diff --git a/src/app/api/staff/index.ts b/src/app/api/staff/index.ts index 31439f8..1a4cfd3 100644 --- a/src/app/api/staff/index.ts +++ b/src/app/api/staff/index.ts @@ -80,8 +80,8 @@ export interface searchInput { export interface SalaryEffectiveInfo { id: number; - date: string; - salaryPoint: number; + date: string | Date; + salaryPoint: number | string; } export const preloadTeamLeads = () => { diff --git a/src/components/EditStaff/EditStaff.tsx b/src/components/EditStaff/EditStaff.tsx index 3e9525d..c4ea80c 100644 --- a/src/components/EditStaff/EditStaff.tsx +++ b/src/components/EditStaff/EditStaff.tsx @@ -28,6 +28,7 @@ import { IndividualStaff, SalaryEffectiveInfo } from "@/app/api/staff"; import dayjs from "dayjs"; import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; import { List, differenceBy } from "lodash"; +// import { useGridApiContext } from '@mui/x-data-grid'; export interface comboItem { company: comboProp[]; @@ -47,6 +48,8 @@ interface formProps { const EditStaff: React.FC = ({ Staff, combos, SalaryEffectiveInfo }) => { + console.log(combos.salary) + console.log(SalaryEffectiveInfo) const defaultSkillset = Staff.skillset.map((s: any) => s.skill.id) const { t } = useTranslation(); const searchParams = useSearchParams() @@ -74,7 +77,12 @@ const EditStaff: React.FC = ({ Staff, combos, SalaryEffectiveInfo }) departDate: dayjs(Staff.departDate).toString() || "", departReason: Staff.departReason, remark: Staff.remark, - salaryEffectiveInfo: SalaryEffectiveInfo + salaryEffectiveInfo: SalaryEffectiveInfo.map(item => { + return ({ + id: Math.random(), + salaryPoint: combos.salary.filter(sal => sal.id === item.salaryPoint)[0].label, + date: dayjs(item.date).toDate(), + })}) }}); const [serverError, setServerError] = useState(""); const router = useRouter(); @@ -147,6 +155,11 @@ const EditStaff: React.FC = ({ Staff, combos, SalaryEffectiveInfo }) const postData = { id: id, ...data, + salaryEffectiveInfo: SalaryEffectiveInfo.map(item => ({ + id: item.id, + salaryPoint: item.salaryPoint, + date: dayjs(item.date).format('YYYY-MM-DD') + })) } console.log(postData) await saveStaff(postData) @@ -168,37 +181,60 @@ const EditStaff: React.FC = ({ Staff, combos, SalaryEffectiveInfo }) router.back(); }; - const resetStaff = useCallback(() => { - console.log(dayjs(Staff.joinDate).format(INPUT_DATE_FORMAT)) - console.log(formProps.getValues("joinDate")) - formProps.reset({ - staffId: Staff.staffId, - name: Staff.name, - companyId: Staff.company.id, - teamId: Staff.team?.id, - departmentId: Staff.department?.id, - gradeId: Staff.grade?.id, - skillSetId: defaultSkillset, - currentPositionId: Staff.currentPosition?.id, - salaryId: Staff.salary.salaryPoint, - employType: Staff.employType, - email: Staff.email, - phone1: Staff.phone1, - phone2: Staff.phone2, - emergContactName: Staff.emergContactName, - emergContactPhone: Staff.emergContactPhone, - joinDate: Staff.joinDate ? dayjs(Staff.joinDate).format(INPUT_DATE_FORMAT) : "", - joinPositionId: Staff.joinPosition?.id, - departDate: !Staff.departDate ? "" : dayjs(Staff.departDate).format(INPUT_DATE_FORMAT), - departReason: Staff.departReason, - remark: Staff.remark, - salaryEffectiveInfo: SalaryEffectiveInfo - }); - }, [Staff,formProps]); + // const resetStaff = useCallback(() => { + // window.location.reload() + // console.log(dayjs(Staff.joinDate).format(INPUT_DATE_FORMAT)) + // console.log(formProps.getValues("joinDate")) + // formProps.setValue('salaryEffectiveInfo', SalaryEffectiveInfo.map(item => { + // return ({ + // id: item.id, + // salaryPoint: combos.salary.filter(sal => sal.id === item.salaryPoint)[0].label, + // date: dayjs(item.date).toDate(), + // })})) + + // formProps.reset({ + // staffId: Staff.staffId, + // name: Staff.name, + // companyId: Staff.company.id, + // teamId: Staff.team?.id, + // departmentId: Staff.department?.id, + // gradeId: Staff.grade?.id, + // skillSetId: defaultSkillset, + // currentPositionId: Staff.currentPosition?.id, + // salaryId: Staff.salary.salaryPoint, + // employType: Staff.employType, + // email: Staff.email, + // phone1: Staff.phone1, + // phone2: Staff.phone2, + // emergContactName: Staff.emergContactName, + // emergContactPhone: Staff.emergContactPhone, + // joinDate: Staff.joinDate ? dayjs(Staff.joinDate).format(INPUT_DATE_FORMAT) : "", + // joinPositionId: Staff.joinPosition?.id, + // departDate: !Staff.departDate ? "" : dayjs(Staff.departDate).format(INPUT_DATE_FORMAT), + // departReason: Staff.departReason, + // remark: Staff.remark, + // salaryEffectiveInfo: SalaryEffectiveInfo.map(item => { + // return ({ + // id: item.id, + // salaryPoint: combos.salary.filter(sal => sal.id === item.salaryPoint)[0].label, + // date: dayjs(item.date).toDate(), + // })}) + // }); + // }, []); + + // useEffect(() => { + // formProps.setValue('salaryEffectiveInfo', SalaryEffectiveInfo.map(item => { + // return ({ + // id: item.id, + // salaryPoint: combos.salary.filter(sal => sal.id === item.salaryPoint)[0].label, + // date: dayjs(item.date).toDate(), + // })}) + // ) + // }, []); - useEffect(() => { - resetStaff() - }, [Staff, formProps, combos]); + // useEffect(() => { + // resetStaff() + // }, [Staff, formProps, combos]); return ( <> @@ -218,7 +254,7 @@ const EditStaff: React.FC = ({ Staff, combos, SalaryEffectiveInfo }) diff --git a/src/components/EditStaff/EditStaffWrapper.tsx b/src/components/EditStaff/EditStaffWrapper.tsx index 50d72cc..52951ca 100644 --- a/src/components/EditStaff/EditStaffWrapper.tsx +++ b/src/components/EditStaff/EditStaffWrapper.tsx @@ -42,6 +42,8 @@ const EditStaffWrapper: React.FC & SubComponents = async ({ fetchSkillCombo(), fetchSalaryCombo(), ]); + + console.log(SalaryCombo.records) const combos: comboItem = { company: CompanyCombo.records, team: TeamCombo.records, @@ -54,7 +56,7 @@ const EditStaffWrapper: React.FC & SubComponents = async ({ console.log(Staff.data) - return ; + return ; }; EditStaffWrapper.Loading = EditStaffLoading; diff --git a/src/components/EditStaff/SalaryEffectiveModel.tsx b/src/components/EditStaff/SalaryEffectiveModel.tsx index 7aae90b..3d2f721 100644 --- a/src/components/EditStaff/SalaryEffectiveModel.tsx +++ b/src/components/EditStaff/SalaryEffectiveModel.tsx @@ -1,17 +1,25 @@ - -import React, { useEffect } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Modal, Box, Typography, Button, TextField, FormControl, InputLabel, Select, MenuItem, Paper, SxProps } from '@mui/material'; -import { useForm, Controller } from 'react-hook-form'; +import { useForm, Controller, useFormContext } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { INPUT_DATE_FORMAT, OUTPUT_DATE_FORMAT } from '@/app/utils/formatUtil'; import dayjs from 'dayjs'; import { DatePicker } from '@mui/x-date-pickers'; +import { DataGrid, GridEventListener, GridRowEditStopParams, GridRowEditStopReasons, GridRowModel, GridRowModes, GridRowModesModel, GridToolbarContainer } from '@mui/x-data-grid'; +import StyledDataGrid from '../StyledDataGrid'; +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 { GridActionsCellItem } from '@mui/x-data-grid'; interface SalaryEffectiveModelProps { open: boolean; onClose: () => void; modalSx?: SxProps; onSave: () => void; + columns: any[] } const modalSx: SxProps = { @@ -20,17 +28,57 @@ const modalSx: SxProps = { left: "50%", transform: "translate(-50%, -50%)", width: "90%", - maxWidth: "sm", - maxHeight: "90%", + maxWidth: "auto", + maxHeight: "auto", padding: 3, display: "flex", flexDirection: "column", gap: 2, }; -const SalaryEffectiveModel: React.FC = ({ open, onClose, modalSx: mSx, onSave }) => { + function EditToolbar(props: React.JSXElementConstructor | null | undefined | any) { + // const intl = useIntl(); + // const addRecordBtn = intl.formatMessage({ id: 'add' }); + const { count, setCount, setRows, setRowModesModel, _columns } = props; + let obj: { [key: string]: string } = {}; + for (let i = 0; i < _columns.length - 1; i++) { + obj[_columns[i].field as string] = ''; + } + + const handleClick = React.useCallback(() => { + const id = Math.random(); + setRows((oldRows: any) => [...oldRows, { id, ...obj, isNew: true }]); + setRowModesModel((oldModel: any) => ({ + ...oldModel, + [id]: { mode: GridRowModes.Edit, + // fieldToFocus: 'material' + } + })); + setCount((prev: number) => prev+1) + }, [count, setCount, setRowModesModel, setRows]) + + return ( + + + {/* */} + + ); + } + +const SalaryEffectiveModel: React.FC = ({ open, onClose, modalSx: mSx, onSave, columns }) => { const { t } = useTranslation(); - const { control, register, formState, trigger, watch, setValue } = useForm({}); + const { control, register, formState, trigger, watch, setValue, getValues } = useFormContext(); + const [rowModesModel, setRowModesModel] = useState({}); + const [count, setCount] = useState(0); + const [_rows, setRows] = useState(() => { + const list = getValues('salaryEffectiveInfo') + console.log(list) + return list && list.length > 0 ? list : [] + }); const formValues = watch(); // This line of code is using the watch function from react-hook-form to get the current values of the form fields. @@ -38,14 +86,133 @@ const SalaryEffectiveModel: React.FC = ({ open, onClo onClose(); }; - const handleSave = async () => { - const isValid = await trigger(); - if (isValid) { - onSave(); - onClose(); + // const handleSave = async () => { + // const isValid = await trigger(); + // // if (isValid) { + // // onSave(); + // // onClose(); + // // } + // }; + + const handleRowEditStop: GridEventListener<"rowEditStop"> = ( + params, + event, + ) => { + if (params.reason === GridRowEditStopReasons.rowFocusOut) { + event.defaultMuiPrevented = true; } }; + const processRowUpdate = useCallback((newRow: GridRowModel) => { + console.log(newRow) + const updatedRow = { ...newRow, updated: true }; + console.log(_rows) + if (_rows.length != 0) { + setRows(_rows?.map((row: any) => (row.id === newRow.id ? updatedRow : row))); + } + return updatedRow; + }, [_rows, setValue, setRows]) + + useEffect(()=> { + setValue('salaryEffectiveInfo', _rows) + }, [_rows]) + + const handleSaveClick = useCallback( + (id: any) => () => { + setRowModesModel((prevRowModesModel) => ({ + ...prevRowModesModel, + [id]: { mode: GridRowModes.View } + })); + }, + [setRowModesModel] + ); + + const handleCancelClick = useCallback( + (id: any) => () => { + setRowModesModel((prevRowModesModel) => ({ + ...prevRowModesModel, + [id]: { mode: GridRowModes.View, ignoreModifications: true } + })); + }, + [setRowModesModel] + ); + + const handleEditClick = useCallback( + (id: any) => () => { + setRowModesModel((prevRowModesModel) => ({ + ...prevRowModesModel, + [id]: { mode: GridRowModes.Edit } + })); + + }, + [setRowModesModel] + ); + + const handleDeleteClick = useCallback( + (id: any) => () => { + setRows((prevRows: any) => prevRows.filter((row: any) => row.id !== id)); + setCount((prev: number) => prev - 1) + }, + [setRows, setCount] + ); + + const defaultCol = useMemo( + () => ( + { + 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={handleSaveClick(id)} + />, + } + label="Cancel" + key="edit" + onClick={handleCancelClick(id)} + /> + ]; + } + return [ + } + label="Edit" + className="textPrimary" + onClick={handleEditClick(id)} + color="inherit" + key="edit" + />, + } + label="Delete" + sx={{ + color: 'error.main' + }} + onClick={handleDeleteClick(id)} color="inherit" key="edit" /> + ]; + } + } + ), [rowModesModel, handleSaveClick, handleCancelClick, handleEditClick, handleDeleteClick] + ) + + + let _columns: any[] = [] + if (columns) { + _columns = [...columns, defaultCol] + } + useEffect(() => { console.log(formValues) }, [open]) @@ -56,30 +223,33 @@ const SalaryEffectiveModel: React.FC = ({ open, onClo {t('Salary Effective Date Change')} - - + - - + {/* */} ); }; -export default SalaryEffectiveModel; +export default SalaryEffectiveModel; \ No newline at end of file diff --git a/src/components/EditStaff/StaffInfo.tsx b/src/components/EditStaff/StaffInfo.tsx index a3fb282..60ceb65 100644 --- a/src/components/EditStaff/StaffInfo.tsx +++ b/src/components/EditStaff/StaffInfo.tsx @@ -9,7 +9,7 @@ import Typography from "@mui/material/Typography"; import { CreateGroupInputs } from "@/app/api/group/actions"; import { Controller, useFormContext } from "react-hook-form"; import { useTranslation } from "react-i18next"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { CreateStaffInputs } from "@/app/api/staff/actions"; import { Button, @@ -95,6 +95,28 @@ const StaffInfo: React.FC = ({ combos }) => { if (departDate) clearErrors("departDate"); }, [joinDate, departDate]); + const salaryCols = useMemo( + () => [ + { + field: 'salaryPoint', + headerName: 'salaryPoint', + flex: 1, + editable: true, + type: 'singleSelect', + valueOptions: combos?.salary.map(item => item.label), + // valueOptions: [], + // width: 150 + }, + { + field: 'date', + headerName: 'date', + flex: 1, + editable: true, + type: 'date', + // width: 150 + }, + ], [combos]) + return ( @@ -305,6 +327,7 @@ const StaffInfo: React.FC = ({ combos }) => { {...field} error={Boolean(errors.salaryId)} style={{ flex: 1, marginRight: '8px' }} + disabled > {combos.salary.map((salary, index) => ( = ({ combos }) => { open={salaryEffectiveModelOpen} onClose={closeSalaryEffectiveModel} onSave={onSalaryEffectiveSave} + columns={salaryCols} /> );