|
- "use client";
-
- import React, {
- CSSProperties,
- DetailedHTMLProps,
- HTMLAttributes,
- useEffect,
- useState,
- } from "react";
- import Paper from "@mui/material/Paper";
- import Table from "@mui/material/Table";
- import TableBody from "@mui/material/TableBody";
- import TableCell from "@mui/material/TableCell";
- import TableContainer from "@mui/material/TableContainer";
- import TableHead from "@mui/material/TableHead";
- import TablePagination from "@mui/material/TablePagination";
- import TableRow from "@mui/material/TableRow";
- import IconButton from "@mui/material/IconButton";
- import EditIcon from "@mui/icons-material/Edit";
- import SaveIcon from "@mui/icons-material/Save";
- import CancelIcon from "@mui/icons-material/Close";
- import DeleteIcon from "@mui/icons-material/Delete";
- import TextField from "@mui/material/TextField";
- import MultiSelect from "@/components/SearchBox/MultiSelect";
- import { Collapse, Typography } from "@mui/material";
- import BomMaterialTable from "./BomMaterialTable";
- import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
- import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
- import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";
- import PlayCircleOutlineIcon from "@mui/icons-material/PlayCircleOutline";
- import { useTranslation } from "react-i18next";
- import {
- DetailedProdScheduleLineResult,
- RoughProdScheduleLineBomMaterialResult,
- RoughProdScheduleLineResultByFg,
- RoughProdScheduleResult,
- ScheduleType,
- } from "@/app/api/scheduling";
- import { defaultPagingController } from "../SearchResults/SearchResults";
-
- export interface ResultWithId {
- id: string | number;
- // id: number;
- }
-
- interface BaseColumn<T extends ResultWithId> {
- field: keyof T;
- label: string;
- type: string;
- options?: T[];
- renderCell?: (params: T) => React.ReactNode;
- style?: Partial<HTMLElement["style"]> & {
- [propName: string]: string;
- } & CSSProperties;
- }
-
- interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> {
- onClick: (item: T) => void;
- buttonIcon: React.ReactNode;
- buttonColor?: "inherit" | "default" | "primary" | "secondary";
- }
-
- export type Column<T extends ResultWithId> =
- | BaseColumn<T>
- | ColumnWithAction<T>;
-
- interface Props<T extends ResultWithId> {
- index?: number;
- items: T[];
- columns: Column<T>[];
- noWrapper?: boolean;
- setPagingController?: (value: {
- pageNum: number;
- pageSize: number;
- totalCount: number;
- index?: number;
- }) => void;
- pagingController?: { pageNum: number; pageSize: number; totalCount: number };
- isAutoPaging: boolean;
- isEdit: boolean;
- isEditable: boolean;
- hasCollapse: boolean;
- type: ScheduleType;
- }
-
- function ScheduleTable<T extends ResultWithId>({
- type,
- index = 7,
- items,
- columns,
- noWrapper,
- pagingController = undefined,
- setPagingController = undefined,
- isAutoPaging = true,
- isEdit = false,
- isEditable = true,
- hasCollapse = false,
- }: Props<T>) {
- const [page, setPage] = useState(0);
- const [rowsPerPage, setRowsPerPage] = useState(10);
- const [editingRowId, setEditingRowId] = useState<number | null>(null);
- const [editedItems, setEditedItems] = useState<T[]>(items);
- const { t } = useTranslation("schedule");
- useEffect(() => {
- setEditedItems(items);
- }, [items]);
- const handleChangePage = (_event: unknown, newPage: number) => {
- setPage(newPage);
- if (setPagingController && pagingController) {
- setPagingController({
- ...pagingController,
- pageNum: newPage + 1,
- index: index ?? -1,
- });
- }
- };
-
- const handleChangeRowsPerPage = (
- event: React.ChangeEvent<HTMLInputElement>,
- ) => {
- setRowsPerPage(+event.target.value);
- setPage(0);
- if (setPagingController && pagingController) {
- setPagingController({
- ...pagingController,
- pageSize: +event.target.value,
- pageNum: 1,
- index: index,
- });
- }
- };
-
- const handleEditClick = (id: number) => {
- setEditingRowId(id);
- };
-
- const handleSaveClick = (item: T) => {
- setEditingRowId(null);
- // Call API or any save logic here
- setEditedItems((prev) =>
- prev.map((row) => (row.id === item.id ? { ...row } : row)),
- );
- };
-
- const handleInputChange = (
- id: number,
- field: keyof T,
- value: string | number[],
- ) => {
- setEditedItems((prev) =>
- prev.map((item) => (item.id === id ? { ...item, [field]: value } : item)),
- );
- };
-
- const handleDeleteClick = (id: number) => {
- // Implement delete logic here
- setEditedItems((prev) => prev.filter((item) => item.id !== id));
- };
-
- useEffect(() => {
- console.log("[debug] isEdit in table", isEdit);
- //TODO: switch all record to not in edit mode and save the changes
- if (!isEdit) {
- editedItems?.forEach((item) => {
- // Call save logic here
- // console.log("Saving item:", item);
- // Reset editing state if needed
- });
-
- setEditingRowId(null);
- }
- }, [isEdit]);
-
- function isRoughType(type: ScheduleType): type is "rough" {
- return type === "rough";
- }
-
- function isDetailedType(type: ScheduleType): type is "detailed" {
- return type === "detailed";
- }
-
- function Row(props: { row: T }) {
- const { row } = props;
- const [open, setOpen] = useState(false);
- // console.log(row)
- return (
- <>
- <TableRow hover tabIndex={-1} key={row.id}>
- {isDetailedType(type) && (
- <TableCell>
- <IconButton disabled={!isEdit}>
- <PlayCircleOutlineIcon />
- </IconButton>
- </TableCell>
- )}
- {(isEditable || hasCollapse) && (
- <TableCell>
- {editingRowId === row.id ? (
- <>
- {isDetailedType(type) && isEditable && (
- <IconButton
- disabled={!isEdit}
- onClick={() => handleSaveClick(row)}
- >
- <SaveIcon />
- </IconButton>
- )}
- {isDetailedType(type) && isEditable && (
- <IconButton
- disabled={!isEdit}
- onClick={() => setEditingRowId(null)}
- >
- <CancelIcon />
- </IconButton>
- )}
- {hasCollapse && (
- <IconButton
- aria-label="expand row"
- size="small"
- onClick={() => setOpen(!open)}
- >
- {open ? (
- <KeyboardArrowUpIcon />
- ) : (
- <KeyboardArrowDownIcon />
- )}
- <Typography>{t("View BoM")}</Typography>
- </IconButton>
- )}
- </>
- ) : (
- <>
- {isDetailedType(type) && isEditable && (
- <IconButton
- disabled={!isEdit}
- onClick={() => handleEditClick(row.id as number)}
- >
- <EditIcon />
- </IconButton>
- )}
- {isDetailedType(type) && isEditable && (
- <IconButton
- disabled={!isEdit}
- onClick={() => handleDeleteClick(row.id as number)}
- >
- <DeleteIcon />
- </IconButton>
- )}
- {hasCollapse && (
- <IconButton
- aria-label="expand row"
- size="small"
- onClick={() => setOpen(!open)}
- >
- {open ? (
- <KeyboardArrowUpIcon />
- ) : (
- <KeyboardArrowDownIcon />
- )}
- <Typography>{t("View BoM")}</Typography>
- </IconButton>
- )}
- </>
- )}
- </TableCell>
- )}
- {columns.map((column, idx) => {
- const columnName = column.field;
- return (
- <TableCell key={`${columnName.toString()}-${idx}`}>
- {editingRowId === row.id ? (
- (() => {
- switch (column.type) {
- case "input":
- return (
- <TextField
- hiddenLabel={true}
- fullWidth
- defaultValue={row[columnName] as string}
- onChange={(e) =>
- handleInputChange(
- row.id as number,
- columnName,
- e.target.value,
- )
- }
- />
- );
- // case 'multi-select':
- // //TODO: May need update if use
- // return (
- // <MultiSelect
- // //label={column.label}
- // options={column.options ?? []}
- // selectedValues={[]}
- // onChange={(selectedValues) => handleInputChange(row.id as number, columnName, selectedValues)}
- // />
- // );
- case "read-only":
- return <span>{row[columnName] as string}</span>;
- default:
- return null; // Handle any default case if needed
- }
- })()
- ) : column.renderCell ? (
- <div style={column.style}>{column.renderCell(row)}</div>
- ) : (
- <div style={column.style}>
- <span
- onDoubleClick={() =>
- isEdit && handleEditClick(row.id as number)
- }
- >
- {row[columnName] as string}
- </span>
- </div>
- )}
- </TableCell>
- );
- })}
- </TableRow>
- <TableRow>
- {hasCollapse && (
- <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
- <Collapse in={open} timeout="auto" unmountOnExit>
- <Table>
- <TableBody>
- <TableRow>
- <TableCell>
- <BomMaterialTable
- type={type}
- bomMaterial={
- isDetailedType(type) ? (row as unknown as RoughProdScheduleLineResultByFg).bomMaterials
- : (row as unknown as DetailedProdScheduleLineResult).bomMaterials
- }
- />
- </TableCell>
- </TableRow>
- </TableBody>
- </Table>
- </Collapse>
- </TableCell>
- )}
- </TableRow>
- </>
- );
- }
-
- const table = (
- <>
- <TableContainer sx={{ maxHeight: 440 }}>
- <Table stickyHeader>
- <TableHead>
- <TableRow>
- {isDetailedType(type) && <TableCell>{t("Release")}</TableCell>}
- {(isEditable || hasCollapse) && (
- <TableCell>{t("Actions")}</TableCell>
- )}{" "}
- {/* Action Column Header */}
- {columns.map((column, idx) => (
- <TableCell
- style={column.style}
- key={`${column.field.toString()}${idx}`}
- >
- {column.label}
- </TableCell>
- ))}
- </TableRow>
- </TableHead>
- <TableBody>
- {/* {(isAutoPaging ? editedItems.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) : editedItems).map((item) => ( */}
- {editedItems
- ?.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
- ?.map((item) => <Row key={item.id} row={item} />)}
- </TableBody>
- </Table>
- </TableContainer>
- <TablePagination
- rowsPerPageOptions={[10, 25, 100]}
- component="div"
- // count={pagingController.totalCount === 0 ? editedItems.length : pagingController.totalCount}
- count={editedItems?.length ?? 0}
- rowsPerPage={rowsPerPage}
- page={page}
- onPageChange={handleChangePage}
- onRowsPerPageChange={handleChangeRowsPerPage}
- />
- </>
- );
-
- return noWrapper ? table : <Paper sx={{ overflow: "hidden" }}>{table}</Paper>;
- }
-
- export default ScheduleTable;
|