Przeglądaj źródła

add custom input datagrid component

feature/axios_provider
MSI\derek 5 miesięcy temu
rodzic
commit
253c021ce4
13 zmienionych plików z 859 dodań i 48 usunięć
  1. +1
    -1
      src/app/(main)/settings/material/page.tsx
  2. +17
    -0
      src/app/api/settings/material/actions.ts
  3. +4
    -2
      src/components/CreateMaterial/CreateMaterialWrapper.tsx
  4. +195
    -35
      src/components/CreateMaterial/MaterialDetails.tsx
  5. +1
    -0
      src/components/CreateProject/MilestoneSection.tsx
  6. +2
    -6
      src/components/DashboardPage/DashboardPage.tsx
  7. +3
    -1
      src/components/MaterialSearch/MaterialSearch.tsx
  8. +0
    -1
      src/components/MaterialSearch/MaterialSearchWrapper.tsx
  9. +1
    -1
      src/components/NavigationContent/NavigationContent.tsx
  10. +1
    -1
      src/components/SearchResults/SearchResults.tsx
  11. +307
    -0
      src/components/useInputDataGrid/backup
  12. +1
    -0
      src/components/useInputDataGrid/index.ts
  13. +326
    -0
      src/components/useInputDataGrid/useInputDataGrid.tsx

+ 1
- 1
src/app/(main)/settings/material/page.tsx Wyświetl plik

@@ -9,7 +9,7 @@ import Link from "next/link";
import { Suspense } from "react";

export const metadata: Metadata = {
title: "Claims",
title: "Material",
};

const materialSetting: React.FC = async () => {


+ 17
- 0
src/app/api/settings/material/actions.ts Wyświetl plik

@@ -4,7 +4,24 @@ import { revalidateTag } from "next/cache";
import { BASE_API_URL } from "@/config/api";

export type CreateMaterialInputs = {
id?: string | number
code: string;
name: string;
isConsumables: boolean;
description?: string | undefined;
type?: string | undefined;
remarks?: string | undefined;
shelfLife?: Number | undefined;
countryOfOrigin?: string | undefined;
minHumid?: number | undefined;
maxHumid?: number | undefined;
minTemp?: number | undefined;
maxTemp?: number | undefined;
sampleRate?: number | undefined;
passingRate?: number | undefined;
netWeight?: number | undefined;
uom?: any;
weightUnit?: any;
}

export const saveMaterial = async (data: CreateMaterialInputs) => {


+ 4
- 2
src/components/CreateMaterial/CreateMaterialWrapper.tsx Wyświetl plik

@@ -1,6 +1,6 @@
import CreateStaff from "./CreateMaterial";
import CreateMaterialLoading from "./CreateMaterialLoading";
import { cookies } from 'next/headers'
interface SubComponents {
Loading: typeof CreateMaterialLoading;
}
@@ -12,7 +12,9 @@ type CreateMaterialProps = {
type Props = CreateMaterialProps

const CreateMaterialWrapper: React.FC<Props> & SubComponents = async (props) => {
console.log(props)
const cookieStore = await cookies()
// console.log("==================cookieStore==================")
// console.log(cookieStore)

return <CreateStaff isEditMode={Boolean(props.isEditMode)}/>
}


+ 195
- 35
src/components/CreateMaterial/MaterialDetails.tsx Wyświetl plik

@@ -1,54 +1,87 @@
"use client";
import { CreateMaterialInputs } from "@/app/api/settings/material/actions";
import { Box, Card, CardContent, Grid, Stack, TextField, Typography } from "@mui/material";
import {
Box,
Card,
CardContent,
Grid,
Stack,
TextField,
Typography,
} from "@mui/material";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import ControlledAutoComplete from "../ControlledAutoComplete";

import InputDataGrid from "../useInputDataGrid";
import useInputDataGrid from "../useInputDataGrid";
import { useMemo, useState } from "react";
import { GridColDef, GridRowModesModel } from "@mui/x-data-grid";
import {
InputDataGridProps,
ResultWithId,
} from "../useInputDataGrid/useInputDataGrid";
type Props = {
isEditMode: boolean;
};
export type EntryError = {
[field in keyof CreateMaterialInputs]?: string;
};

const MaterialDetails: React.FC<Props> = ({ isEditMode }) => {
const {
t,
i18n: { language },
} = useTranslation();

const MaterialDetails: React.FC<Props> = ({
isEditMode,
}) => {
const {
t,
i18n: { language },
} = useTranslation();
const {
register,
formState: { errors, defaultValues, touchedFields },
watch,
control,
setValue,
getValues,
reset,
resetField,
setError,
clearErrors,
} = useFormContext<CreateMaterialInputs>();
const columns = useMemo<GridColDef[]>(() => [], []);
const validationTest = (): EntryError => {
const error: EntryError = {};
return error;
};
const MaterialTypeInputGridProps: InputDataGridProps<
Partial<CreateMaterialInputs>,
EntryError
> = {
_formKey: "type",
columns,
validation: validationTest,
};
const MaterialUomInputGridProps: InputDataGridProps<
Partial<CreateMaterialInputs>,
EntryError
> = {
_formKey: "uom",
columns,
validation: validationTest,
};
const { DataGrid: MaterialTypeInputGrid } = useInputDataGrid(
MaterialTypeInputGridProps
);
const { DataGrid: MaterialUomInputGrid } = useInputDataGrid(
MaterialUomInputGridProps
);

const {
register,
formState: { errors, defaultValues, touchedFields },
watch,
control,
setValue,
getValues,
reset,
resetField,
setError,
clearErrors
} = useFormContext<CreateMaterialInputs>();
return (
<Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}>
<Box>
<Typography variant="overline" display="block" marginBlockEnd={1}>
<Typography variant="overline" display="block" marginBlockEnd={1}>
{t("Material Details")}
</Typography>
<Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
<Grid item xs={6}>
<ControlledAutoComplete
control={control}
options={[]}
name="name"
label={t("name")}
noOptionsText={t("No Option")}
// disabled={isEditMode}
/>
</Grid>
<Grid item xs={6}>
<Grid item xs={6}>
<TextField
label={t("Name")}
fullWidth
@@ -58,10 +91,137 @@ const MaterialDetails: React.FC<Props> = ({
error={Boolean(errors.name)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Code")}
fullWidth
{...register("code", {
required: "code required!",
})}
error={Boolean(errors.code)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("description")}
fullWidth
{...register("description", {
required: "description required!",
})}
error={Boolean(errors.description)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("shelfLife")}
fullWidth
{...register("shelfLife", {
required: "shelfLife required!",
})}
error={Boolean(errors.shelfLife)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("countryOfOrigin")}
fullWidth
{...register("countryOfOrigin", {
required: "countryOfOrigin required!",
})}
error={Boolean(errors.countryOfOrigin)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("minHumid")}
fullWidth
{...register("minHumid", {
required: "minHumid required!",
})}
error={Boolean(errors.minHumid)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("maxHumid")}
fullWidth
{...register("maxHumid", {
required: "maxHumid required!",
})}
error={Boolean(errors.maxHumid)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("minTemp")}
fullWidth
{...register("minTemp", {
required: "minTemp required!",
})}
error={Boolean(errors.minTemp)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("maxTemp")}
fullWidth
{...register("maxTemp", {
required: "maxTemp required!",
})}
error={Boolean(errors.maxTemp)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("sampleRate")}
fullWidth
{...register("sampleRate", {
required: "sampleRate required!",
})}
error={Boolean(errors.sampleRate)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("passingRate")}
fullWidth
{...register("passingRate", {
required: "passingRate required!",
})}
error={Boolean(errors.passingRate)}
/>
</Grid>
<Grid item xs={6} />
<Grid item xs={6}>
<TextField
label={t("remarks")}
fullWidth
{...register("remarks", {
required: "remarks required!",
})}
error={Boolean(errors.remarks)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("netWeight")}
fullWidth
{...register("netWeight", {
required: "netWeight required!",
})}
error={Boolean(errors.netWeight)}
/>
</Grid>
<Grid item xs={6}>
<MaterialTypeInputGrid />
</Grid>
<Grid item xs={6}>
<MaterialUomInputGrid />
</Grid>
</Grid>
</Box>
</CardContent>
</Card>
);
);
};
export default MaterialDetails;

+ 1
- 0
src/components/CreateProject/MilestoneSection.tsx Wyświetl plik

@@ -39,6 +39,7 @@ interface Props {
declare module "@mui/x-data-grid" {
interface FooterPropsOverrides {
onAdd: () => void;
child?: React.ReactNode;
}
}



+ 2
- 6
src/components/DashboardPage/DashboardPage.tsx Wyświetl plik

@@ -7,18 +7,14 @@ import React, { useCallback, useEffect, useState } from "react";
import { useRouter } from "next/navigation";

type Props = {
// abilities: string[]
}
const DashboardPage: React.FC<Props> = ({
// abilities
}) => {
const { t } = useTranslation("dashboard");
const router = useRouter();

// useEffect(()=> {
// window.localStorage.setItem("abilities", JSON.stringify(abilities))
// })

return (
<ThemeProvider theme={theme}>
<>


+ 3
- 1
src/components/MaterialSearch/MaterialSearch.tsx Wyświetl plik

@@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults";
import { EditNote } from "@mui/icons-material";
import { useRouter, useSearchParams } from "next/navigation";
import { GridDeleteIcon } from "@mui/x-data-grid";

type Props = {
materials: MaterialResult[]
@@ -17,7 +18,7 @@ type SearchParamNames = keyof SearchQuery;
const MaterialSearch: React.FC<Props> = ({
materials
}) => {
const [filteredMaterials, setFilteredMaterials] = useState<MaterialResult[]>([])
const [filteredMaterials, setFilteredMaterials] = useState<MaterialResult[]>(materials)
const { t } = useTranslation("materials");
const router = useRouter();

@@ -59,6 +60,7 @@ const router = useRouter();
{
name: "action",
label: t(""),
buttonIcon: <GridDeleteIcon />,
onClick: onDeleteClick,
},


+ 0
- 1
src/components/MaterialSearch/MaterialSearchWrapper.tsx Wyświetl plik

@@ -7,7 +7,6 @@ interface SubComponents {
}

const MaterialSearchWrapper: React.FC & SubComponents = async () => {
// const materials: MaterialResult[] = []
const materials = await fetchMaterials();
console.log(materials)



+ 1
- 1
src/components/NavigationContent/NavigationContent.tsx Wyświetl plik

@@ -37,7 +37,7 @@ const NavigationContent: React.FC = () => {
{
icon: <Dashboard />,
label: "Dashboard",
path: "",
path: "/dashboard",
},
{
icon: <RequestQuote />,


+ 1
- 1
src/components/SearchResults/SearchResults.tsx Wyświetl plik

@@ -97,7 +97,7 @@ function SearchResults<T extends ResultWithId>({
{column.buttonIcon}
</IconButton>
) : (
<>{item[columnName]}</>
<>{item[columnName] as string}</>
)}
</TableCell>
);


+ 307
- 0
src/components/useInputDataGrid/backup Wyświetl plik

@@ -0,0 +1,307 @@
// import {
// Dispatch,
// SetStateAction,
// useCallback,
// useEffect,
// useMemo,
// useState,
// } from "react";
// import StyledDataGrid from "../StyledDataGrid";
// import {
// FooterPropsOverrides,
// GridActionsCellItem,
// GridCellParams,
// GridColDef,
// GridRowId,
// GridRowIdGetter,
// GridRowModel,
// GridRowModes,
// GridRowModesModel,
// GridToolbarContainer,
// GridValidRowModel,
// useGridApiRef,
// } from "@mui/x-data-grid";
// import { useFormContext } from "react-hook-form";
// import SaveIcon from "@mui/icons-material/Save";
// import DeleteIcon from "@mui/icons-material/Delete";
// import CancelIcon from "@mui/icons-material/Cancel";
// import { Add } from "@mui/icons-material";
// import { Box, Button, Typography } from "@mui/material";
// import { useTranslation } from "react-i18next";

// export interface ResultWithId {
// id: string | number;
// }

// export type TableRow<T extends ResultWithId, E> = Partial<
// T & {
// _isNew: boolean;
// _error: E;
// }
// >;

// export type InputDataGridProps<T extends ResultWithId, E> = {
// formKey: string;
// // items?: TableRow<T, E>[];
// columns: GridColDef[];
// _rowModesModel: GridRowModesModel;
// validation: () => E;
// };

// export class ProcessRowUpdateError<T, E> extends Error {
// public readonly row: T;
// public readonly errors: E | undefined;
// constructor(row: T, message?: string, errors?: E) {
// super(message);
// this.row = row;
// this.errors = errors;

// Object.setPrototypeOf(this, ProcessRowUpdateError.prototype);
// }
// }

// function useInputDataGrid<T extends ResultWithId, E>({
// formKey = "testing",
// // items,
// columns,
// _rowModesModel,
// validation,
// }: InputDataGridProps<T, E>): {
// DataGrid: React.FC;
// rowModesModel: GridRowModesModel;
// setRowModesModel: Dispatch<SetStateAction<GridRowModesModel>>;
// } {
// const {
// t,
// // i18n: { language },
// } = useTranslation();
// const { setValue, getValues } = useFormContext();
// const [rowModesModel, setRowModesModel] =
// useState<GridRowModesModel>(_rowModesModel);
// const apiRef = useGridApiRef();
// const getRowId = useCallback<GridRowIdGetter<TableRow<T, E>>>(
// (row) => row.id!!.toString(),
// []
// );
// const list: TableRow<T, E>[] = getValues(formKey);
// const [rows, setRows] = useState<TableRow<T, E>[]>(() => {
// const list: TableRow<T, E>[] = getValues(formKey);
// return list && list.length > 0 ? list : [];
// });
// const originalRows = list && list.length > 0 ? list : [];

// const handleSave = useCallback(
// (id: GridRowId) => () => {
// setRowModesModel((prevRowModesModel) => ({
// ...prevRowModesModel,
// [id]: { mode: GridRowModes.View },
// }));
// },
// [setRowModesModel]
// );
// const onProcessRowUpdateError = useCallback(
// (updateError: ProcessRowUpdateError<T, E>) => {
// const errors = updateError.errors;
// const row = updateError.row;
// console.log(errors);
// apiRef.current.updateRows([{ ...row, _error: errors }]);
// },
// [apiRef, rowModesModel]
// );

// const processRowUpdate = useCallback(
// (
// newRow: GridRowModel<TableRow<T, E>>,
// originalRow: GridRowModel<TableRow<T, E>>
// ) => {
// /////////////////
// // validation here
// // const errors = validation(); //repace true with validation method
// // if (errors) {
// // throw new ProcessRowUpdateError(
// // originalRow,
// // "validation error",
// // errors,
// // );
// // }
// /////////////////
// const { _isNew, _error, ...updatedRow } = newRow;
// const rowToSave = {
// ...updatedRow,
// } as TableRow<T, E>; /// test
// setRows((rw) =>
// rw.map((r) => (getRowId(r) === getRowId(originalRow) ? rowToSave : r))
// );

// return rowToSave;
// },
// [rows]
// );

// const addRow = useCallback(() => {
// const newEntry = { id: Date.now(), _isNew: true } as TableRow<T, E>;
// setRows((prev) => [...prev, newEntry]);
// setRowModesModel((model) => ({
// ...model,
// [getRowId(newEntry)]: {
// mode: GridRowModes.Edit,
// // fieldToFocus: "team", /// test
// },
// }));
// }, [getRowId]);

// const handleCancel = useCallback(
// (id: GridRowId) => () => {
// setRowModesModel((model) => ({
// ...model,
// [id]: { mode: GridRowModes.View, ignoreModifications: true },
// }));
// const editedRow = rows.find((row) => getRowId(row) === id);
// console.log(editedRow);
// 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) => getRowId(row) !== id));
// },
// []
// );

// const _columns = useMemo<GridColDef[]>(
// () => [
// ...columns,
// {
// field: "actions",
// type: "actions",
// headerName: "edit",
// width: 100,
// cellClassName: "actions",
// getActions: ({ id }: { id: GridRowId }) => {
// const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
// if (isInEditMode) {
// return [
// <GridActionsCellItem
// icon={<SaveIcon />}
// label="Save"
// key="edit"
// sx={{
// color: "primary.main",
// }}
// onClick={handleSave(id)}
// />,
// <GridActionsCellItem
// icon={<CancelIcon />}
// label="Cancel"
// key="edit"
// onClick={handleCancel(id)}
// />,
// ];
// }
// return [
// <GridActionsCellItem
// icon={<DeleteIcon />}
// label="Delete"
// sx={{
// color: "error.main",
// }}
// onClick={handleDelete(id)}
// color="inherit"
// key="edit"
// />,
// ];
// },
// },
// ],
// []
// );

// // sync useForm
// useEffect(() => {
// setValue(formKey, rows);
// }, [rows]);

// const footer = (
// <Box display="flex" gap={2} alignItems="center">
// <Button
// disableRipple
// variant="outlined"
// startIcon={<Add />}
// onClick={addRow}
// size="small"
// >
// {t("Add Record")}
// </Button>
// </Box>
// );
// const DataGrid: React.FC = ({ ...props }) => (
// <StyledDataGrid
// getRowId={getRowId as GridRowIdGetter<GridValidRowModel>}
// apiRef={apiRef}
// rows={rows}
// columns={_columns}
// editMode="row"
// 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
// rowModesModel={rowModesModel}
// onRowModesModelChange={setRowModesModel}
// processRowUpdate={processRowUpdate as any}
// onProcessRowUpdateError={onProcessRowUpdateError}
// getCellClassName={(params: GridCellParams<TableRow<T, E>>) => {
// let classname = "";
// if (params.row._error) {
// classname = "hasError";
// }
// return classname;
// }}
// slots={{
// footer: FooterToolbar,
// noRowsOverlay: NoRowsOverlay,
// }}
// slotProps={{
// footer: { child: footer },
// }}
// />
// );
// return {
// DataGrid,
// rowModesModel,
// setRowModesModel,
// };
// }
// const FooterToolbar: React.FC<FooterPropsOverrides> = ({ child }) => {
// return <GridToolbarContainer sx={{ p: 2 }}>{child}</GridToolbarContainer>;
// };
// 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>
// );
// };
// export default useInputDataGrid;

+ 1
- 0
src/components/useInputDataGrid/index.ts Wyświetl plik

@@ -0,0 +1 @@
export { default } from "./useInputDataGrid";

+ 326
- 0
src/components/useInputDataGrid/useInputDataGrid.tsx Wyświetl plik

@@ -0,0 +1,326 @@
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import StyledDataGrid from "../StyledDataGrid";
import {
FooterPropsOverrides,
GridActionsCellItem,
GridCellParams,
GridColDef,
GridRowId,
GridRowIdGetter,
GridRowModel,
GridRowModes,
GridRowModesModel,
GridToolbarContainer,
GridValidRowModel,
useGridApiRef,
} from "@mui/x-data-grid";
import { useFormContext } from "react-hook-form";
import SaveIcon from "@mui/icons-material/Save";
import DeleteIcon from "@mui/icons-material/Delete";
import CancelIcon from "@mui/icons-material/Cancel";
import { Add } from "@mui/icons-material";
import { Box, Button, Typography } from "@mui/material";
import { useTranslation } from "react-i18next";

export interface ResultWithId {
id: string | number;
}
type DataGridProps = {
[key: string]: any
}
export type TableRow<T, E> = Partial<
T & {
_isNew: boolean;
_error: E;
} & ResultWithId
>;

export type InputDataGridProps<T, E> = {
_formKey: keyof T;
columns: GridColDef[];
validation: () => E;
};

export class ProcessRowUpdateError<T, E> extends Error {
public readonly row: T;
public readonly errors: E | undefined;
constructor(row: T, message?: string, errors?: E) {
super(message);
this.row = row;
this.errors = errors;

Object.setPrototypeOf(this, ProcessRowUpdateError.prototype);
}
}

function useInputDataGrid<T, E>({
_formKey,
columns,
validation,
}: InputDataGridProps<T, E>): {
DataGrid: React.FC;
rowModesModel: GridRowModesModel;
setRowModesModel: Dispatch<SetStateAction<GridRowModesModel>>;
} {
const {
t,
// i18n: { language },
} = useTranslation();
const formKey = _formKey.toString()
const { setValue, getValues } = useFormContext();
const [rowModesModel, setRowModesModel] =
useState<GridRowModesModel>({});
const apiRef = useGridApiRef();
const getRowId = useCallback<GridRowIdGetter<TableRow<T, E>>>(
(row) => row.id!! as number,
[]
);
const list: TableRow<T, E>[] = getValues(formKey);
const [rows, setRows] = useState<TableRow<T, E>[]>(() => {
const list: TableRow<T, E>[] = getValues(formKey);
return list && list.length > 0 ? list : [];
});
const originalRows = list && list.length > 0 ? list : [];

const handleSave = useCallback(
(id: GridRowId) => () => {
setRowModesModel((prevRowModesModel) => ({
...prevRowModesModel,
[id]: { mode: GridRowModes.View },
}));
},
[setRowModesModel]
);
const onProcessRowUpdateError = useCallback(
(updateError: ProcessRowUpdateError<T, E>) => {
const errors = updateError.errors;
const row = updateError.row;
console.log(errors);
apiRef.current.updateRows([{ ...row, _error: errors }]);
},
[apiRef, rowModesModel]
);

const processRowUpdate = useCallback(
(
newRow: GridRowModel<TableRow<T, E>>,
originalRow: GridRowModel<TableRow<T, E>>
) => {
/////////////////
// validation here
// const errors = validation(); //repace true with validation method
// if (errors) {
// throw new ProcessRowUpdateError(
// originalRow,
// "validation error",
// errors,
// );
// }
/////////////////
const { _isNew, _error, ...updatedRow } = newRow;
const rowToSave = {
...updatedRow,
} as TableRow<T, E>; /// test
setRows((rw) =>
rw.map((r) => (getRowId(r) === getRowId(originalRow) ? rowToSave : r))
);

return rowToSave;
},
[rows]
);

const addRow = useCallback(() => {
const newEntry = { id: Date.now(), _isNew: true } as TableRow<T, E>;
setRows((prev) => [...prev, newEntry]);
// console.log(newEntry)
setRowModesModel((model) => ({
...model,
[getRowId(newEntry)]: {
mode: GridRowModes.Edit,
// fieldToFocus: "team", /// test
},
}));
}, [getRowId]);

const reset = useCallback(() => {
setRowModesModel({})
setRows([])
}, []);

const handleCancel = useCallback(
(id: GridRowId) => () => {
setRowModesModel((model) => ({
...model,
[id]: { mode: GridRowModes.View, ignoreModifications: true },
}));
const editedRow = rows.find((row) => getRowId(row) === id);
if (editedRow?._isNew) {
setRows((rw) => rw.filter((r) => getRowId(r) !== id
));
} else {
setRows((rw) =>
rw.map((r) => (getRowId(r) === id ? { ...r, _error: undefined } : r))
);
}
},
[setRowModesModel, rows]
);
useEffect(() => {
console.log(rows)
}, [rows])
const handleDelete = useCallback(
(id: GridRowId) => () => {
setRows((prevRows) => prevRows.filter((row) => getRowId(row) !== id));
},
[]
);
if (columns) {

}
const _columns = useMemo<GridColDef[]>(
() => [
...columns,
{
field: "actions",
type: "actions",
headerName: "",
width: 100,
cellClassName: "actions",
getActions: ({ id }: { id: GridRowId }) => {
const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
if (isInEditMode) {
return [
<GridActionsCellItem
icon={<SaveIcon />}
label="Save"
key="edit"
sx={{
color: "primary.main",
}}
onClick={handleSave(id)}
/>,
<GridActionsCellItem
icon={<CancelIcon />}
label="Cancel"
key="edit"
onClick={handleCancel(id)}
/>,
];
}
return [
<GridActionsCellItem
icon={<DeleteIcon />}
label="Delete"
sx={{
color: "error.main",
}}
onClick={handleDelete(id)}
color="inherit"
key="edit"
/>,
];
},
},
],
[rowModesModel, handleSave, handleCancel, handleDelete]
);

// sync useForm
useEffect(() => {
setValue(formKey, rows);
}, [rows]);

const footer = (
<Box display="flex" gap={2} alignItems="center">
<Button
disableRipple
variant="outlined"
startIcon={<Add />}
onClick={addRow}
size="small"
>
{t("Add Record")}
</Button>
<Button
disableRipple
variant="outlined"
startIcon={<Add />}
onClick={reset}
size="small"
>
{t("Clean Record")}
</Button>
</Box>
);
const DataGrid: React.FC<DataGridProps> = (props) => (
<StyledDataGrid
{...props}
getRowId={getRowId as GridRowIdGetter<GridValidRowModel>}
apiRef={apiRef}
rows={rows}
columns={_columns}
editMode="row"
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
rowModesModel={rowModesModel}
onRowModesModelChange={setRowModesModel}
processRowUpdate={processRowUpdate as any}
onProcessRowUpdateError={onProcessRowUpdateError}
getCellClassName={(params: GridCellParams<TableRow<T, E>>) => {
let classname = "";
if (params.row._error) {
classname = "hasError";
}
return classname;
}}
slots={{
footer: FooterToolbar,
noRowsOverlay: NoRowsOverlay,
}}
slotProps={{
footer: { child: footer },
}}
/>
);
return {
DataGrid,
rowModesModel,
setRowModesModel,
};
}
const FooterToolbar: React.FC<FooterPropsOverrides> = ({ child }) => {
return <GridToolbarContainer sx={{ p: 2 }}>{child}</GridToolbarContainer>;
};
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>
);
};
export default useInputDataGrid;

Ładowanie…
Anuluj
Zapisz