@@ -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"; |