|
- "use client";
-
- import Stack from "@mui/material/Stack";
- import Card from "@mui/material/Card";
- import CardContent from "@mui/material/CardContent";
- import Typography from "@mui/material/Typography";
- import { useTranslation } from "react-i18next";
- import CardActions from "@mui/material/CardActions";
- import RestartAlt from "@mui/icons-material/RestartAlt";
- import Button from "@mui/material/Button";
- import AddIcon from '@mui/icons-material/Add';
- import EditIcon from '@mui/icons-material/Edit';
- import DeleteIcon from '@mui/icons-material/DeleteOutlined';
- import SaveIcon from '@mui/icons-material/Save';
- import CancelIcon from '@mui/icons-material/Close';
- import {
- GridRowsProp,
- GridRowModesModel,
- GridRowModes,
- GridColDef,
- GridToolbarContainer,
- GridActionsCellItem,
- GridEventListener,
- GridRowId,
- GridRowModel,
- GridRowEditStopReasons,
- } from '@mui/x-data-grid';
- import CustomDatagrid from "../CustomDatagrid/CustomDatagrid";
- import { useFieldArray, useFormContext } from "react-hook-form";
- import { useCallback, useEffect, useMemo, useState } from "react";
-
- interface Props {
- }
-
- interface EditToolbarProps {
- setRows: (newRows: (oldRows: GridRowsProp) => GridRowsProp) => void;
- setRowModesModel: (
- newModel: (oldModel: GridRowModesModel) => GridRowModesModel,
- ) => void;
- }
-
- var rowId = -1
- function EditToolbar(props: EditToolbarProps) {
- const { setRows, setRowModesModel } = props;
- const { t } = useTranslation();
-
- const handleClick = () => {
- const id = rowId;
- rowId = rowId - 1;
- setRows((oldRows) => [{ id, name: '', phone: '', email: '', isNew: true }, ...oldRows]);
- setRowModesModel((oldModel) => ({
- ...oldModel,
- [id]: { mode: GridRowModes.Edit, fieldToFocus: 'name' },
- }));
- };
-
- return (
- <GridToolbarContainer>
- <Button color="primary" startIcon={<AddIcon />} onClick={handleClick}>
- {t("Add Contact Person")}
- </Button>
- </GridToolbarContainer>
- );
- }
-
- const ContactInfo: React.FC<Props> = ({
- }) => {
- const { t } = useTranslation();
-
- const { control, setValue, getValues, formState: { errors, defaultValues }, setError, clearErrors, reset, watch, resetField } = useFormContext();
- const { fields } = useFieldArray({
- control,
- name: "addContacts"
- })
-
- const initialRows: GridRowsProp = fields.map((item, index) => {
- return ({
- id: Number(getValues(`addContacts[${index}].id`)),
- name: getValues(`addContacts[${index}].name`),
- phone: getValues(`addContacts[${index}].phone`),
- email: getValues(`addContacts[${index}].email`),
- isNew: false,
- })
- })
-
- const [rows, setRows] = useState<GridRowsProp>([]);
- const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
-
- useEffect(() => {
- if (initialRows.length > 0 && rows.length === 0) {
- setRows(initialRows)
- }
- }, [initialRows.length > 0])
-
- const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => {
- if (params.reason === GridRowEditStopReasons.rowFocusOut) {
- event.defaultMuiPrevented = true;
- }
- };
-
- const handleEditClick = (id: GridRowId) => () => {
- setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.Edit } });
- };
-
- const handleSaveClick = (id: GridRowId) => () => {
- setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View } });
- };
-
- const handleDeleteClick = (id: GridRowId) => () => {
- const updatedRows = rows.filter((row) => row.id !== id)
- setRows(updatedRows);
- setValue("addContacts", updatedRows)
- };
-
- const handleCancelClick = (id: GridRowId) => () => {
- setRowModesModel({
- ...rowModesModel,
- [id]: { mode: GridRowModes.View, ignoreModifications: true },
- });
-
- const editedRow = rows.find((row) => row.id === id);
- if (editedRow!.isNew) {
- setRows(rows.filter((row) => row.id !== id));
- }
- };
-
- const processRowUpdate = useCallback((newRow: GridRowModel) => {
- const updatedRow = { ...newRow };
-
- const updatedRows = rows.map((row) => (row.id === newRow.id ? updatedRow : row))
- setRows(updatedRows);
- setValue("addContacts", updatedRows)
- return updatedRow;
- }, [rows]);
-
- const handleRowModesModelChange = useCallback((newRowModesModel: GridRowModesModel) => {
- setRowModesModel(newRowModesModel);
- }, [rows]);
-
- const resetContact = useCallback(() => {
- if (defaultValues !== undefined) {
- resetField("addContacts")
- // reset({addContacts: defaultValues.addContacts})
- setRows((prev) => defaultValues.addContacts)
- setRowModesModel(rows.reduce((acc, row) => ({...acc, [row.id]: { mode: GridRowModes.View } }), {}))
- }
- }, [defaultValues])
-
- const columns = useMemo<GridColDef[]>(
- () => [
- {
- field: 'name',
- headerName: t('Contact Name'),
- editable: true,
- flex: 1,
- },
- {
- field: 'phone',
- headerName: t('Contact Phone'),
- editable: true,
- flex: 1,
- },
- {
- field: 'email',
- headerName: t('Contact Email'),
- editable: true,
- flex: 1,
- },
- {
- field: 'actions',
- type: 'actions',
- headerName: '',
- flex: 0.6,
- // width: 100,
- cellClassName: 'actions',
- getActions: ({ id, ...params }) => {
- const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
-
- if (isInEditMode) {
- return [
- <GridActionsCellItem
- icon={<SaveIcon />}
- label="Save"
- sx={{
- color: 'primary.main',
- }}
- onClick={handleSaveClick(id)}
- />,
- <GridActionsCellItem
- icon={<CancelIcon />}
- label="Cancel"
- className="textPrimary"
- onClick={handleCancelClick(id)}
- color="inherit"
- />,
- ];
- }
-
- return [
- <GridActionsCellItem
- icon={<EditIcon />}
- label="Edit"
- className="textPrimary"
- onClick={handleEditClick(id)}
- color="inherit"
- />,
- <GridActionsCellItem
- icon={<DeleteIcon />}
- label="Delete"
- onClick={handleDeleteClick(id)}
- color="inherit"
- />,
- ];
- },
- },
- ],
- [rows, rowModesModel, t],
- );
-
- // check error
- useEffect(() => {
- if (getValues("addContacts") === undefined || getValues("addContacts") === null) {
- return;
- }
-
- if (getValues("addContacts").length === 0) {
- clearErrors("addContacts")
- } else {
- const errorRows = rows.filter(row => String(row.name).trim().length === 0 || String(row.phone).trim().length === 0 || String(row.email).trim().length === 0)
-
- if (errorRows.length > 0) {
- setError("addContacts", { message: "Contact details include empty fields", type: "required" })
- } else {
- const errorRows_EmailFormat = rows.filter(row => !/^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/.test(String(row.email)))
- if (errorRows_EmailFormat.length > 0) {
- setError("addContacts", { message: "Contact details include empty fields", type: "email_format" })
- } else {
- clearErrors("addContacts")
- }
- }
- }
- }, [rows, rowModesModel])
-
- // check editing
- useEffect(() => {
- const filteredByKey = Object.fromEntries(
- Object.entries(rowModesModel).filter(([key, value]) => rowModesModel[key].mode === 'edit'))
-
- if (Object.keys(filteredByKey).length > 0) {
- setValue("isGridEditing", true)
- } else {
- setValue("isGridEditing", false)
- }
- }, [rowModesModel])
-
- return (
- <Card sx={{ display: "block" }}>
- <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
- <Stack gap={2}>
- {/* <div> */}
- <Typography variant="overline" display='inline-block' noWrap>
- {t("Contact Info")}
- </Typography>
- {Boolean(errors.addContacts?.type === "required") && <Typography sx={(theme) => ({ color: theme.palette.error.main })} variant="overline" display='inline-block' noWrap>
- {t("Please ensure at least one row is created, and all the fields are inputted and saved")}
- </Typography>}
- {Boolean(errors.addContacts?.type === "email_format") && <Typography sx={(theme) => ({ color: theme.palette.error.main })} variant="overline" display='inline-block' noWrap>
- {t("Please ensure all the email formats are correct")}
- </Typography>}
- {/* </div> */}
- <CustomDatagrid
- rows={[...rows]}
- columns={columns}
- editMode="row"
- rowModesModel={rowModesModel}
- onRowEditStop={handleRowEditStop}
- processRowUpdate={processRowUpdate}
- // onProcessRowUpdateError={handleProcessRowUpdateError}
- onRowModesModelChange={handleRowModesModelChange}
- slots={{
- toolbar: EditToolbar,
- }}
- slotProps={{
- toolbar: { setRows, setRowModesModel },
- }}
- sx={{
- height: '100%'
- }}
- />
- <CardActions sx={{ justifyContent: "flex-end" }}>
- <Button variant="text" startIcon={<RestartAlt />} onClick={resetContact} disabled={Boolean(watch("isGridEditing"))}>
- {t("Reset")}
- </Button>
- </CardActions>
- </Stack>
- </CardContent>
- </Card>
- );
- };
-
- export default ContactInfo;
|