| @@ -1,6 +1,6 @@ | |||
| import { SearchParams } from "@/app/utils/fetchUtil"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import CreateProductMaterial from "@/components/CreateProductMaterial"; | |||
| import CreateProductMaterial from "@/components/CreateItem"; | |||
| import { I18nProvider, getServerI18n } from "@/i18n"; | |||
| import { Typography } from "@mui/material"; | |||
| import { isString } from "lodash"; | |||
| @@ -15,7 +15,7 @@ const byProductSetting: React.FC<Props> = async ({ searchParams }) => { | |||
| return ( | |||
| <> | |||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | |||
| <I18nProvider namespaces={[type]}> | |||
| <I18nProvider namespaces={[type.toString()]}> | |||
| <CreateProductMaterial type={type} /> | |||
| </I18nProvider> | |||
| </> | |||
| @@ -1,6 +1,6 @@ | |||
| import { SearchParams } from "@/app/utils/fetchUtil"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import CreateProductMaterial from "@/components/CreateProductMaterial"; | |||
| import CreateProductMaterial from "@/components/CreateItem"; | |||
| import { I18nProvider, getServerI18n } from "@/i18n"; | |||
| import { Typography } from "@mui/material"; | |||
| import { isString } from "lodash"; | |||
| @@ -1,5 +1,5 @@ | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import MaterialSearch from "@/components/ProductMaterialSearch"; | |||
| import MaterialSearch from "@/components/ItemsSearch"; | |||
| import { getServerI18n } from "@/i18n"; | |||
| import Add from "@mui/icons-material/Add"; | |||
| import Button from "@mui/material/Button"; | |||
| @@ -1,6 +1,6 @@ | |||
| import { SearchParams } from "@/app/utils/fetchUtil"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import CreateProductMaterial from "@/components/CreateProductMaterial"; | |||
| import CreateProductMaterial from "@/components/CreateItem"; | |||
| import { I18nProvider, getServerI18n } from "@/i18n"; | |||
| import { Typography } from "@mui/material"; | |||
| import { isString } from "lodash"; | |||
| @@ -1,6 +1,6 @@ | |||
| import { SearchParams } from "@/app/utils/fetchUtil"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import CreateProductMaterial from "@/components/CreateProductMaterial"; | |||
| import CreateProductMaterial from "@/components/CreateItem"; | |||
| import { I18nProvider, getServerI18n } from "@/i18n"; | |||
| import { Typography } from "@mui/material"; | |||
| import { isString } from "lodash"; | |||
| @@ -22,7 +22,7 @@ const materialSetting: React.FC<Props> = async ({ searchParams }) => { | |||
| return ( | |||
| <> | |||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | |||
| <I18nProvider namespaces={[type]}> | |||
| <I18nProvider namespaces={[type.toString()]}> | |||
| <CreateProductMaterial type={type} id={id} /> | |||
| </I18nProvider> | |||
| </> | |||
| @@ -1,5 +1,5 @@ | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import MaterialSearch from "@/components/ProductMaterialSearch"; | |||
| import MaterialSearch from "@/components/ItemsSearch"; | |||
| import { getServerI18n } from "@/i18n"; | |||
| import Add from "@mui/icons-material/Add"; | |||
| import Button from "@mui/material/Button"; | |||
| @@ -15,7 +15,7 @@ export const metadata: Metadata = { | |||
| const materialSetting: React.FC = async () => { | |||
| const material = TypeEnum.MATERIAL | |||
| const { t } = await getServerI18n(material); | |||
| const { t } = await getServerI18n("material"); | |||
| // preloadClaims(); | |||
| return ( | |||
| @@ -1,6 +1,6 @@ | |||
| import { SearchParams } from "@/app/utils/fetchUtil"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import CreateProductMaterial from "@/components/CreateProductMaterial"; | |||
| import CreateProductMaterial from "@/components/CreateItem"; | |||
| import { I18nProvider, getServerI18n } from "@/i18n"; | |||
| import { Typography } from "@mui/material"; | |||
| import isString from "lodash/isString"; | |||
| @@ -1,6 +1,6 @@ | |||
| import { SearchParams } from "@/app/utils/fetchUtil"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import CreateProductMaterial from "@/components/CreateProductMaterial"; | |||
| import CreateProductMaterial from "@/components/CreateItem"; | |||
| import { I18nProvider, getServerI18n } from "@/i18n"; | |||
| import { Typography } from "@mui/material"; | |||
| import isString from "lodash/isString"; | |||
| @@ -1,5 +1,5 @@ | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import MaterialSearch from "@/components/ProductMaterialSearch"; | |||
| import MaterialSearch from "@/components/ItemsSearch"; | |||
| import { getServerI18n } from "@/i18n"; | |||
| import Add from "@mui/icons-material/Add"; | |||
| import Button from "@mui/material/Button"; | |||
| @@ -1,39 +0,0 @@ | |||
| "use server"; | |||
| import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; | |||
| import { revalidateTag } from "next/cache"; | |||
| import { BASE_API_URL } from "@/config/api"; | |||
| import { TypeInputs, UomInputs, WeightUnitInputs } from "../material/actions"; | |||
| import { CreateItemResponse } from "../../utils"; | |||
| export type CreateByProductInputs = { | |||
| id?: string | number | |||
| code: string; | |||
| name: string; | |||
| // same goes for other props | |||
| // change backend for null or not null | |||
| description?: 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; | |||
| type?: TypeInputs[]; | |||
| uom?: UomInputs[]; | |||
| weightUnit?: WeightUnitInputs[]; | |||
| } | |||
| export const saveByProduct = async (data: CreateByProductInputs) => { | |||
| // try { | |||
| const byProduct = await serverFetchJson<CreateItemResponse<CreateByProductInputs>>(`${BASE_API_URL}/byProduct/new`, { | |||
| method: "POST", | |||
| body: JSON.stringify(data), | |||
| headers: { "Content-Type": "application/json" }, | |||
| }); | |||
| revalidateTag("byProduct"); | |||
| return byProduct | |||
| }; | |||
| @@ -1,40 +0,0 @@ | |||
| import { cache } from "react"; | |||
| import "server-only"; | |||
| import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||
| import { BASE_API_URL } from "@/config/api"; | |||
| import { TypeInputs, UomInputs, WeightUnitInputs } from "../material/actions"; | |||
| export type ByProductResult = { | |||
| id: string | number | |||
| code: string; | |||
| name: string; | |||
| description: 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: UomInputs[]; | |||
| weightUnit: WeightUnitInputs[]; | |||
| type: TypeInputs[]; | |||
| action?: any; | |||
| } | |||
| export const fetchAllByProduct = cache(async () => { | |||
| return serverFetchJson<ByProductResult[]>(`${BASE_API_URL}/byProduct`, { | |||
| next: { tags: ["byProduct"] }, | |||
| }); | |||
| }); | |||
| export const fetchByProduct = cache(async (id: number) => { | |||
| return serverFetchJson<ByProductResult>(`${BASE_API_URL}/byProduct/details/${id}`, { | |||
| next: { tags: ["byProduct"] }, | |||
| }); | |||
| }); | |||
| @@ -6,7 +6,8 @@ import { HTMLInputTypeAttribute } from "react"; | |||
| import { CreateItemResponse } from "../../utils"; | |||
| export type TypeInputs = { | |||
| type: string | |||
| id: number; | |||
| name: string | |||
| } | |||
| export type UomInputs = { | |||
| uom: string | |||
| @@ -15,13 +16,10 @@ export type WeightUnitInputs = { | |||
| weightUnit: string | |||
| conversion: number | |||
| } | |||
| export type CreateMaterialInputs = { | |||
| export type CreateItemInputs = { | |||
| id?: string | number | |||
| code: string; | |||
| name: string; | |||
| isConsumables: boolean; | |||
| // same goes for other props | |||
| // change backend for null or not null | |||
| description?: string | undefined; | |||
| remarks?: string | undefined; | |||
| shelfLife?: Number | undefined; | |||
| @@ -32,19 +30,17 @@ export type CreateMaterialInputs = { | |||
| maxTemp?: number | undefined; | |||
| sampleRate?: number | undefined; | |||
| passingRate?: number | undefined; | |||
| netWeight?: number | undefined; | |||
| type?: TypeInputs[]; | |||
| uom?: UomInputs[]; | |||
| weightUnit?: WeightUnitInputs[]; | |||
| netWeight: number; | |||
| typeId: number; | |||
| } | |||
| export const saveMaterial = async (data: CreateMaterialInputs) => { | |||
| export const saveItem = async (data: CreateItemInputs) => { | |||
| // try { | |||
| const material = await serverFetchJson<CreateItemResponse<CreateMaterialInputs>>(`${BASE_API_URL}/material/new`, { | |||
| const item = await serverFetchJson<CreateItemResponse<CreateItemInputs>>(`${BASE_API_URL}/items/new`, { | |||
| method: "POST", | |||
| body: JSON.stringify(data), | |||
| headers: { "Content-Type": "application/json" }, | |||
| }); | |||
| revalidateTag("material"); | |||
| return material | |||
| revalidateTag("items"); | |||
| return item | |||
| }; | |||
| @@ -4,11 +4,10 @@ import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||
| import { BASE_API_URL } from "@/config/api"; | |||
| import { TypeInputs, UomInputs, WeightUnitInputs } from "./actions"; | |||
| export type MaterialResult = { | |||
| export type ItemsResult = { | |||
| id: string | number | |||
| code: string; | |||
| name: string; | |||
| isConsumables: boolean; | |||
| description: string | undefined; | |||
| remarks: string | undefined; | |||
| shelfLife: Number | undefined; | |||
| @@ -20,22 +19,22 @@ export type MaterialResult = { | |||
| sampleRate: number | undefined; | |||
| passingRate: number | undefined; | |||
| netWeight: number | undefined; | |||
| uom: UomInputs[]; | |||
| weightUnit: WeightUnitInputs[]; | |||
| type: TypeInputs[]; | |||
| // uom: UomInputs[]; | |||
| // weightUnit: WeightUnitInputs[]; | |||
| type: TypeInputs; | |||
| action?: any | |||
| } | |||
| export const fetchAllMaterials = cache(async () => { | |||
| return serverFetchJson<MaterialResult[]>(`${BASE_API_URL}/material`, { | |||
| next: { tags: ["material"] }, | |||
| export const fetchAllItems = cache(async () => { | |||
| return serverFetchJson<ItemsResult[]>(`${BASE_API_URL}/items`, { | |||
| next: { tags: ["items"] }, | |||
| }); | |||
| }); | |||
| export const fetchMaterial = cache(async (id: number) => { | |||
| return serverFetchJson<MaterialResult>(`${BASE_API_URL}/material/details/${id}`, { | |||
| next: { tags: ["material"] }, | |||
| export const fetchItem = cache(async (id: number) => { | |||
| return serverFetchJson<ItemsResult>(`${BASE_API_URL}/items/details/${id}`, { | |||
| next: { tags: ["items"] }, | |||
| }); | |||
| }); | |||
| @@ -1,37 +0,0 @@ | |||
| "use server"; | |||
| import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; | |||
| import { revalidateTag } from "next/cache"; | |||
| import { BASE_API_URL } from "@/config/api"; | |||
| import { TypeInputs, UomInputs, WeightUnitInputs } from "../material/actions"; | |||
| import { CreateItemResponse } from "../../utils"; | |||
| export type CreateProductInputs = { | |||
| id?: string | number | |||
| code: string; | |||
| name: string; | |||
| description?: 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; | |||
| type?: TypeInputs[]; | |||
| uom?: UomInputs[]; | |||
| weightUnit?: WeightUnitInputs[]; | |||
| } | |||
| export const saveProduct = async (data: CreateProductInputs) => { | |||
| // try { | |||
| const product = await serverFetchJson<CreateItemResponse<CreateProductInputs>>(`${BASE_API_URL}/product/new`, { | |||
| method: "POST", | |||
| body: JSON.stringify(data), | |||
| headers: { "Content-Type": "application/json" }, | |||
| }); | |||
| revalidateTag("product"); | |||
| return product | |||
| }; | |||
| @@ -1,40 +0,0 @@ | |||
| import { cache } from "react"; | |||
| import "server-only"; | |||
| import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||
| import { BASE_API_URL } from "@/config/api"; | |||
| import { TypeInputs, UomInputs, WeightUnitInputs } from "../material/actions"; | |||
| export type ProductResult = { | |||
| id: string | number | |||
| code: string; | |||
| name: string; | |||
| description: 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: UomInputs[]; | |||
| weightUnit: WeightUnitInputs[]; | |||
| type: TypeInputs[]; | |||
| action?: any; | |||
| } | |||
| export const fetchAllProduct = cache(async () => { | |||
| return serverFetchJson<ProductResult[]>(`${BASE_API_URL}/product`, { | |||
| next: { tags: ["product"] }, | |||
| }); | |||
| }); | |||
| export const fetchProduct = cache(async (id: number) => { | |||
| return serverFetchJson<ProductResult>(`${BASE_API_URL}/product/details/${id}`, { | |||
| next: { tags: ["product"] }, | |||
| }); | |||
| }); | |||
| @@ -1,5 +1,10 @@ | |||
| export enum TypeEnum { | |||
| PRODUCT = "product", | |||
| MATERIAL = "material", | |||
| MATERIAL_ID = 1, | |||
| PRODUCT = "product", | |||
| PRODUCT_ID = 2, | |||
| BYPRODUCT = "byProduct", | |||
| } | |||
| BYPRODUCT_ID = 3, | |||
| CONSUMABLE = "consumables", | |||
| CONSUMABLE_ID = 4, | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| "use client"; | |||
| import { CreateMaterialInputs } from "@/app/api/settings/material/actions"; | |||
| import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
| import { | |||
| Box, | |||
| Card, | |||
| @@ -12,27 +12,24 @@ import { | |||
| import { useFormContext } from "react-hook-form"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import InputDataGrid from "../InputDataGrid"; | |||
| import { useCallback, useMemo, useState } from "react"; | |||
| import { useCallback, useEffect, useMemo, useState } from "react"; | |||
| import { GridColDef, GridRowModel } from "@mui/x-data-grid"; | |||
| import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import { CreateByProductInputs } from "@/app/api/settings/byProduct/actions"; | |||
| import { NumberInputProps } from "./NumberInputProps"; | |||
| type Props = { | |||
| // isEditMode: boolean; | |||
| // type: TypeEnum; | |||
| // isEditMode: boolean; | |||
| // type: TypeEnum; | |||
| }; | |||
| export type EntryError = | |||
| | { | |||
| [field in keyof CreateByProductInputs]?: string; | |||
| [field in keyof CreateItemInputs]?: string; | |||
| } | |||
| | undefined; | |||
| const ByProductDetails: React.FC<Props> = ({ | |||
| }) => { | |||
| const ByProductDetails: React.FC<Props> = ({}) => { | |||
| const { | |||
| t, | |||
| i18n: { language }, | |||
| @@ -49,7 +46,7 @@ const ByProductDetails: React.FC<Props> = ({ | |||
| resetField, | |||
| setError, | |||
| clearErrors, | |||
| } = useFormContext<CreateByProductInputs>(); | |||
| } = useFormContext<CreateItemInputs>(); | |||
| const typeColumns = useMemo<GridColDef[]>( | |||
| () => [ | |||
| { | |||
| @@ -93,7 +90,7 @@ const ByProductDetails: React.FC<Props> = ({ | |||
| const validationTest = useCallback( | |||
| ( | |||
| newRow: GridRowModel<TableRow<Partial<CreateByProductInputs>, EntryError>> | |||
| newRow: GridRowModel<TableRow<Partial<CreateItemInputs>, EntryError>> | |||
| ): EntryError => { | |||
| const error: EntryError = {}; | |||
| console.log(newRow); | |||
| @@ -102,6 +99,22 @@ const ByProductDetails: React.FC<Props> = ({ | |||
| [] | |||
| ); | |||
| const validateUom = useCallback( | |||
| ( | |||
| newRow: GridRowModel<TableRow<Partial<CreateItemInputs>, EntryError>> | |||
| ): EntryError => { | |||
| const error: EntryError = {}; | |||
| console.log(newRow); | |||
| // if (!newRow.uom) { | |||
| // error.uom = "Uom cannot be empty"; | |||
| // } | |||
| return Object.keys(error).length > 0 ? error : undefined; | |||
| }, | |||
| [] | |||
| ); | |||
| useEffect(() => { | |||
| console.log(errors) | |||
| }, [errors]) | |||
| return ( | |||
| <Card sx={{ display: "block" }}> | |||
| <CardContent component={Stack} spacing={4}> | |||
| @@ -272,27 +285,6 @@ const ByProductDetails: React.FC<Props> = ({ | |||
| helperText={errors.netWeight?.message} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <InputDataGrid<CreateByProductInputs, EntryError> | |||
| _formKey={"type"} | |||
| columns={typeColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <InputDataGrid<CreateByProductInputs, EntryError> | |||
| _formKey={"uom"} | |||
| columns={uomColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={12}> | |||
| <InputDataGrid<CreateByProductInputs, EntryError> | |||
| _formKey={"weightUnit"} | |||
| columns={weightUnitColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| </Grid> | |||
| </Box> | |||
| </CardContent> | |||
| @@ -4,9 +4,9 @@ import { useCallback, useEffect, useMemo, useState } from "react"; | |||
| import { useRouter, useSearchParams } from "next/navigation"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { | |||
| CreateMaterialInputs, | |||
| saveMaterial, | |||
| } from "@/app/api/settings/material/actions"; | |||
| CreateItemInputs, | |||
| saveItem, | |||
| } from "@/app/api/settings/item/actions"; | |||
| import { | |||
| FormProvider, | |||
| SubmitErrorHandler, | |||
| @@ -17,67 +17,69 @@ import { deleteDialog } from "../Swal/CustomAlerts"; | |||
| import { Box, Button, Grid, Stack, Typography } from "@mui/material"; | |||
| import { Check, Close, EditNote } from "@mui/icons-material"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import { | |||
| CreateProductInputs, | |||
| saveProduct, | |||
| } from "@/app/api/settings/product/actions"; | |||
| import { CreateInputsFields } from "./CreateProductMaterialWrapper"; | |||
| import MaterialDetails from "./MaterialDetails"; | |||
| import ProductDetails from "./ProductDetails"; | |||
| import { CreateItemResponse } from "@/app/api/utils"; | |||
| import { CreateByProductInputs, saveByProduct } from "@/app/api/settings/byProduct/actions"; | |||
| import ByProductDetails from "./ByProductDetails"; | |||
| type Props = { | |||
| isEditMode: boolean; | |||
| type: TypeEnum; | |||
| defaultValues: Partial<CreateInputsFields> | undefined; | |||
| defaultValues: Partial<CreateItemInputs> | undefined; | |||
| }; | |||
| const CreateProductMaterial: React.FC<Props> = ({ | |||
| const CreateItem: React.FC<Props> = ({ | |||
| isEditMode, | |||
| type, | |||
| defaultValues, | |||
| }) => { | |||
| console.log(type) | |||
| const [serverError, setServerError] = useState(""); | |||
| const [tabIndex, setTabIndex] = useState(0); | |||
| const { t } = useTranslation(); | |||
| const router = useRouter(); | |||
| const [title, mode, redirPath] = useMemo(() => { | |||
| const [typeId, title, mode, redirPath] = useMemo(() => { | |||
| var typeId = TypeEnum.CONSUMABLE_ID | |||
| var title = ""; | |||
| var mode = ""; | |||
| var redirPath = ""; | |||
| if (type === TypeEnum.MATERIAL) { | |||
| typeId = TypeEnum.MATERIAL_ID | |||
| title = "Material"; | |||
| redirPath = "/material"; | |||
| redirPath = "/settings/material"; | |||
| } | |||
| if (type === TypeEnum.PRODUCT) { | |||
| typeId = TypeEnum.PRODUCT_ID | |||
| title = "Product"; | |||
| redirPath = "/product"; | |||
| redirPath = "/settings/product"; | |||
| } | |||
| if (type === TypeEnum.BYPRODUCT) { | |||
| typeId = TypeEnum.BYPRODUCT_ID | |||
| title = "By-Product"; | |||
| redirPath = "/byProduct"; | |||
| redirPath = "/settings/byProduct"; | |||
| } | |||
| if (isEditMode) { | |||
| mode = "Edit"; | |||
| } else { | |||
| mode = "Create"; | |||
| } | |||
| return [title, mode, redirPath]; | |||
| return [typeId, title, mode, redirPath]; | |||
| }, [type, isEditMode]); | |||
| const formProps = useForm<CreateInputsFields>({ | |||
| defaultValues: defaultValues ? defaultValues : {}, | |||
| console.log(typeId) | |||
| const formProps = useForm<CreateItemInputs>({ | |||
| defaultValues: defaultValues ? defaultValues : { | |||
| typeId: typeId | |||
| }, | |||
| }); | |||
| const errors = formProps.formState.errors; | |||
| const handleCancel = () => { | |||
| router.replace(`/settings/${type}`); | |||
| }; | |||
| const onSubmit = useCallback<SubmitHandler<CreateInputsFields>>( | |||
| const onSubmit = useCallback<SubmitHandler<CreateItemInputs>>( | |||
| async (data, event) => { | |||
| let hasErrors = false; | |||
| console.log("dasasdasd") | |||
| try { | |||
| // checking humid input | |||
| if (data.maxHumid && data.minHumid!! > data.maxHumid!!) { | |||
| @@ -135,31 +137,19 @@ const CreateProductMaterial: React.FC<Props> = ({ | |||
| } | |||
| console.log("data posted"); | |||
| console.log(data); | |||
| // do api | |||
| var response; | |||
| if (type === TypeEnum.MATERIAL) { | |||
| response = await saveMaterial(data as CreateMaterialInputs); | |||
| } else if (type === TypeEnum.PRODUCT) { | |||
| response = await saveProduct(data as CreateProductInputs); | |||
| } else if (type === TypeEnum.BYPRODUCT) { | |||
| // response = await saveByProduct(data as CreateByProductInputs); | |||
| } else { | |||
| // Handle unexpected type | |||
| throw new Error("Invalid type provided"); | |||
| } | |||
| // return | |||
| // do api | |||
| var response = await saveItem(data); | |||
| if (response) { | |||
| if (!Boolean(response.id)) { | |||
| formProps.setError(response.errorPosition!! as keyof CreateInputsFields, { | |||
| formProps.setError(response.errorPosition!! as keyof CreateItemInputs, { | |||
| message: response.message!!, | |||
| type: "required", | |||
| }); | |||
| throw response; | |||
| } else if (Boolean(response.id)) { | |||
| router.replace(redirPath); | |||
| } | |||
| } else { | |||
| throw "no response"; | |||
| } | |||
| } catch (e) { | |||
| // backend error | |||
| @@ -171,7 +161,7 @@ const CreateProductMaterial: React.FC<Props> = ({ | |||
| ); | |||
| // multiple tabs | |||
| const onSubmitError = useCallback<SubmitErrorHandler<CreateInputsFields>>( | |||
| const onSubmitError = useCallback<SubmitErrorHandler<CreateItemInputs>>( | |||
| (errors) => {}, | |||
| [] | |||
| ); | |||
| @@ -220,4 +210,4 @@ const CreateProductMaterial: React.FC<Props> = ({ | |||
| </> | |||
| ); | |||
| }; | |||
| export default CreateProductMaterial; | |||
| export default CreateItem; | |||
| @@ -5,7 +5,7 @@ import Stack from "@mui/material/Stack"; | |||
| import React from "react"; | |||
| // Can make this nicer | |||
| export const CreateProductMaterialLoading: React.FC = () => { | |||
| export const CreateItemLoading: React.FC = () => { | |||
| return ( | |||
| <> | |||
| <Card> | |||
| @@ -37,4 +37,4 @@ export const CreateProductMaterialLoading: React.FC = () => { | |||
| ); | |||
| }; | |||
| export default CreateProductMaterialLoading; | |||
| export default CreateItemLoading; | |||
| @@ -0,0 +1,53 @@ | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import CreateItem from "./CreateItem"; | |||
| import CreateItemLoading from "./CreateItemLoading"; | |||
| import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
| import { notFound } from "next/navigation"; | |||
| import { fetchItem } from "@/app/api/settings/item"; | |||
| interface SubComponents { | |||
| Loading: typeof CreateItemLoading; | |||
| } | |||
| type Props = { | |||
| id?: number | |||
| type: TypeEnum; | |||
| }; | |||
| const CreateItemWrapper: React.FC<Props> & | |||
| SubComponents = async ({ type, id }) => { | |||
| var result | |||
| var defaultValues: Partial<CreateItemInputs> | undefined | |||
| console.log(type) | |||
| if (id) { | |||
| result = await fetchItem(id); | |||
| console.log(result) | |||
| defaultValues = { | |||
| typeId: result?.type.id, | |||
| id: result?.id, | |||
| code: result?.code, | |||
| name: result?.name, | |||
| description: result?.description, | |||
| remarks: result?.remarks, | |||
| shelfLife: result?.shelfLife, | |||
| countryOfOrigin: result?.countryOfOrigin, | |||
| minHumid: result?.minHumid, | |||
| maxHumid: result?.maxHumid, | |||
| minTemp: result?.minTemp, | |||
| maxTemp: result?.maxTemp, | |||
| sampleRate: result?.sampleRate, | |||
| passingRate: result?.passingRate, | |||
| netWeight: result?.netWeight | |||
| }; | |||
| } | |||
| return ( | |||
| <CreateItem | |||
| isEditMode={Boolean(id)} | |||
| type={type} | |||
| defaultValues={defaultValues} | |||
| /> | |||
| ); | |||
| }; | |||
| CreateItemWrapper.Loading = CreateItemLoading; | |||
| export default CreateItemWrapper; | |||
| @@ -1,5 +1,5 @@ | |||
| "use client"; | |||
| import { CreateMaterialInputs } from "@/app/api/settings/material/actions"; | |||
| import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
| import { | |||
| Box, | |||
| Card, | |||
| @@ -31,7 +31,7 @@ type Props = { | |||
| export type EntryError = | |||
| | { | |||
| [field in keyof CreateMaterialInputs]?: string; | |||
| [field in keyof CreateItemInputs]?: string; | |||
| } | |||
| | undefined; | |||
| @@ -52,8 +52,9 @@ const MaterialDetails: React.FC<Props> = ({}) => { | |||
| resetField, | |||
| setError, | |||
| clearErrors, | |||
| } = useFormContext<CreateMaterialInputs>(); | |||
| } = useFormContext<CreateItemInputs>(); | |||
| // textfield error msg locale problem | |||
| console.log(defaultValues) | |||
| const typeColumns = useMemo<GridColDef[]>( | |||
| () => [ | |||
| { | |||
| @@ -97,7 +98,7 @@ const MaterialDetails: React.FC<Props> = ({}) => { | |||
| const validationTest = useCallback( | |||
| ( | |||
| newRow: GridRowModel<TableRow<Partial<CreateMaterialInputs>, EntryError>> | |||
| newRow: GridRowModel<TableRow<Partial<CreateItemInputs>, EntryError>> | |||
| ): EntryError => { | |||
| const error: EntryError = {}; | |||
| console.log(newRow); | |||
| @@ -117,15 +118,20 @@ const MaterialDetails: React.FC<Props> = ({}) => { | |||
| <FormControlLabel | |||
| control={ | |||
| <Controller | |||
| name={"isConsumables"} | |||
| name={"typeId"} | |||
| control={control} | |||
| render={({ field: props }) => ( | |||
| render={({ field: props }) => { | |||
| console.log(props) | |||
| return ( | |||
| <Checkbox | |||
| {...props} | |||
| checked={props.value} | |||
| onChange={(e) => props.onChange(e.target.checked)} | |||
| checked={props.value === TypeEnum.CONSUMABLE_ID} | |||
| onChange={(e) => { | |||
| const newValue = e.target.checked ? TypeEnum.CONSUMABLE_ID : TypeEnum.MATERIAL_ID; | |||
| props.onChange(newValue); | |||
| }} | |||
| /> | |||
| )} | |||
| )}} | |||
| /> | |||
| } | |||
| label={ | |||
| @@ -310,27 +316,6 @@ const MaterialDetails: React.FC<Props> = ({}) => { | |||
| helperText={errors.netWeight?.message} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <InputDataGrid<CreateMaterialInputs, EntryError> | |||
| _formKey={"type"} | |||
| columns={typeColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <InputDataGrid<CreateMaterialInputs, EntryError> | |||
| _formKey={"uom"} | |||
| columns={uomColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={12}> | |||
| <InputDataGrid<CreateMaterialInputs, EntryError> | |||
| _formKey={"weightUnit"} | |||
| columns={weightUnitColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| </Grid> | |||
| </Box> | |||
| </CardContent> | |||
| @@ -1,5 +1,4 @@ | |||
| "use client"; | |||
| import { CreateMaterialInputs } from "@/app/api/settings/material/actions"; | |||
| import { | |||
| Box, | |||
| Card, | |||
| @@ -16,8 +15,8 @@ import { useCallback, useMemo, useState } from "react"; | |||
| import { GridColDef, GridRowModel } from "@mui/x-data-grid"; | |||
| import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import { CreateProductInputs } from "@/app/api/settings/product/actions"; | |||
| import { NumberInputProps } from "./NumberInputProps"; | |||
| import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
| type Props = { | |||
| // isEditMode: boolean; | |||
| @@ -26,7 +25,7 @@ type Props = { | |||
| export type EntryError = | |||
| | { | |||
| [field in keyof CreateProductInputs]?: string; | |||
| [field in keyof CreateItemInputs]?: string; | |||
| } | |||
| | undefined; | |||
| @@ -49,7 +48,7 @@ const ProductDetails: React.FC<Props> = ({ | |||
| resetField, | |||
| setError, | |||
| clearErrors, | |||
| } = useFormContext<CreateProductInputs>(); | |||
| } = useFormContext<CreateItemInputs>(); | |||
| const typeColumns = useMemo<GridColDef[]>( | |||
| () => [ | |||
| { | |||
| @@ -93,7 +92,7 @@ const ProductDetails: React.FC<Props> = ({ | |||
| const validationTest = useCallback( | |||
| ( | |||
| newRow: GridRowModel<TableRow<Partial<CreateProductInputs>, EntryError>> | |||
| newRow: GridRowModel<TableRow<Partial<CreateItemInputs>, EntryError>> | |||
| ): EntryError => { | |||
| const error: EntryError = {}; | |||
| console.log(newRow); | |||
| @@ -276,28 +275,28 @@ const ProductDetails: React.FC<Props> = ({ | |||
| helperText={errors.netWeight?.message} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <InputDataGrid<CreateProductInputs, EntryError> | |||
| {/* <Grid item xs={6}> | |||
| <InputDataGrid<CreateItemInputs, EntryError> | |||
| _formKey={"type"} | |||
| columns={typeColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <InputDataGrid<CreateProductInputs, EntryError> | |||
| <InputDataGrid<CreateItemInputs, EntryError> | |||
| _formKey={"uom"} | |||
| columns={uomColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={12}> | |||
| <InputDataGrid<CreateProductInputs, EntryError> | |||
| <InputDataGrid<CreateItemInputs, EntryError> | |||
| _formKey={"weightUnit"} | |||
| columns={weightUnitColumns} | |||
| validateRow={validationTest} | |||
| /> | |||
| </Grid> | |||
| </Grid> | |||
| </Grid>*/} | |||
| </Grid> | |||
| </Box> | |||
| </CardContent> | |||
| </Card> | |||
| @@ -0,0 +1 @@ | |||
| export { default } from "./CreateItemWrapper"; | |||
| @@ -1,67 +0,0 @@ | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import CreateProductMaterial from "./CreateProductMaterial"; | |||
| import CreateMaterialLoading from "./CreateProductMaterialLoading"; | |||
| import { CreateMaterialInputs } from "@/app/api/settings/material/actions"; | |||
| import { CreateProductInputs } from "@/app/api/settings/product/actions"; | |||
| import { fetchMaterial } from "@/app/api/settings/material"; | |||
| import { fetchProduct } from "@/app/api/settings/product"; | |||
| import { fetchByProduct } from "@/app/api/settings/byProduct"; | |||
| import { notFound } from "next/navigation"; | |||
| import { CreateByProductInputs } from "@/app/api/settings/byProduct/actions"; | |||
| interface SubComponents { | |||
| Loading: typeof CreateMaterialLoading; | |||
| } | |||
| type Props = { | |||
| id?: number | |||
| type: TypeEnum; | |||
| }; | |||
| export type CreateInputsFields = CreateMaterialInputs | CreateProductInputs | CreateByProductInputs; | |||
| const CreateProductMaterialWrapper: React.FC<Props> & | |||
| SubComponents = async ({ type, id }) => { | |||
| var defaultValues: Partial<CreateInputsFields> = {}; | |||
| var result | |||
| if (id && type === TypeEnum.MATERIAL) { | |||
| result = await fetchMaterial(id); | |||
| defaultValues = { | |||
| isConsumables: result.isConsumables | |||
| } | |||
| } else if (id && type === TypeEnum.PRODUCT) { | |||
| result = await fetchProduct(id); | |||
| } else if (id && type === TypeEnum.BYPRODUCT) { | |||
| result = await fetchByProduct(id); | |||
| } | |||
| defaultValues = { | |||
| ...defaultValues, | |||
| id: result?.id, | |||
| code: result?.code, | |||
| name: result?.name, | |||
| description: result?.description, | |||
| type: result?.type, | |||
| remarks: result?.remarks, | |||
| shelfLife: result?.shelfLife, | |||
| countryOfOrigin: result?.countryOfOrigin, | |||
| minHumid: result?.minHumid, | |||
| maxHumid: result?.maxHumid, | |||
| minTemp: result?.minTemp, | |||
| maxTemp: result?.maxTemp, | |||
| sampleRate: result?.sampleRate, | |||
| passingRate: result?.passingRate, | |||
| netWeight: result?.netWeight, | |||
| uom: result?.uom, | |||
| weightUnit: result?.weightUnit, | |||
| }; | |||
| return ( | |||
| <CreateProductMaterial | |||
| isEditMode={Boolean(id)} | |||
| type={type} | |||
| defaultValues={defaultValues} | |||
| /> | |||
| ); | |||
| }; | |||
| CreateProductMaterialWrapper.Loading = CreateMaterialLoading; | |||
| export default CreateProductMaterialWrapper; | |||
| @@ -1 +0,0 @@ | |||
| export { default } from "./CreateProductMaterialWrapper"; | |||
| @@ -151,7 +151,7 @@ function InputDataGrid<T, E>({ | |||
| const reset = useCallback(() => { | |||
| setRowModesModel({}) | |||
| setRows([]) | |||
| setRows(originalRows) | |||
| }, []); | |||
| const handleCancel = useCallback( | |||
| @@ -239,7 +239,7 @@ function InputDataGrid<T, E>({ | |||
| <Button | |||
| disableRipple | |||
| variant="outlined" | |||
| startIcon={<Add />} | |||
| startIcon={<Add />} | |||
| onClick={addRow} | |||
| size="small" | |||
| > | |||
| @@ -2,26 +2,24 @@ | |||
| import { useCallback, useMemo, useState } from "react"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import { MaterialResult } from "@/app/api/settings/material"; | |||
| import { ItemsResult } from "@/app/api/settings/item"; | |||
| 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"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import { ProductResult } from "@/app/api/settings/product"; | |||
| export type ListResult = MaterialResult | ProductResult; | |||
| type Props = { | |||
| productMaterial: ListResult[]; | |||
| items: ItemsResult[]; | |||
| type: TypeEnum; | |||
| }; | |||
| type SearchQuery = Partial<Omit<ListResult, "id">>; | |||
| type SearchQuery = Partial<Omit<ItemsResult, "id">>; | |||
| type SearchParamNames = keyof SearchQuery; | |||
| const MaterialSearch: React.FC<Props> = ({ productMaterial, type }) => { | |||
| const [filteredItems, setFilteredItems] = useState<ListResult[]>(productMaterial); | |||
| const { t } = useTranslation(type); | |||
| const ItemsSearch: React.FC<Props> = ({ items, type }) => { | |||
| const [filteredItems, setFilteredItems] = useState<ItemsResult[]>(items); | |||
| const { t } = useTranslation(type.toString()); | |||
| const router = useRouter(); | |||
| const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | |||
| @@ -38,22 +36,22 @@ const MaterialSearch: React.FC<Props> = ({ productMaterial, type }) => { | |||
| } | |||
| return searchCriteria | |||
| }, | |||
| [t, productMaterial] | |||
| [t, items] | |||
| ); | |||
| const onDetailClick = useCallback( | |||
| (productMaterial: ListResult) => { | |||
| router.push(`/settings/${type}/edit?id=${productMaterial.id}`); | |||
| (item: ItemsResult) => { | |||
| router.push(`/settings/${type}/edit?id=${item.id}`); | |||
| }, | |||
| [type, router] | |||
| ); | |||
| const onDeleteClick = useCallback( | |||
| (productMaterial: ListResult) => {}, | |||
| (item: ItemsResult) => {}, | |||
| [router] | |||
| ); | |||
| const columns = useMemo<Column<ListResult>[]>( | |||
| const columns = useMemo<Column<ItemsResult>[]>( | |||
| () => [ | |||
| { | |||
| name: "id", | |||
| @@ -80,8 +78,8 @@ const MaterialSearch: React.FC<Props> = ({ productMaterial, type }) => { | |||
| ); | |||
| const onReset = useCallback(() => { | |||
| setFilteredItems(productMaterial); | |||
| }, [productMaterial]); | |||
| setFilteredItems(items); | |||
| }, [items]); | |||
| return ( | |||
| <> | |||
| @@ -89,7 +87,7 @@ const MaterialSearch: React.FC<Props> = ({ productMaterial, type }) => { | |||
| criteria={searchCriteria} | |||
| onSearch={(query) => { | |||
| setFilteredItems( | |||
| productMaterial.filter((pm) => { | |||
| items.filter((pm) => { | |||
| if (type === TypeEnum.MATERIAL) { | |||
| return ( | |||
| pm.code.toLowerCase().includes(query.code.toLowerCase()) && | |||
| @@ -111,9 +109,9 @@ const MaterialSearch: React.FC<Props> = ({ productMaterial, type }) => { | |||
| }} | |||
| onReset={onReset} | |||
| /> | |||
| <SearchResults<ListResult> items={filteredItems} columns={columns} /> | |||
| <SearchResults<ItemsResult> items={filteredItems} columns={columns} /> | |||
| </> | |||
| ); | |||
| }; | |||
| export default MaterialSearch; | |||
| export default ItemsSearch; | |||
| @@ -5,7 +5,7 @@ import Stack from "@mui/material/Stack"; | |||
| import React from "react"; | |||
| // Can make this nicer | |||
| export const ProductMaterialSearchLoading: React.FC = () => { | |||
| export const ItemsSearchLoading: React.FC = () => { | |||
| return ( | |||
| <> | |||
| <Card> | |||
| @@ -37,4 +37,4 @@ export const ProductMaterialSearchLoading: React.FC = () => { | |||
| ); | |||
| }; | |||
| export default ProductMaterialSearchLoading; | |||
| export default ItemsSearchLoading; | |||
| @@ -0,0 +1,26 @@ | |||
| import { fetchAllItems, } from "@/app/api/settings/item"; | |||
| import ItemsSearch from "./ItemsSearch"; | |||
| import ItemsSearchLoading from "./ItemsSearchLoading"; | |||
| import { SearchParams } from "@/app/utils/fetchUtil"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import { notFound } from "next/navigation"; | |||
| interface SubComponents { | |||
| Loading: typeof ItemsSearchLoading; | |||
| } | |||
| type Props = { | |||
| type: TypeEnum; | |||
| }; | |||
| const ItemsSearchWrapper: React.FC<Props> & SubComponents = async ({ | |||
| type, | |||
| }) => { | |||
| console.log(type) | |||
| var result = await fetchAllItems() | |||
| return <ItemsSearch items={result} type={type} />; | |||
| }; | |||
| ItemsSearchWrapper.Loading = ItemsSearchLoading; | |||
| export default ItemsSearchWrapper; | |||
| @@ -0,0 +1 @@ | |||
| export { default } from "./ItemsSearchWrapper"; | |||
| @@ -1,35 +0,0 @@ | |||
| import { fetchAllMaterials, MaterialResult } from "@/app/api/settings/material"; | |||
| import ProductMaterialSearch, { ListResult } from "./ProductMaterialSearch"; | |||
| import MaterialSearchLoading from "./ProductMaterialSearchLoading"; | |||
| import { SearchParams } from "@/app/utils/fetchUtil"; | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import { notFound } from "next/navigation"; | |||
| interface SubComponents { | |||
| Loading: typeof MaterialSearchLoading; | |||
| } | |||
| type Props = { | |||
| type: TypeEnum; | |||
| }; | |||
| const ProductMaterialSearchWrapper: React.FC<Props> & SubComponents = async ({ | |||
| type, | |||
| }) => { | |||
| var result: ListResult[] = []; | |||
| if (TypeEnum.PRODUCT === type) { | |||
| result = []; | |||
| } else if (TypeEnum.MATERIAL === type) { | |||
| result = await fetchAllMaterials(); | |||
| } else if (TypeEnum.BYPRODUCT === type) { | |||
| result = []; | |||
| } else { | |||
| notFound(); | |||
| } | |||
| return <ProductMaterialSearch productMaterial={result} type={type} />; | |||
| }; | |||
| ProductMaterialSearchWrapper.Loading = MaterialSearchLoading; | |||
| export default ProductMaterialSearchWrapper; | |||
| @@ -1 +0,0 @@ | |||
| export { default } from "./ProductMaterialSearchWrapper"; | |||