diff --git a/src/app/(main)/settings/byProduct/create/page.tsx b/src/app/(main)/settings/byProduct/create/page.tsx deleted file mode 100644 index 37072c0..0000000 --- a/src/app/(main)/settings/byProduct/create/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { SearchParams } from "@/app/utils/fetchUtil"; -import { TypeEnum } from "@/app/utils/typeEnum"; -import CreateProductMaterial from "@/components/CreateItem"; -import { I18nProvider, getServerI18n } from "@/i18n"; -import { Typography } from "@mui/material"; -import { isString } from "lodash"; - -type Props = {} & SearchParams; - -const byProductSetting: React.FC = async ({ searchParams }) => { - const type = TypeEnum.BYPRODUCT; - const { t } = await getServerI18n(type); - console.log(searchParams); - - return ( - <> - {/* {t("Create Material")} */} - - - - - ); -}; -export default byProductSetting; diff --git a/src/app/(main)/settings/byProduct/edit/page.tsx b/src/app/(main)/settings/byProduct/edit/page.tsx deleted file mode 100644 index 2768e3d..0000000 --- a/src/app/(main)/settings/byProduct/edit/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { SearchParams } from "@/app/utils/fetchUtil"; -import { TypeEnum } from "@/app/utils/typeEnum"; -import CreateProductMaterial from "@/components/CreateItem"; -import { I18nProvider, getServerI18n } from "@/i18n"; -import { Typography } from "@mui/material"; -import { isString } from "lodash"; - -type Props = {} & SearchParams; - -const byProductSetting: React.FC = async ({ searchParams }) => { - const type = TypeEnum.BYPRODUCT; - const { t } = await getServerI18n(type); - console.log(searchParams); - - return ( - <> - {/* {t("Create Material")} */} - - - - - ); -}; -export default byProductSetting; diff --git a/src/app/(main)/settings/byProduct/page.tsx b/src/app/(main)/settings/byProduct/page.tsx deleted file mode 100644 index ab2c01a..0000000 --- a/src/app/(main)/settings/byProduct/page.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { TypeEnum } from "@/app/utils/typeEnum"; -import MaterialSearch from "@/components/ItemsSearch"; -import { getServerI18n } from "@/i18n"; -import Add from "@mui/icons-material/Add"; -import Button from "@mui/material/Button"; -import Stack from "@mui/material/Stack"; -import Typography from "@mui/material/Typography"; -import { Metadata } from "next"; -import Link from "next/link"; -import { Suspense } from "react"; - -export const metadata: Metadata = { - title: "ByProduct", -}; - -const materialSetting: React.FC = async () => { - const byProduct = TypeEnum.BYPRODUCT - const { t } = await getServerI18n(byProduct); - // preloadClaims(); - - return ( - <> - - - {t("ByProduct")} - - - - }> - - - - ); -}; - -export default materialSetting; diff --git a/src/app/(main)/settings/product/create/page.tsx b/src/app/(main)/settings/items/create/page.tsx similarity index 69% rename from src/app/(main)/settings/product/create/page.tsx rename to src/app/(main)/settings/items/create/page.tsx index dd6248f..5b1e314 100644 --- a/src/app/(main)/settings/product/create/page.tsx +++ b/src/app/(main)/settings/items/create/page.tsx @@ -1,6 +1,6 @@ import { SearchParams } from "@/app/utils/fetchUtil"; import { TypeEnum } from "@/app/utils/typeEnum"; -import CreateProductMaterial from "@/components/CreateItem"; +import CreateItem from "@/components/CreateItem"; import { I18nProvider, getServerI18n } from "@/i18n"; import { Typography } from "@mui/material"; import isString from "lodash/isString"; @@ -8,13 +8,13 @@ import isString from "lodash/isString"; type Props = {} & SearchParams; const materialSetting: React.FC = async ({ searchParams }) => { - const type = TypeEnum.PRODUCT; - const { t } = await getServerI18n(type); + // const type = TypeEnum.PRODUCT; + const { t } = await getServerI18n("items"); return ( <> {/* {t("Create Material")} */} - - + + ); diff --git a/src/app/(main)/settings/product/edit/page.tsx b/src/app/(main)/settings/items/edit/page.tsx similarity index 90% rename from src/app/(main)/settings/product/edit/page.tsx rename to src/app/(main)/settings/items/edit/page.tsx index 04cd5c1..9e2f936 100644 --- a/src/app/(main)/settings/product/edit/page.tsx +++ b/src/app/(main)/settings/items/edit/page.tsx @@ -9,7 +9,7 @@ import { notFound } from "next/navigation"; type Props = {} & SearchParams; const productSetting: React.FC = async ({ searchParams }) => { - const type = TypeEnum.PRODUCT; + const type = "items"; const { t } = await getServerI18n(type); const id = isString(searchParams["id"]) ? parseInt(searchParams["id"]) @@ -21,7 +21,7 @@ const productSetting: React.FC = async ({ searchParams }) => { <> {/* {t("Create Material")} */} - + ); diff --git a/src/app/(main)/settings/product/page.tsx b/src/app/(main)/settings/items/page.tsx similarity index 85% rename from src/app/(main)/settings/product/page.tsx rename to src/app/(main)/settings/items/page.tsx index 0fa4c0b..205cf4f 100644 --- a/src/app/(main)/settings/product/page.tsx +++ b/src/app/(main)/settings/items/page.tsx @@ -1,5 +1,5 @@ import { TypeEnum } from "@/app/utils/typeEnum"; -import MaterialSearch from "@/components/ItemsSearch"; +import ItemsSearch from "@/components/ItemsSearch"; import { getServerI18n } from "@/i18n"; import Add from "@mui/icons-material/Add"; import Button from "@mui/material/Button"; @@ -29,17 +29,17 @@ const productSetting: React.FC = async () => { {t("Product")} - + */} - }> - + }> + ); diff --git a/src/app/(main)/settings/material/create/page.tsx b/src/app/(main)/settings/material/create/page.tsx deleted file mode 100644 index 94ada52..0000000 --- a/src/app/(main)/settings/material/create/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { SearchParams } from "@/app/utils/fetchUtil"; -import { TypeEnum } from "@/app/utils/typeEnum"; -import CreateProductMaterial from "@/components/CreateItem"; -import { I18nProvider, getServerI18n } from "@/i18n"; -import { Typography } from "@mui/material"; -import { isString } from "lodash"; - -type Props = {} & SearchParams; - -const materialSetting: React.FC = async ({ searchParams }) => { - const type = TypeEnum.MATERIAL; - const { t } = await getServerI18n(type); - console.log(searchParams); - - return ( - <> - {/* {t("Create Material")} */} - - - - - ); -}; -export default materialSetting; diff --git a/src/app/(main)/settings/material/edit/page.tsx b/src/app/(main)/settings/material/edit/page.tsx deleted file mode 100644 index 8dc83a2..0000000 --- a/src/app/(main)/settings/material/edit/page.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { SearchParams } from "@/app/utils/fetchUtil"; -import { TypeEnum } from "@/app/utils/typeEnum"; -import CreateProductMaterial from "@/components/CreateItem"; -import { I18nProvider, getServerI18n } from "@/i18n"; -import { Typography } from "@mui/material"; -import { isString } from "lodash"; -import { notFound } from "next/navigation"; - -type Props = {} & SearchParams; - -const materialSetting: React.FC = async ({ searchParams }) => { - const type = TypeEnum.MATERIAL; - const { t } = await getServerI18n(type); - console.log(searchParams); - const id = isString(searchParams["id"]) - ? parseInt(searchParams["id"]) - : undefined; - console.log(id) - if (!id) { - notFound(); - } - return ( - <> - {/* {t("Create Material")} */} - - - - - ); -}; -export default materialSetting; diff --git a/src/app/(main)/settings/material/page.tsx b/src/app/(main)/settings/material/page.tsx deleted file mode 100644 index 2f1e8bb..0000000 --- a/src/app/(main)/settings/material/page.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { TypeEnum } from "@/app/utils/typeEnum"; -import MaterialSearch from "@/components/ItemsSearch"; -import { getServerI18n } from "@/i18n"; -import Add from "@mui/icons-material/Add"; -import Button from "@mui/material/Button"; -import Stack from "@mui/material/Stack"; -import Typography from "@mui/material/Typography"; -import { Metadata } from "next"; -import Link from "next/link"; -import { Suspense } from "react"; - -export const metadata: Metadata = { - title: "Material", -}; - -const materialSetting: React.FC = async () => { - const material = TypeEnum.MATERIAL - const { t } = await getServerI18n("material"); - // preloadClaims(); - - return ( - <> - - - {t("Material")} - - - - }> - - - - ); -}; - -export default materialSetting; diff --git a/src/app/api/settings/item/actions.ts b/src/app/api/settings/item/actions.ts index 467f516..8449009 100644 --- a/src/app/api/settings/item/actions.ts +++ b/src/app/api/settings/item/actions.ts @@ -2,20 +2,23 @@ import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; import { revalidateTag } from "next/cache"; import { BASE_API_URL } from "@/config/api"; -import { HTMLInputTypeAttribute } from "react"; import { CreateItemResponse } from "../../utils"; +import { ItemQc } from "."; +import { QcChecksInputs } from "../qcCheck/actions"; + +// export type TypeInputs = { +// id: number; +// name: string +// } +// export type UomInputs = { +// uom: string +// } +// export type WeightUnitInputs = { +// weightUnit: string +// conversion: number +// } + -export type TypeInputs = { - id: number; - name: string -} -export type UomInputs = { - uom: string -} -export type WeightUnitInputs = { - weightUnit: string - conversion: number -} export type CreateItemInputs = { id?: string | number code: string; @@ -24,14 +27,10 @@ export type CreateItemInputs = { 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; - typeId: number; + maxQty: number; + type: string; + qcChecks: QcChecksInputs[] + qcChecks_active: number[] } export const saveItem = async (data: CreateItemInputs) => { @@ -43,4 +42,4 @@ export const saveItem = async (data: CreateItemInputs) => { }); revalidateTag("items"); return item - }; + }; \ No newline at end of file diff --git a/src/app/api/settings/item/index.ts b/src/app/api/settings/item/index.ts index a346ec5..a51bc92 100644 --- a/src/app/api/settings/item/index.ts +++ b/src/app/api/settings/item/index.ts @@ -2,7 +2,18 @@ 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 "./actions"; +// import { TypeInputs, UomInputs, WeightUnitInputs } from "./actions"; + +export type ItemQc = { + id: number; // id = qc_check # + name: string; + code: string; + description: string | undefined; + instruction: string | undefined; + lowerLimit: number | undefined; + upperLimit: number | undefined; + isActive: boolean | undefined; +} export type ItemsResult = { id: string | number @@ -12,20 +23,15 @@ export type ItemsResult = { 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; + maxQty: number | undefined; + type: string; + qcChecks: ItemQc[] action?: any } - - +export type Result = { + item: ItemsResult + qcChecks: ItemQc[] +} export const fetchAllItems = cache(async () => { return serverFetchJson(`${BASE_API_URL}/items`, { next: { tags: ["items"] }, @@ -34,7 +40,7 @@ export const fetchAllItems = cache(async () => { export const fetchItem = cache(async (id: number) => { - return serverFetchJson(`${BASE_API_URL}/items/details/${id}`, { + return serverFetchJson(`${BASE_API_URL}/items/details/${id}`, { next: { tags: ["items"] }, }); }); \ No newline at end of file diff --git a/src/app/api/settings/qcCheck/actions.ts b/src/app/api/settings/qcCheck/actions.ts new file mode 100644 index 0000000..98133ef --- /dev/null +++ b/src/app/api/settings/qcCheck/actions.ts @@ -0,0 +1,22 @@ +"use server"; +import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; +import { revalidateTag } from "next/cache"; +import { BASE_API_URL } from "@/config/api"; +import { CreateItemResponse } from "../../utils"; +import { ItemQc } from "../item"; + +export type QcChecksInputs = { + +} & Partial + + +export const saveItemQcChecks = async (data: QcChecksInputs[]) => { + // try { + const res = await serverFetchJson>(`${BASE_API_URL}/qcCheck/new`, { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); + revalidateTag("items"); + return res + }; \ No newline at end of file diff --git a/src/app/utils/fetchUtil.ts b/src/app/utils/fetchUtil.ts index 8034c63..227d858 100644 --- a/src/app/utils/fetchUtil.ts +++ b/src/app/utils/fetchUtil.ts @@ -56,6 +56,7 @@ type FetchParams = Parameters; export async function serverFetchJson(...args: FetchParams) { const response = await serverFetch(...args); + console.log(response.status) if (response.ok) { if (response.status === 204) { return response.status as T diff --git a/src/components/CreateItem/ByProductDetails.tsx b/src/components/CreateItem/ByProductDetails.tsx deleted file mode 100644 index be48d5b..0000000 --- a/src/components/CreateItem/ByProductDetails.tsx +++ /dev/null @@ -1,294 +0,0 @@ -"use client"; -import { CreateItemInputs } from "@/app/api/settings/item/actions"; -import { - Box, - Card, - CardContent, - Grid, - Stack, - TextField, - Typography, -} from "@mui/material"; -import { useFormContext } from "react-hook-form"; -import { useTranslation } from "react-i18next"; -import InputDataGrid from "../InputDataGrid"; -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 { NumberInputProps } from "./NumberInputProps"; - -type Props = { - // isEditMode: boolean; - // type: TypeEnum; -}; - -export type EntryError = - | { - [field in keyof CreateItemInputs]?: string; - } - | undefined; - -const ByProductDetails: React.FC = ({}) => { - const { - t, - i18n: { language }, - } = useTranslation(); - - const { - register, - formState: { errors, defaultValues, touchedFields }, - watch, - control, - setValue, - getValues, - reset, - resetField, - setError, - clearErrors, - } = useFormContext(); - const typeColumns = useMemo( - () => [ - { - field: "type", - headerName: "type", - flex: 1, - editable: true, - }, - ], - [] - ); - const weightUnitColumns = useMemo( - () => [ - { - field: "weightUnit", - headerName: "Weight Unit", - flex: 1, - editable: true, - }, - { - field: "conversion", - headerName: "conversion", // show base unit - flex: 1, - type: "number", - editable: true, - }, - ], - [] - ); - const uomColumns = useMemo( - () => [ - { - field: "uom", - headerName: "uom", - flex: 1, - editable: true, - }, - ], - [] - ); - - const validationTest = useCallback( - ( - newRow: GridRowModel, EntryError>> - ): EntryError => { - const error: EntryError = {}; - console.log(newRow); - return Object.keys(error).length > 0 ? error : undefined; - }, - [] - ); - - const validateUom = useCallback( - ( - newRow: GridRowModel, 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 ( - - - - - {t("Product Details")} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; -export default ByProductDetails; diff --git a/src/components/CreateItem/CreateItem.tsx b/src/components/CreateItem/CreateItem.tsx index bc7689e..ff8d1ea 100644 --- a/src/components/CreateItem/CreateItem.tsx +++ b/src/components/CreateItem/CreateItem.tsx @@ -14,140 +14,126 @@ import { useForm, } from "react-hook-form"; import { deleteDialog } from "../Swal/CustomAlerts"; -import { Box, Button, Grid, Stack, Typography } from "@mui/material"; +import { Box, Button, Grid, Stack, Tab, Tabs, TabsProps, Typography } from "@mui/material"; import { Check, Close, EditNote } from "@mui/icons-material"; import { TypeEnum } from "@/app/utils/typeEnum"; -import MaterialDetails from "./MaterialDetails"; import ProductDetails from "./ProductDetails"; import { CreateItemResponse } from "@/app/api/utils"; -import ByProductDetails from "./ByProductDetails"; +import QcDetails from "./QcDetails"; +import { ItemQc } from "@/app/api/settings/item"; +import { saveItemQcChecks } from "@/app/api/settings/qcCheck/actions"; +import { useGridApiRef } from "@mui/x-data-grid"; type Props = { isEditMode: boolean; - type: TypeEnum; + // type: TypeEnum; defaultValues: Partial | undefined; + qcChecks: ItemQc[] }; const CreateItem: React.FC = ({ isEditMode, - type, + // type, defaultValues, + qcChecks }) => { - console.log(type) + // console.log(type) + const apiRef = useGridApiRef(); + const params = useSearchParams() + console.log(params.get("id")) const [serverError, setServerError] = useState(""); const [tabIndex, setTabIndex] = useState(0); const { t } = useTranslation(); const router = useRouter(); - const [typeId, title, mode, redirPath] = useMemo(() => { - var typeId = TypeEnum.CONSUMABLE_ID + const title = "Product / Material" + const [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 = "/settings/material"; - } - if (type === TypeEnum.PRODUCT) { - typeId = TypeEnum.PRODUCT_ID + // if (type === TypeEnum.MATERIAL) { + // typeId = TypeEnum.MATERIAL_ID + // title = "Material"; + // redirPath = "/settings/material"; + // } + // if (type === TypeEnum.PRODUCT) { + // typeId = TypeEnum.PRODUCT_ID title = "Product"; - redirPath = "/settings/product"; - } - if (type === TypeEnum.BYPRODUCT) { - typeId = TypeEnum.BYPRODUCT_ID - title = "By-Product"; - redirPath = "/settings/byProduct"; - } + redirPath = "/settings/items"; + // } + // if (type === TypeEnum.BYPRODUCT) { + // typeId = TypeEnum.BYPRODUCT_ID + // title = "By-Product"; + // redirPath = "/settings/byProduct"; + // } if (isEditMode) { mode = "Edit"; } else { mode = "Create"; } - return [typeId, title, mode, redirPath]; - }, [type, isEditMode]); - console.log(typeId) + return [mode, redirPath]; + }, [isEditMode]); + // console.log(typeId) const formProps = useForm({ defaultValues: defaultValues ? defaultValues : { - typeId: typeId }, }); const errors = formProps.formState.errors; + const handleTabChange = useCallback>( + (_e, newValue) => { + setTabIndex(newValue); + }, + [], + ); + const handleCancel = () => { - router.replace(`/settings/${type}`); + router.replace(`/settings/product`); }; - const onSubmit = useCallback>( + const onSubmit = useCallback>( async (data, event) => { let hasErrors = false; - console.log("dasasdasd") + console.log(errors) + // console.log(apiRef.current.getCellValue(2, "lowerLimit")) + // apiRef.current. try { - // checking humid input - if (data.maxHumid && data.minHumid!! > data.maxHumid!!) { - const message = "minHumid should not be greater than maxHumid"; - formProps.setError("minHumid", { - message: message, - type: "required", - }); - formProps.setError("maxHumid", { - message: message, - type: "required", - }); - hasErrors = true; - } - // checking temp input - if (data.maxTemp && data.minTemp!! > data.maxTemp!!) { - const message = "minTemp should not be greater than maxTemp"; - formProps.setError("minTemp", { - message: message, - type: "required", - }); - formProps.setError("maxTemp", { - message: message, - type: "required", - }); - hasErrors = true; - } - // checking temp input - if (data.netWeight && data.netWeight < 0) { - const message = "netWeight should not be greater than 0"; - formProps.setError("netWeight", { - message: message, - type: "required", - }); - } - // checking passing rate - if (data.passingRate && (data.passingRate < 0 || data.passingRate > 100)) { - const message = "passingRate should not be greater than 100%"; - formProps.setError("passingRate", { - message: message, - type: "required", - }); - } - // checking sampling rate - if (data.sampleRate && (data.sampleRate < 0 || data.sampleRate > 100)) { - const message = "sampleRate should not be greater than 100%"; - formProps.setError("sampleRate", { - message: message, - type: "required", - }); - } if (hasErrors) { setServerError(t("An error has occurred. Please try again later.")); return false; } console.log("data posted"); console.log(data); + const qcCheck = data.qcChecks.length > 0 ? data.qcChecks.filter((q) => data.qcChecks_active.includes(q.id!!)).map((qc) => { + return { + qcItemId: qc.id, + instruction: qc.instruction, + lowerLimit: qc.lowerLimit, + upperLimit: qc.upperLimit, + itemId: parseInt(params.get("id")!.toString()) + } + }) : [] + const test = data.qcChecks.filter((q) => data.qcChecks_active.includes(q.id!!)) + // TODO: + // 1. check field ( directly modify col def / check here ) + // 2. set error change tab index + console.log(test) + console.log(qcCheck) // return // do api - var response = await saveItem(data); - if (response) { - if (!Boolean(response.id)) { - formProps.setError(response.errorPosition!! as keyof CreateItemInputs, { - message: response.message!!, + console.log("asdad") + var responseI = await saveItem(data); + console.log("asdad") + var responseQ = await saveItemQcChecks(qcCheck) + if (responseI && responseQ) { + if (!Boolean(responseI.id)) { + formProps.setError(responseI.errorPosition!! as keyof CreateItemInputs, { + message: responseI.message!!, type: "required", }); - } else if (Boolean(response.id)) { + } else if (!Boolean(responseQ.id)) { + + } else if (Boolean(responseI.id) && Boolean(responseQ.id)) { router.replace(redirPath); } } @@ -157,7 +143,7 @@ const CreateItem: React.FC = ({ console.log(e); } }, - [router, t] + [apiRef, router, t] ); // multiple tabs @@ -174,19 +160,24 @@ const CreateItem: React.FC = ({ component="form" onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)} > - - - {t(`${mode} ${title}`)} - - + + + {t(`${mode} ${title}`)} + + + + + + {serverError && ( {serverError} )} - {type === TypeEnum.MATERIAL && } - {type === TypeEnum.PRODUCT && } - {type === TypeEnum.BYPRODUCT && } + {tabIndex === 0 && } + {tabIndex === 1 && } + {/* {type === TypeEnum.MATERIAL && } */} + {/* {type === TypeEnum.BYPRODUCT && } */}