|
- "use client";
- import {
- FooterPropsOverrides,
- GridActionsCellItem,
- GridCellParams,
- GridRowId,
- GridRowIdGetter,
- GridRowModel,
- GridRowModes,
- GridRowModesModel,
- GridToolbarContainer,
- useGridApiRef,
- } from "@mui/x-data-grid";
- import {
- Dispatch,
- MutableRefObject,
- SetStateAction,
- useCallback,
- useEffect,
- useMemo,
- useState,
- } from "react";
- import StyledDataGrid from "../StyledDataGrid";
- import { GridColDef } from "@mui/x-data-grid";
- import { Box, Button, Grid, Icon, Typography } from "@mui/material";
- import { useTranslation } from "react-i18next";
- import { Add } from "@mui/icons-material";
- import SaveIcon from "@mui/icons-material/Save";
- import DeleteIcon from "@mui/icons-material/Delete";
- import CancelIcon from "@mui/icons-material/Cancel";
- import FactCheckIcon from "@mui/icons-material/FactCheck";
- import ShoppingCartIcon from "@mui/icons-material/ShoppingCart";
- // import PoQcModal from "./PoQcModal";
- import PlayArrowIcon from "@mui/icons-material/PlayArrow";
- import { useSearchParams } from "next/navigation";
- import { decimalFormatter } from "@/app/utils/formatUtil";
- import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
- import HighlightOffIcon from '@mui/icons-material/HighlightOff';
- import { ProdScheduleLineBomMaterialResult, ScheduleType } from "@/app/api/scheduling";
-
- interface ResultWithId {
- id: number;
- }
-
- interface Props {
- bomMaterial: ProdScheduleLineBomMaterialResult[];
- type: ScheduleType
- }
-
- export type BomMaterialEntryError = {
- [field in keyof any]?: string;
- };
-
- export type BomMaterialRow = Partial<
- any & {
- isActive: boolean | undefined;
- _isNew: boolean;
- _error: BomMaterialEntryError;
- } & ResultWithId
- >;
-
- class ProcessRowUpdateError extends Error {
- public readonly row: BomMaterialRow;
- public readonly errors: BomMaterialEntryError | undefined;
- constructor(row: BomMaterialRow, message?: string, errors?: BomMaterialEntryError) {
- super(message);
- this.row = row;
- this.errors = errors;
-
- Object.setPrototypeOf(this, ProcessRowUpdateError.prototype);
- }
- }
-
- function BomMaterialTable({ bomMaterial }: Props) {
- const { t } = useTranslation("schedule");
- const apiRef = useGridApiRef();
- const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
- const getRowId = useCallback<GridRowIdGetter<BomMaterialRow>>(
- (row) => row.id as number,
- []
- );
- const [entries, setEntries] = useState<BomMaterialRow[]>(bomMaterial || []);
-
- const columns = useMemo<GridColDef[]>(
- () => [
- {
- field: "code",
- headerName: t("Code"),
- flex: 1,
- },
- {
- field: "name",
- headerName: t("Name"),
- flex: 1,
- },
- {
- field: "type",
- headerName: t("type"),
- flex: 1,
- renderCell: (row) => {
- return t(row.value)
- }
- },
- {
- field: "availableQty",
- headerName: t("Available Qty"),
- flex: 0.5,
- type: "number",
- editable: true,
- align: "right",
- headerAlign: "right",
- renderCell: (row) => {
- return decimalFormatter.format(row.value)
- }
- // replace with tooltip + content
- },
- {
- field: "demandQty",
- headerName: t("Demand Qty"),
- flex: 0.5,
- editable: true,
- align: "right",
- headerAlign: "right",
- renderCell: (row) => {
- return decimalFormatter.format(row.value)
- }
- },
- {
- field: "status",
- headerName: t("status"),
- flex: 0.5,
- editable: true,
- align: "center",
- headerAlign: "center",
- renderCell: (params) => {
- return params.row.availableQty - params.row.demandQty >= 0 ?
- <CheckCircleOutlineIcon
- color="success"
- fontSize="small"
- /> :
- <HighlightOffIcon
- color="error"
- fontSize="small"
- />
- }
- },
- ],
- []
- );
- const validation = useCallback(
- (
- newRow: GridRowModel<BomMaterialRow>
- ): BomMaterialEntryError | undefined => {
- const error: BomMaterialEntryError = {};
- console.log(newRow);
- return Object.keys(error).length > 0 ? error : undefined;
- },
- []
- );
- const processRowUpdate = useCallback(
- (newRow: GridRowModel<BomMaterialRow>, originalRow: GridRowModel<BomMaterialRow>) => {
- const errors = validation(newRow); // change to validation
- if (errors) {
- throw new ProcessRowUpdateError(
- originalRow,
- "validation error",
- errors
- );
- }
- const { _isNew, _error, ...updatedRow } = newRow;
- const rowToSave = {
- ...updatedRow,
- } satisfies BomMaterialRow;
- const newEntries = entries.map((e) =>
- getRowId(e) === getRowId(originalRow) ? rowToSave : e
- );
- setEntries(newEntries);
- //update remaining qty
- const total = newEntries.reduce((acc, curr) => acc + (curr.acceptedQty || 0), 0);
- return rowToSave;
- },
- [getRowId, entries]
- );
-
- const onProcessRowUpdateError = useCallback(
- (updateError: ProcessRowUpdateError) => {
- const errors = updateError.errors;
- const oldRow = updateError.row;
-
- apiRef.current.updateRows([{ ...oldRow, _error: errors }]);
- },
- [apiRef]
- );
-
- return (
- <>
- <StyledDataGrid
- getRowId={getRowId}
- apiRef={apiRef}
- autoHeight
- sx={{
- "--DataGrid-overlayHeight": "100px",
- ".MuiDataGrid-row .MuiDataGrid-cell.hasError": {
- border: "1px solid",
- borderColor: "error.main",
- },
- ".MuiDataGrid-row .MuiDataGrid-cell.hasWarning": {
- border: "1px solid",
- borderColor: "warning.main",
- },
- }}
- disableColumnMenu
- editMode="row"
- rows={entries}
- rowModesModel={rowModesModel}
- onRowModesModelChange={setRowModesModel}
- processRowUpdate={processRowUpdate}
- onProcessRowUpdateError={onProcessRowUpdateError}
- columns={columns}
- getCellClassName={(params: GridCellParams<BomMaterialRow>) => {
- let classname = "";
- if (params.row._error) {
- classname = "hasError";
- }
- return classname;
- }}
- // slots={{
- // footer: FooterToolbar,
- // noRowsOverlay: NoRowsOverlay,
- // }}
- // slotProps={{
- // footer: { child: footer },
- // }}
- />
- </>
- );
- }
- const NoRowsOverlay: React.FC = () => {
- const { t } = useTranslation("home");
- return (
- <Box
- display="flex"
- justifyContent="center"
- alignItems="center"
- height="100%"
- >
- <Typography variant="caption">{t("Add some entries!")}</Typography>
- </Box>
- );
- };
-
- const FooterToolbar: React.FC<FooterPropsOverrides> = ({ child }) => {
- return <GridToolbarContainer sx={{ p: 2 }}>{child}</GridToolbarContainer>;
- };
- export default BomMaterialTable;
|