@@ -0,0 +1,24 @@ | |||||
import { SearchParams } from "@/app/utils/fetchUtil"; | |||||
import { TypeEnum } from "@/app/utils/typeEnum"; | |||||
import CreateProductMaterial from "@/components/CreateProductMaterial"; | |||||
import { I18nProvider, getServerI18n } from "@/i18n"; | |||||
import { Typography } from "@mui/material"; | |||||
import { isString } from "lodash"; | |||||
type Props = {} & SearchParams; | |||||
const byProductSetting: React.FC<Props> = async ({ searchParams }) => { | |||||
const type = TypeEnum.BYPRODUCT; | |||||
const { t } = await getServerI18n(type); | |||||
console.log(searchParams); | |||||
return ( | |||||
<> | |||||
{/* <Typography variant="h4">{t("Create Material")}</Typography> */} | |||||
<I18nProvider namespaces={[type]}> | |||||
<CreateProductMaterial type={type} /> | |||||
</I18nProvider> | |||||
</> | |||||
); | |||||
}; | |||||
export default byProductSetting; |
@@ -0,0 +1,24 @@ | |||||
import { SearchParams } from "@/app/utils/fetchUtil"; | |||||
import { TypeEnum } from "@/app/utils/typeEnum"; | |||||
import CreateProductMaterial from "@/components/CreateProductMaterial"; | |||||
import { I18nProvider, getServerI18n } from "@/i18n"; | |||||
import { Typography } from "@mui/material"; | |||||
import { isString } from "lodash"; | |||||
type Props = {} & SearchParams; | |||||
const byProductSetting: React.FC<Props> = async ({ searchParams }) => { | |||||
const type = TypeEnum.BYPRODUCT; | |||||
const { t } = await getServerI18n(type); | |||||
console.log(searchParams); | |||||
return ( | |||||
<> | |||||
{/* <Typography variant="h4">{t("Create Material")}</Typography> */} | |||||
<I18nProvider namespaces={[type]}> | |||||
<CreateProductMaterial type={type} /> | |||||
</I18nProvider> | |||||
</> | |||||
); | |||||
}; | |||||
export default byProductSetting; |
@@ -0,0 +1,48 @@ | |||||
import { TypeEnum } from "@/app/utils/typeEnum"; | |||||
import MaterialSearch from "@/components/ProductMaterialSearch"; | |||||
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 ( | |||||
<> | |||||
<Stack | |||||
direction="row" | |||||
justifyContent="space-between" | |||||
flexWrap="wrap" | |||||
rowGap={2} | |||||
> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("ByProduct")} | |||||
</Typography> | |||||
<Button | |||||
variant="contained" | |||||
startIcon={<Add />} | |||||
LinkComponent={Link} | |||||
href="byProduct/create" | |||||
> | |||||
{t("Create by-Product")} | |||||
</Button> | |||||
</Stack> | |||||
<Suspense fallback={<MaterialSearch.Loading />}> | |||||
<MaterialSearch type={byProduct} /> | |||||
</Suspense> | |||||
</> | |||||
); | |||||
}; | |||||
export default materialSetting; |
@@ -0,0 +1,39 @@ | |||||
"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 | |||||
}; |
@@ -0,0 +1,40 @@ | |||||
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"] }, | |||||
}); | |||||
}); |
@@ -3,6 +3,7 @@ import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/a | |||||
import { revalidateTag } from "next/cache"; | import { revalidateTag } from "next/cache"; | ||||
import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
import { HTMLInputTypeAttribute } from "react"; | import { HTMLInputTypeAttribute } from "react"; | ||||
import { CreateItemResponse } from "../../utils"; | |||||
export type TypeInputs = { | export type TypeInputs = { | ||||
type: string | type: string | ||||
@@ -36,17 +37,10 @@ export type CreateMaterialInputs = { | |||||
uom?: UomInputs[]; | uom?: UomInputs[]; | ||||
weightUnit?: WeightUnitInputs[]; | weightUnit?: WeightUnitInputs[]; | ||||
} | } | ||||
export interface CreateProductMaterialResponse { | |||||
id: number | null; | |||||
name: string; | |||||
code: string; | |||||
message: string | null; | |||||
errorPosition: keyof CreateMaterialInputs; | |||||
} | |||||
export const saveMaterial = async (data: CreateMaterialInputs) => { | export const saveMaterial = async (data: CreateMaterialInputs) => { | ||||
// try { | // try { | ||||
const material = await serverFetchJson<CreateProductMaterialResponse>(`${BASE_API_URL}/material/new`, { | |||||
const material = await serverFetchJson<CreateItemResponse<CreateMaterialInputs>>(`${BASE_API_URL}/material/new`, { | |||||
method: "POST", | method: "POST", | ||||
body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
@@ -2,7 +2,8 @@ | |||||
import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; | import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; | ||||
import { revalidateTag } from "next/cache"; | import { revalidateTag } from "next/cache"; | ||||
import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
import { CreateProductMaterialResponse, TypeInputs, UomInputs, WeightUnitInputs } from "../material/actions"; | |||||
import { TypeInputs, UomInputs, WeightUnitInputs } from "../material/actions"; | |||||
import { CreateItemResponse } from "../../utils"; | |||||
export type CreateProductInputs = { | export type CreateProductInputs = { | ||||
id?: string | number | id?: string | number | ||||
@@ -26,11 +27,11 @@ export type CreateProductInputs = { | |||||
export const saveProduct = async (data: CreateProductInputs) => { | export const saveProduct = async (data: CreateProductInputs) => { | ||||
// try { | // try { | ||||
const material = await serverFetchJson<CreateProductMaterialResponse>(`${BASE_API_URL}/product/new`, { | |||||
const product = await serverFetchJson<CreateItemResponse<CreateProductInputs>>(`${BASE_API_URL}/product/new`, { | |||||
method: "POST", | method: "POST", | ||||
body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
}); | }); | ||||
revalidateTag("product"); | revalidateTag("product"); | ||||
return material | |||||
return product | |||||
}; | }; |
@@ -2,14 +2,13 @@ import { cache } from "react"; | |||||
import "server-only"; | import "server-only"; | ||||
import { serverFetchJson } from "@/app/utils/fetchUtil"; | import { serverFetchJson } from "@/app/utils/fetchUtil"; | ||||
import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
import { TypeInputs, UomInputs, WeightUnitInputs } from "../material/actions"; | |||||
export type ProductResult = { | export type ProductResult = { | ||||
id: string | number | id: string | number | ||||
code: string; | code: string; | ||||
name: string; | name: string; | ||||
isConsumables: boolean; | |||||
description: string | undefined; | description: string | undefined; | ||||
type: string | undefined; | |||||
remarks: string | undefined; | remarks: string | undefined; | ||||
shelfLife: Number | undefined; | shelfLife: Number | undefined; | ||||
countryOfOrigin: string | undefined; | countryOfOrigin: string | undefined; | ||||
@@ -20,20 +19,21 @@ export type ProductResult = { | |||||
sampleRate: number | undefined; | sampleRate: number | undefined; | ||||
passingRate: number | undefined; | passingRate: number | undefined; | ||||
netWeight: number | undefined; | netWeight: number | undefined; | ||||
uom: string[] | any[]; | |||||
weightUnit: string[] | any[]; | |||||
uom: UomInputs[]; | |||||
weightUnit: WeightUnitInputs[]; | |||||
type: TypeInputs[]; | |||||
action?: any; | action?: any; | ||||
} | } | ||||
export const fetchAllMaterials = cache(async () => { | |||||
export const fetchAllProduct = cache(async () => { | |||||
return serverFetchJson<ProductResult[]>(`${BASE_API_URL}/product`, { | return serverFetchJson<ProductResult[]>(`${BASE_API_URL}/product`, { | ||||
next: { tags: ["product"] }, | next: { tags: ["product"] }, | ||||
}); | }); | ||||
}); | }); | ||||
export const fetchMaterial = cache(async (id: number) => { | |||||
export const fetchProduct = cache(async (id: number) => { | |||||
return serverFetchJson<ProductResult>(`${BASE_API_URL}/product/details/${id}`, { | return serverFetchJson<ProductResult>(`${BASE_API_URL}/product/details/${id}`, { | ||||
next: { tags: ["product"] }, | next: { tags: ["product"] }, | ||||
}); | }); |
@@ -0,0 +1,7 @@ | |||||
export interface CreateItemResponse<T> { | |||||
id: number | null; | |||||
name: string; | |||||
code: string; | |||||
message: string | null; | |||||
errorPosition: string | keyof T; | |||||
} |
@@ -1,4 +1,5 @@ | |||||
export enum TypeEnum { | export enum TypeEnum { | ||||
PRODUCT = "product", | PRODUCT = "product", | ||||
MATERIAL = "material", | MATERIAL = "material", | ||||
BYPRODUCT = "byProduct", | |||||
} | } |
@@ -0,0 +1,302 @@ | |||||
"use client"; | |||||
import { CreateMaterialInputs } from "@/app/api/settings/material/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, 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; | |||||
}; | |||||
export type EntryError = | |||||
| { | |||||
[field in keyof CreateByProductInputs]?: string; | |||||
} | |||||
| undefined; | |||||
const ByProductDetails: React.FC<Props> = ({ | |||||
}) => { | |||||
const { | |||||
t, | |||||
i18n: { language }, | |||||
} = useTranslation(); | |||||
const { | |||||
register, | |||||
formState: { errors, defaultValues, touchedFields }, | |||||
watch, | |||||
control, | |||||
setValue, | |||||
getValues, | |||||
reset, | |||||
resetField, | |||||
setError, | |||||
clearErrors, | |||||
} = useFormContext<CreateByProductInputs>(); | |||||
const typeColumns = useMemo<GridColDef[]>( | |||||
() => [ | |||||
{ | |||||
field: "type", | |||||
headerName: "type", | |||||
flex: 1, | |||||
editable: true, | |||||
}, | |||||
], | |||||
[] | |||||
); | |||||
const weightUnitColumns = useMemo<GridColDef[]>( | |||||
() => [ | |||||
{ | |||||
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<GridColDef[]>( | |||||
() => [ | |||||
{ | |||||
field: "uom", | |||||
headerName: "uom", | |||||
flex: 1, | |||||
editable: true, | |||||
}, | |||||
], | |||||
[] | |||||
); | |||||
const validationTest = useCallback( | |||||
( | |||||
newRow: GridRowModel<TableRow<Partial<CreateByProductInputs>, EntryError>> | |||||
): EntryError => { | |||||
const error: EntryError = {}; | |||||
console.log(newRow); | |||||
return Object.keys(error).length > 0 ? error : undefined; | |||||
}, | |||||
[] | |||||
); | |||||
return ( | |||||
<Card sx={{ display: "block" }}> | |||||
<CardContent component={Stack} spacing={4}> | |||||
<Box> | |||||
<Typography variant="overline" display="block" marginBlockEnd={1}> | |||||
{t("Product Details")} | |||||
</Typography> | |||||
<Grid container spacing={2} columns={{ xs: 6, sm: 12 }}> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("Name")} | |||||
fullWidth | |||||
{...register("name", { | |||||
required: "name required!", | |||||
})} | |||||
error={Boolean(errors.name)} | |||||
helperText={errors.name?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("Code")} | |||||
fullWidth | |||||
{...register("code", { | |||||
required: "code required!", | |||||
})} | |||||
error={Boolean(errors.code)} | |||||
helperText={errors.code?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("description")} | |||||
fullWidth | |||||
{...register("description")} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("shelfLife")} | |||||
type="number" | |||||
fullWidth | |||||
{...register("shelfLife", { | |||||
valueAsNumber: true, | |||||
required: "shelfLife required!", | |||||
})} | |||||
error={Boolean(errors.shelfLife)} | |||||
helperText={errors.shelfLife?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("countryOfOrigin")} | |||||
fullWidth | |||||
{...register("countryOfOrigin", { | |||||
required: "countryOfOrigin required!", | |||||
})} | |||||
error={Boolean(errors.countryOfOrigin)} | |||||
helperText={errors.countryOfOrigin?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("minHumid")} | |||||
type="number" | |||||
fullWidth | |||||
inputProps={NumberInputProps} | |||||
{...register("minHumid", { | |||||
valueAsNumber: true, | |||||
required: "minHumid required!", | |||||
})} | |||||
error={Boolean(errors.minHumid)} | |||||
helperText={errors.minHumid?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("maxHumid")} | |||||
type="number" | |||||
fullWidth | |||||
inputProps={NumberInputProps} | |||||
{...register("maxHumid", { | |||||
valueAsNumber: true, | |||||
})} | |||||
error={Boolean(errors.maxHumid)} | |||||
helperText={errors.maxHumid?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("minTemp")} | |||||
type="number" | |||||
fullWidth | |||||
inputProps={NumberInputProps} | |||||
{...register("minTemp", { | |||||
valueAsNumber: true, | |||||
required: "minTemp required!", | |||||
})} | |||||
error={Boolean(errors.minTemp)} | |||||
helperText={errors.minTemp?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("maxTemp")} | |||||
type="number" | |||||
fullWidth | |||||
inputProps={NumberInputProps} | |||||
{...register("maxTemp", { | |||||
valueAsNumber: true, | |||||
required: "maxTemp required!", | |||||
})} | |||||
error={Boolean(errors.maxTemp)} | |||||
helperText={errors.maxTemp?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("sampleRate")} | |||||
type="number" | |||||
fullWidth | |||||
inputProps={NumberInputProps} | |||||
{...register("sampleRate", { | |||||
valueAsNumber: true, | |||||
required: "sampleRate required!", | |||||
})} | |||||
error={Boolean(errors.sampleRate)} | |||||
helperText={errors.sampleRate?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("passingRate")} | |||||
type="number" | |||||
fullWidth | |||||
inputProps={NumberInputProps} | |||||
{...register("passingRate", { | |||||
valueAsNumber: true, | |||||
required: "passingRate required!", | |||||
})} | |||||
error={Boolean(errors.passingRate)} // change backend for null or not null | |||||
helperText={errors.passingRate?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6} /> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("remarks")} | |||||
fullWidth | |||||
{...register("remarks", { | |||||
// required: "remarks required!", | |||||
})} | |||||
error={Boolean(errors.remarks)} | |||||
helperText={errors.remarks?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("netWeight")} | |||||
type="number" | |||||
fullWidth | |||||
inputProps={NumberInputProps} | |||||
{...register("netWeight", { | |||||
valueAsNumber: true, | |||||
required: "netWeight required!", | |||||
})} | |||||
error={Boolean(errors.netWeight)} | |||||
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> | |||||
</Card> | |||||
); | |||||
}; | |||||
export default ByProductDetails; |
@@ -5,7 +5,6 @@ import { useRouter, useSearchParams } from "next/navigation"; | |||||
import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
import { | import { | ||||
CreateMaterialInputs, | CreateMaterialInputs, | ||||
CreateProductMaterialResponse, | |||||
saveMaterial, | saveMaterial, | ||||
} from "@/app/api/settings/material/actions"; | } from "@/app/api/settings/material/actions"; | ||||
import { | import { | ||||
@@ -25,6 +24,9 @@ import { | |||||
import { CreateInputsFields } from "./CreateProductMaterialWrapper"; | import { CreateInputsFields } from "./CreateProductMaterialWrapper"; | ||||
import MaterialDetails from "./MaterialDetails"; | import MaterialDetails from "./MaterialDetails"; | ||||
import ProductDetails from "./ProductDetails"; | 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 = { | type Props = { | ||||
isEditMode: boolean; | isEditMode: boolean; | ||||
@@ -53,6 +55,10 @@ const CreateProductMaterial: React.FC<Props> = ({ | |||||
title = "Product"; | title = "Product"; | ||||
redirPath = "/product"; | redirPath = "/product"; | ||||
} | } | ||||
if (type === TypeEnum.BYPRODUCT) { | |||||
title = "By-Product"; | |||||
redirPath = "/byProduct"; | |||||
} | |||||
if (isEditMode) { | if (isEditMode) { | ||||
mode = "Edit"; | mode = "Edit"; | ||||
} else { | } else { | ||||
@@ -99,8 +105,16 @@ const CreateProductMaterial: React.FC<Props> = ({ | |||||
}); | }); | ||||
hasErrors = true; | 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 | // checking passing rate | ||||
if (data.passingRate && data.passingRate > 100) { | |||||
if (data.passingRate && (data.passingRate < 0 || data.passingRate > 100)) { | |||||
const message = "passingRate should not be greater than 100%"; | const message = "passingRate should not be greater than 100%"; | ||||
formProps.setError("passingRate", { | formProps.setError("passingRate", { | ||||
message: message, | message: message, | ||||
@@ -108,7 +122,7 @@ const CreateProductMaterial: React.FC<Props> = ({ | |||||
}); | }); | ||||
} | } | ||||
// checking sampling rate | // checking sampling rate | ||||
if (data.sampleRate && data.sampleRate > 100) { | |||||
if (data.sampleRate && (data.sampleRate < 0 || data.sampleRate > 100)) { | |||||
const message = "sampleRate should not be greater than 100%"; | const message = "sampleRate should not be greater than 100%"; | ||||
formProps.setError("sampleRate", { | formProps.setError("sampleRate", { | ||||
message: message, | message: message, | ||||
@@ -122,15 +136,21 @@ const CreateProductMaterial: React.FC<Props> = ({ | |||||
console.log("data posted"); | console.log("data posted"); | ||||
console.log(data); | console.log(data); | ||||
// do api | // do api | ||||
var response: CreateProductMaterialResponse | undefined; | |||||
var response; | |||||
if (type === TypeEnum.MATERIAL) { | if (type === TypeEnum.MATERIAL) { | ||||
response = await saveMaterial(data as CreateMaterialInputs); | response = await saveMaterial(data as CreateMaterialInputs); | ||||
} else if (type === TypeEnum.PRODUCT) { | } else if (type === TypeEnum.PRODUCT) { | ||||
response = await saveProduct(data as CreateProductInputs); | 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"); | |||||
} | } | ||||
if (response) { | if (response) { | ||||
if (!Boolean(response.id)) { | if (!Boolean(response.id)) { | ||||
formProps.setError(response.errorPosition!!, { | |||||
formProps.setError(response.errorPosition!! as keyof CreateInputsFields, { | |||||
message: response.message!!, | message: response.message!!, | ||||
type: "required", | type: "required", | ||||
}); | }); | ||||
@@ -176,6 +196,7 @@ const CreateProductMaterial: React.FC<Props> = ({ | |||||
)} | )} | ||||
{type === TypeEnum.MATERIAL && <MaterialDetails />} | {type === TypeEnum.MATERIAL && <MaterialDetails />} | ||||
{type === TypeEnum.PRODUCT && <ProductDetails />} | {type === TypeEnum.PRODUCT && <ProductDetails />} | ||||
{type === TypeEnum.BYPRODUCT && <ByProductDetails />} | |||||
<Stack direction="row" justifyContent="flex-end" gap={1}> | <Stack direction="row" justifyContent="flex-end" gap={1}> | ||||
<Button | <Button | ||||
name="submit" | name="submit" | ||||
@@ -3,67 +3,57 @@ import CreateProductMaterial from "./CreateProductMaterial"; | |||||
import CreateMaterialLoading from "./CreateProductMaterialLoading"; | import CreateMaterialLoading from "./CreateProductMaterialLoading"; | ||||
import { CreateMaterialInputs } from "@/app/api/settings/material/actions"; | import { CreateMaterialInputs } from "@/app/api/settings/material/actions"; | ||||
import { CreateProductInputs } from "@/app/api/settings/product/actions"; | import { CreateProductInputs } from "@/app/api/settings/product/actions"; | ||||
import { fetchMaterial, MaterialResult } from "@/app/api/settings/material"; | |||||
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 { | interface SubComponents { | ||||
Loading: typeof CreateMaterialLoading; | Loading: typeof CreateMaterialLoading; | ||||
} | } | ||||
type CreateMaterialProps = { | |||||
// isEditMode: false; | |||||
type Props = { | |||||
id?: number | |||||
type: TypeEnum; | type: TypeEnum; | ||||
}; | }; | ||||
type EditMaterialProps = { | |||||
// isEditMode: true; | |||||
type: TypeEnum; | |||||
}; | |||||
type CreateProductProps = { | |||||
// isEditMode: false; | |||||
type: TypeEnum; | |||||
}; | |||||
type EditProductProps = { | |||||
// isEditMode: true; | |||||
type: TypeEnum; | |||||
}; | |||||
type Props = | |||||
| CreateMaterialProps | |||||
| EditMaterialProps | |||||
| CreateProductProps | |||||
| EditProductProps; | |||||
export type CreateInputsFields = CreateMaterialInputs | CreateProductInputs; | |||||
export type CreateInputsFields = CreateMaterialInputs | CreateProductInputs | CreateByProductInputs; | |||||
const CreateProductMaterialWrapper: React.FC<Props & { id?: number }> & | |||||
const CreateProductMaterialWrapper: React.FC<Props> & | |||||
SubComponents = async ({ type, id }) => { | SubComponents = async ({ type, id }) => { | ||||
var defaultValues: Partial<CreateInputsFields> = {}; | var defaultValues: Partial<CreateInputsFields> = {}; | ||||
var result | |||||
if (id && type === TypeEnum.MATERIAL) { | if (id && type === TypeEnum.MATERIAL) { | ||||
const result = await fetchMaterial(id); | |||||
console.log(result) | |||||
result = await fetchMaterial(id); | |||||
defaultValues = { | defaultValues = { | ||||
id: result.id, | |||||
code: result.name, | |||||
name: result.name, | |||||
isConsumables: result.isConsumables, | |||||
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, | |||||
}; | |||||
isConsumables: result.isConsumables | |||||
} | |||||
} else if (id && type === TypeEnum.PRODUCT) { | |||||
result = await fetchProduct(id); | |||||
} else if (id && type === TypeEnum.BYPRODUCT) { | |||||
result = await fetchByProduct(id); | |||||
} | } | ||||
if (id && type === TypeEnum.PRODUCT) { | |||||
defaultValues = {}; | |||||
} | |||||
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 ( | return ( | ||||
<CreateProductMaterial | <CreateProductMaterial | ||||
isEditMode={Boolean(id)} | isEditMode={Boolean(id)} | ||||
@@ -229,8 +229,6 @@ const ProductDetails: React.FC<Props> = ({ | |||||
inputProps={NumberInputProps} | inputProps={NumberInputProps} | ||||
{...register("sampleRate", { | {...register("sampleRate", { | ||||
valueAsNumber: true, | valueAsNumber: true, | ||||
min: 0, | |||||
max: 100, | |||||
required: "sampleRate required!", | required: "sampleRate required!", | ||||
})} | })} | ||||
error={Boolean(errors.sampleRate)} | error={Boolean(errors.sampleRate)} | ||||
@@ -245,8 +243,6 @@ const ProductDetails: React.FC<Props> = ({ | |||||
inputProps={NumberInputProps} | inputProps={NumberInputProps} | ||||
{...register("passingRate", { | {...register("passingRate", { | ||||
valueAsNumber: true, | valueAsNumber: true, | ||||
min: 0, | |||||
max: 100, | |||||
required: "passingRate required!", | required: "passingRate required!", | ||||
})} | })} | ||||
error={Boolean(errors.passingRate)} // change backend for null or not null | error={Boolean(errors.passingRate)} // change backend for null or not null | ||||
@@ -188,8 +188,8 @@ const NavigationContent: React.FC = () => { | |||||
}, | }, | ||||
{ | { | ||||
icon: <RequestQuote />, | icon: <RequestQuote />, | ||||
label: "Maintain By-product", | |||||
path: "/settings/user", | |||||
label: "By-product", | |||||
path: "/settings/byProduct", | |||||
}, | }, | ||||
{ | { | ||||
icon: <RequestQuote />, | icon: <RequestQuote />, | ||||
@@ -100,6 +100,11 @@ const MaterialSearch: React.FC<Props> = ({ productMaterial, type }) => { | |||||
pm.code.toLowerCase().includes(query.code.toLowerCase()) && | pm.code.toLowerCase().includes(query.code.toLowerCase()) && | ||||
pm.name.toLowerCase().includes(query.name.toLowerCase()) | pm.name.toLowerCase().includes(query.name.toLowerCase()) | ||||
); | ); | ||||
} else if (type === TypeEnum.BYPRODUCT) { | |||||
return ( | |||||
pm.code.toLowerCase().includes(query.code.toLowerCase()) && | |||||
pm.name.toLowerCase().includes(query.name.toLowerCase()) | |||||
); | |||||
} | } | ||||
}) | }) | ||||
); | ); | ||||
@@ -3,6 +3,7 @@ import ProductMaterialSearch, { ListResult } from "./ProductMaterialSearch"; | |||||
import MaterialSearchLoading from "./ProductMaterialSearchLoading"; | import MaterialSearchLoading from "./ProductMaterialSearchLoading"; | ||||
import { SearchParams } from "@/app/utils/fetchUtil"; | import { SearchParams } from "@/app/utils/fetchUtil"; | ||||
import { TypeEnum } from "@/app/utils/typeEnum"; | import { TypeEnum } from "@/app/utils/typeEnum"; | ||||
import { notFound } from "next/navigation"; | |||||
interface SubComponents { | interface SubComponents { | ||||
Loading: typeof MaterialSearchLoading; | Loading: typeof MaterialSearchLoading; | ||||
@@ -13,16 +14,20 @@ type Props = { | |||||
}; | }; | ||||
const ProductMaterialSearchWrapper: React.FC<Props> & SubComponents = async ({ | const ProductMaterialSearchWrapper: React.FC<Props> & SubComponents = async ({ | ||||
type | |||||
type, | |||||
}) => { | }) => { | ||||
var result: ListResult[] = [] | |||||
if (TypeEnum.PRODUCT === type) { | |||||
result = [] | |||||
} else if (TypeEnum.MATERIAL === type) { | |||||
var result: ListResult[] = []; | |||||
if (TypeEnum.PRODUCT === type) { | |||||
result = []; | |||||
} else if (TypeEnum.MATERIAL === type) { | |||||
result = await fetchAllMaterials(); | result = await fetchAllMaterials(); | ||||
} else if (TypeEnum.BYPRODUCT === type) { | |||||
result = []; | |||||
} else { | |||||
notFound(); | |||||
} | } | ||||
return <ProductMaterialSearch productMaterial={result} type={TypeEnum.MATERIAL} />; | |||||
return <ProductMaterialSearch productMaterial={result} type={type} />; | |||||
}; | }; | ||||
ProductMaterialSearchWrapper.Loading = MaterialSearchLoading; | ProductMaterialSearchWrapper.Loading = MaterialSearchLoading; | ||||