import { Box, Button, Modal, ModalProps, Paper, SxProps, Tooltip, Typography } from "@mui/material" import StyledDataGrid from "../StyledDataGrid" import { useTranslation } from "react-i18next"; import { useFormContext } from "react-hook-form"; import { useCallback, useEffect, useMemo, useState } from "react"; import { GridRenderEditCellParams, FooterPropsOverrides, GridActionsCellItem, GridCellParams, GridEventListener, GridRowEditStopReasons, GridRowId, GridRowIdGetter, GridRowModel, GridRowModes, GridRowModesModel, GridToolbarContainer, useGridApiRef, GridEditDateCell, GridEditSingleSelectCell } from "@mui/x-data-grid"; import AddIcon from '@mui/icons-material/Add'; import SaveIcon from '@mui/icons-material/Save'; import DeleteIcon from '@mui/icons-material/Delete'; import CancelIcon from '@mui/icons-material/Cancel'; import EditIcon from '@mui/icons-material/Edit'; import waitForCondition from "../utils/waitFor"; import { gradeHistory } from "@/app/api/staff/actions"; import { Add } from "@mui/icons-material"; import { comboItem } from "../CreateStaff/CreateStaff"; import { StaffEntryError, validateRowAndRowBefore } from "./validateDates"; import { ProcessRowUpdateError } from "./TeamHistoryModal"; interface Props { open: boolean; onClose: () => void; combos: comboItem; // columns: any[] } const modalSx: SxProps = { position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", width: "90%", maxWidth: "auto", maxHeight: "auto", padding: 3, display: "flex", flexDirection: "column", gap: 2, }; export type GradeModalRow = Partial< gradeHistory & { _isNew: boolean _error: StaffEntryError; }> const thisField = "gradeHistory" const GradeHistoryModal: React.FC = ({ open, onClose, combos }) => { const { t, // i18n: { language }, } = useTranslation(); const { setValue, getValues } = useFormContext(); const [rowModesModel, setRowModesModel] = useState({}); const apiRef = useGridApiRef() const originalRows = getValues(thisField) const [_rows, setRows] = useState(() => { const list: GradeModalRow[] = getValues(thisField) return list && list.length > 0 ? list : [] }); const [_delRows, setDelRows] = useState([]); const getRowId = useCallback>( (row) => row.id!!, [], ); const handleSave = useCallback( (id: GridRowId) => () => { setRowModesModel((prevRowModesModel) => ({ ...prevRowModesModel, [id]: { mode: GridRowModes.View } })); }, [setRowModesModel] ); const onCancel = useCallback(() => { setRows(originalRows) onClose(); }, [onClose, originalRows]); const handleClose = useCallback>( (_, reason) => { if (reason !== "backdropClick") { onClose(); } }, [onClose]); const isSaved = useCallback(() => { const saved = Object.keys(rowModesModel).every(key => { rowModesModel[key].mode === GridRowModes.Edit }) return saved }, [rowModesModel]) const doSave = useCallback(async () => { try { if (isSaved()) { setValue(thisField, _rows) onClose() } } catch (error) { console.error(error); } }, [isSaved, onClose, _rows]) const addRow = useCallback(() => { const id = Date.now() const newEntry = { id, _isNew: true } satisfies GradeModalRow; setRows((prev) => [...prev, newEntry]) setRowModesModel((model) => ({ ...model, [getRowId(newEntry)]: { mode: GridRowModes.Edit, fieldToFocus: "grade", } })) }, []); const onProcessRowUpdateError = useCallback( (updateError: ProcessRowUpdateError) => { const errors = updateError.errors; // const prevRow = updateError.prevRow; const currRow = updateError.currRow; // if (updateError.prevRow) { // apiRef.current.updateRows([{ ...prevRow, _error: errors }]); // } apiRef.current.updateRows([{ ...currRow, _error: errors }]); }, [apiRef, rowModesModel], ); const processRowUpdate = useCallback(( newRow: GridRowModel, originalRow: GridRowModel ) => { const rowIndex = _rows.findIndex((row: GradeModalRow) => row.id === newRow.id); const prevRow: GradeModalRow | null = rowIndex > 0 ? _rows[rowIndex - 1] : null; const errors = validateRowAndRowBefore(prevRow, newRow) console.log(errors) if (errors) { throw new ProcessRowUpdateError( prevRow, newRow, "validation error", errors ) } const { _isNew, _error, ...updatedRow } = newRow; const rowToSave = { ...updatedRow, } console.log(_rows) if (_rows.length != 0) { setRows((prev: any[]) => prev?.map((row: any) => (row.id === newRow.id ? rowToSave : row)).sort((a, b) => { if (!a.from || !b.from) return 0; return new Date(a.from).getTime() - new Date(b.from).getTime(); })); } return rowToSave; } , [_rows, validateRowAndRowBefore]) const handleCancel = useCallback( (id: any) => () => { setRowModesModel((prevRowModesModel) => ({ ...prevRowModesModel, [id]: { mode: GridRowModes.View, ignoreModifications: true } })); const editedRow = _rows.find((r) => getRowId(r) === id) if (editedRow?._isNew) { setRows((rw) => rw.filter((r) => r.id !== id)) } else { setRows((rw) => rw.map((r) => getRowId(r) === id ? { ...r, _error: undefined } : r, ), ); } }, [setRowModesModel, _rows] ); const handleDelete = useCallback( (id: GridRowId) => () => { setRows((prevRows) => prevRows.filter((row) => row.id !== id)); setDelRows((prevRowsId: number[]) => [...prevRowsId, id as number]) }, [] ); useEffect(()=> { console.log(_rows) // setValue(thisField, _rows) setValue('delGradeHistory', _delRows) }, [_rows, _delRows]) const footer = ( ) const columns = useMemo( () => [ { field: 'grade', headerName: 'grade', flex: 1, editable: true, type: 'singleSelect', valueOptions: combos.grade.map(item => item.label), renderEditCell(params: GridRenderEditCellParams) { const errorMessage = params.row._error?.[params.field as keyof StaffEntryError] const content = ( ); return errorMessage ? ( {content} ) : ( content ); } }, { field: 'from', headerName: 'from', flex: 1, editable: true, type: 'date', renderEditCell(params: GridRenderEditCellParams) { const errorMessage = params.row._error?.[params.field as keyof StaffEntryError] const content = ; return errorMessage ? ( {content} ) : ( content ); } }, { field: 'actions', type: 'actions', headerName: 'edit', width: 100, cellClassName: 'actions', getActions: ({ id }: { id: number }) => { const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit; if (isInEditMode) { return [ } label="Save" key="edit" sx={{ color: 'primary.main' }} onClick={handleSave(id)} />, } label="Cancel" key="edit" onClick={handleCancel(id)} /> ]; } return [ } label="Delete" sx={{ color: 'error.main' }} onClick={handleDelete(id)} color="inherit" key="edit" /> ]; } } ], [combos, rowModesModel, handleSave, handleCancel, handleDelete]) return ( {t('GradeHistoryModal')} ) => { let classname = ""; if (params.row._error) { classname = "hasError" } return classname; }} slots={{ footer: FooterToolbar, noRowsOverlay: NoRowsOverlay, }} slotProps={{ footer: { child: footer }, }} /> {/* */} ) } const FooterToolbar: React.FC = ({ child }) => { return {child}; }; const NoRowsOverlay: React.FC = () => { const { t } = useTranslation("home"); return ( {t("Add some entries!")} ); }; export default GradeHistoryModal