Explorar el Código

i18n,setting/Equipmenttype

master
CANCERYS\kw093 hace 1 mes
padre
commit
fd122103f3
Se han modificado 23 ficheros con 937 adiciones y 30 borrados
  1. +1
    -0
      src/app/(main)/material/page.tsx
  2. +22
    -0
      src/app/(main)/settings/equipmentType/create/page.tsx
  3. +29
    -0
      src/app/(main)/settings/equipmentType/edit/page.tsx
  4. +52
    -0
      src/app/(main)/settings/equipmentType/page.tsx
  5. +6
    -4
      src/app/(main)/settings/rss/page.tsx
  6. +37
    -0
      src/app/api/settings/equipmentType/actions.ts
  7. +33
    -0
      src/app/api/settings/equipmentType/index.ts
  8. +7
    -0
      src/app/api/utils/index.ts
  9. +193
    -0
      src/components/CreateEquipmentType/CreateEquipmentType.tsx
  10. +40
    -0
      src/components/CreateEquipmentType/CreateEquipmentTypeLoading.tsx
  11. +43
    -0
      src/components/CreateEquipmentType/CreateEquipmentTypeWrapper.tsx
  12. +199
    -0
      src/components/CreateEquipmentType/EquipmentTypeDetails.tsx
  13. +5
    -0
      src/components/CreateEquipmentType/NumberInputProps.ts
  14. +1
    -0
      src/components/CreateEquipmentType/index.ts
  15. +3
    -1
      src/components/CreateItem/CreateItem.tsx
  16. +39
    -3
      src/components/CreateItem/ProductDetails.tsx
  17. +147
    -0
      src/components/EquipmentTypeSearch/EquipmentTypeSearch.tsx
  18. +40
    -0
      src/components/EquipmentTypeSearch/EquipmentTypeSearchLoading.tsx
  19. +26
    -0
      src/components/EquipmentTypeSearch/EquipmentTypeSearchWrapper.tsx
  20. +1
    -0
      src/components/EquipmentTypeSearch/index.ts
  21. +1
    -1
      src/components/NavigationContent/NavigationContent.tsx
  22. +9
    -19
      src/i18n/zh/common.json
  23. +3
    -2
      src/i18n/zh/project.json

+ 1
- 0
src/app/(main)/material/page.tsx Ver fichero

@@ -37,6 +37,7 @@ const material: React.FC<Props> = async ({ searchParams }) => {
>
{t("Create Claim")}
</Button>
</Stack>
{/* <Suspense fallback={<MaterialSearch.Loading />}>
<MaterialSearch />


+ 22
- 0
src/app/(main)/settings/equipmentType/create/page.tsx Ver fichero

@@ -0,0 +1,22 @@
import { SearchParams } from "@/app/utils/fetchUtil";
import { TypeEnum } from "@/app/utils/typeEnum";
import CreateEquipmentType from "@/components/CreateEquipmentType";
import { I18nProvider, getServerI18n } from "@/i18n";
import { Typography } from "@mui/material";
import isString from "lodash/isString";

type Props = {} & SearchParams;

const materialSetting: React.FC<Props> = async ({ searchParams }) => {
// const type = TypeEnum.PRODUCT;
const { t } = await getServerI18n("common");
return (
<>
{/* <Typography variant="h4">{t("Create Material")}</Typography> */}
<I18nProvider namespaces={["common"]}>
<CreateEquipmentType />
</I18nProvider>
</>
);
};
export default materialSetting;

+ 29
- 0
src/app/(main)/settings/equipmentType/edit/page.tsx Ver fichero

@@ -0,0 +1,29 @@
import { SearchParams } from "@/app/utils/fetchUtil";
import { TypeEnum } from "@/app/utils/typeEnum";
import CreateEquipmentType from "@/components/CreateEquipmentType";
import { I18nProvider, getServerI18n } from "@/i18n";
import { Typography } from "@mui/material";
import isString from "lodash/isString";
import { notFound } from "next/navigation";

type Props = {} & SearchParams;

const productSetting: React.FC<Props> = async ({ searchParams }) => {
const type = "common";
const { t } = await getServerI18n(type);
const id = isString(searchParams["id"])
? parseInt(searchParams["id"])
: undefined;
if (!id) {
notFound();
}
return (
<>
{/* <Typography variant="h4">{t("Create Material")}</Typography> */}
<I18nProvider namespaces={[type]}>
<CreateEquipmentType id={id} />
</I18nProvider>
</>
);
};
export default productSetting;

+ 52
- 0
src/app/(main)/settings/equipmentType/page.tsx Ver fichero

@@ -0,0 +1,52 @@
import { TypeEnum } from "@/app/utils/typeEnum";
import EquipmentTypeSearch from "@/components/EquipmentTypeSearch";
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";
import { fetchAllEquipmentTypes } from "@/app/api/settings/equipmentType";
import { I18nProvider } from "@/i18n";
export const metadata: Metadata = {
title: "Equipment Type",
};

const productSetting: React.FC = async () => {
const type = "common";
const { t } = await getServerI18n(type);
const equipmentTypes = await fetchAllEquipmentTypes();
// preloadClaims();

return (
<>
<Stack
direction="row"
justifyContent="space-between"
flexWrap="wrap"
rowGap={2}
>
<Typography variant="h4" marginInlineEnd={2}>
{t("Equipment Type")}
</Typography>
{/* <Button
variant="contained"
startIcon={<Add />}
LinkComponent={Link}
href="product/create"
>
{t("Create product")}
</Button> */}
</Stack>
<Suspense fallback={<EquipmentTypeSearch.Loading />}>
<I18nProvider namespaces={["common","project"]}>
<EquipmentTypeSearch />
</I18nProvider>
</Suspense>
</>
);
};

export default productSetting;

+ 6
- 4
src/app/(main)/settings/rss/page.tsx Ver fichero

@@ -10,7 +10,7 @@ import Link from "next/link";
import { Suspense } from "react";
import RoughScheduleLoading from "@/components/RoughScheduleSetting/RoughScheduleLoading";
import RoughScheduleSetting from "@/components/RoughScheduleSetting/RoughScheduleSetting";
import { I18nProvider } from "@/i18n";
export const metadata: Metadata = {
title: "Demand Forecast Setting",
};
@@ -40,9 +40,11 @@ const roughScheduleSetting: React.FC = async () => {
{t("Create product")}
</Button> */}
</Stack>
<Suspense fallback={<RoughScheduleLoading.Loading />}>
<RoughScheduleSetting />
</Suspense>
<I18nProvider namespaces={[ "common", "project"]}>
<Suspense fallback={<RoughScheduleLoading.Loading />}>
<RoughScheduleSetting />
</Suspense>
</I18nProvider>
</>
);
};


+ 37
- 0
src/app/api/settings/equipmentType/actions.ts Ver fichero

@@ -0,0 +1,37 @@
"use server";
import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
import { revalidateTag } from "next/cache";
import { BASE_API_URL } from "@/config/api";
import { CreateEquipmentTypeResponse } from "../../utils";

// export type TypeInputs = {
// id: number;
// name: string
// }
// export type UomInputs = {
// uom: string
// }
// export type WeightUnitInputs = {
// weightUnit: string
// conversion: number
// }


export type CreateEquipmentTypeInputs = {
id?: string | number
code: string;
name: string;
description?: string | undefined;

}

export const saveEquipmentType = async (data: CreateEquipmentTypeInputs) => {
// try {
const equipmentType = await serverFetchJson<CreateEquipmentTypeResponse<CreateEquipmentTypeInputs>>(`${BASE_API_URL}/EquipmentType/save`, {
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
});
revalidateTag("EquipmentType");
return equipmentType
};

+ 33
- 0
src/app/api/settings/equipmentType/index.ts Ver fichero

@@ -0,0 +1,33 @@
import { cache } from "react";
import "server-only";
// import { serverFetchJson } from "@/app/utils/fetchUtil";
// import { BASE_API_URL } from "@/config/api";
import { serverFetchJson } from "../../../utils/fetchUtil";
import { BASE_API_URL } from "../../../../config/api";
export { default } from "../../../../components/CreateEquipmentType/CreateEquipmentType";
// import { TypeInputs, UomInputs, WeightUnitInputs } from "./actions";


export type EquipmentTypeResult = {
id: string | number
code: string;
name: string;
description: string | undefined;
action?: any
}

export type Result = {
equipmentType: EquipmentTypeResult
}
export const fetchAllEquipmentTypes = cache(async () => {
return serverFetchJson<EquipmentTypeResult[]>(`${BASE_API_URL}/EquipmentType`, {
next: { tags: ["equipmentTypes"] },
});
});


export const fetchEquipmentType = cache(async (id: number) => {
return serverFetchJson<EquipmentTypeResult>(`${BASE_API_URL}/EquipmentType/details/${id}`, {
next: { tags: ["equipmentTypes"] },
});
});

+ 7
- 0
src/app/api/utils/index.ts Ver fichero

@@ -5,6 +5,13 @@ export interface CreateItemResponse<T> {
message: string | null;
errorPosition: string | keyof T;
}
export interface CreateEquipmentTypeResponse<T> {
id: number | null;
name: string;
code: string;
message: string | null;
errorPosition: string | keyof T;
}

export interface RecordsRes<T>{
records: T


+ 193
- 0
src/components/CreateEquipmentType/CreateEquipmentType.tsx Ver fichero

@@ -0,0 +1,193 @@
"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { useTranslation } from "react-i18next";
import {
CreateEquipmentTypeInputs,
saveEquipmentType,
} from "@/app/api/settings/equipmentType/actions";
import {
FormProvider,
SubmitErrorHandler,
SubmitHandler,
useForm,
} from "react-hook-form";
import { deleteDialog } from "../Swal/CustomAlerts";
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 EquipmentTypeDetails from "./EquipmentTypeDetails";
import { CreateItemResponse } from "@/app/api/utils";
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;
defaultValues: Partial<CreateEquipmentTypeInputs> | undefined;
};

const CreateItem: React.FC<Props> = ({
isEditMode,
// type,
defaultValues,

}) => {
// 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("common");
const router = useRouter();
const title = "Equipment Type"
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
title = "Equipment Type";
redirPath = "/settings/equipmentType";
// }
// if (type === TypeEnum.BYPRODUCT) {
// typeId = TypeEnum.BYPRODUCT_ID
// title = "By-Product";
// redirPath = "/settings/byProduct";
// }
if (isEditMode) {
mode = "Edit";
} else {
mode = "Create";
}
return [mode, redirPath];
}, [isEditMode]);
// console.log(typeId)
const formProps = useForm<CreateEquipmentTypeInputs>({
defaultValues: defaultValues ? defaultValues : {
},
});
const errors = formProps.formState.errors;

const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
(_e, newValue) => {
setTabIndex(newValue);
},
[],
);

const handleCancel = () => {
router.replace(`/settings/equipmentType`);
};
const onSubmit = useCallback<SubmitHandler<CreateEquipmentTypeInputs & {}>>(
async (data, event) => {
let hasErrors = false;
console.log(errors)
// console.log(apiRef.current.getCellValue(2, "lowerLimit"))
// apiRef.current.
try {
if (hasErrors) {
setServerError(t("An error has occurred. Please try again later."));
return false;
}
console.log("data posted");
console.log(data);


// TODO:
// 1. check field ( directly modify col def / check here )
// 2. set error change tab index

// return
// do api
console.log("asdad")
var responseI = await saveEquipmentType(data);
console.log("asdad")
// var responseQ = await saveItemQcChecks(qcCheck)
if (responseI) {
if (!Boolean(responseI.id)) {
formProps.setError(responseI.errorPosition!! as keyof CreateEquipmentTypeInputs, {
message: responseI.message!!,
type: "required",
})
} else if (Boolean(responseI.id)) {
router.replace(redirPath);
}
}
} catch (e) {
// backend error
setServerError(t("An error has occurred. Please try again later."));
console.log(e);
}
},
[apiRef, router, t]
);

// multiple tabs
const onSubmitError = useCallback<SubmitErrorHandler<CreateEquipmentTypeInputs>>(
(errors) => {},
[]
);

return (
<>
<FormProvider {...formProps}>
<Stack
spacing={2}
component="form"
onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
>
<Grid>
<Typography mb={2} variant="h4">
{t(`${mode} ${title}`)}
</Typography>
</Grid>
<Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable">
<Tab label={t("Equipment Type Details")} iconPosition="end"/>
{/* <Tab label={t("Qc items")} iconPosition="end" /> */}
</Tabs>
{serverError && (
<Typography variant="body2" color="error" alignSelf="flex-end">
{serverError}
</Typography>
)}
{tabIndex === 0 && <EquipmentTypeDetails isEditMode={isEditMode} />}
{/* {tabIndex === 1 && <QcDetails apiRef={apiRef} />} */}
{/* {type === TypeEnum.MATERIAL && <MaterialDetails />} */}
{/* {type === TypeEnum.BYPRODUCT && <ByProductDetails />} */}
{/*
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
name="submit"
variant="contained"
startIcon={<Check />}
type="submit"
// disabled={submitDisabled}
>
{isEditMode ? t("Save") : t("Confirm")}
</Button>
<Button
variant="outlined"
startIcon={<Close />}
onClick={handleCancel}
>
{t("Cancel")}
</Button>
</Stack>
*/}
</Stack>
</FormProvider>
</>
);
};
export default CreateItem;

+ 40
- 0
src/components/CreateEquipmentType/CreateEquipmentTypeLoading.tsx Ver fichero

@@ -0,0 +1,40 @@
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import Skeleton from "@mui/material/Skeleton";
import Stack from "@mui/material/Stack";
import React from "react";

// Can make this nicer
export const CreateItemLoading: React.FC = () => {
return (
<>
<Card>
<CardContent>
<Stack spacing={2}>
<Skeleton variant="rounded" height={60} />
<Skeleton variant="rounded" height={60} />
<Skeleton variant="rounded" height={60} />
<Skeleton
variant="rounded"
height={50}
width={100}
sx={{ alignSelf: "flex-end" }}
/>
</Stack>
</CardContent>
</Card>
<Card>CreateMaterial
<CardContent>
<Stack spacing={2}>
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
</Stack>
</CardContent>
</Card>
</>
);
};

export default CreateItemLoading;

+ 43
- 0
src/components/CreateEquipmentType/CreateEquipmentTypeWrapper.tsx Ver fichero

@@ -0,0 +1,43 @@
import { TypeEnum } from "@/app/utils/typeEnum";
import CreateEquipmentType from "./CreateEquipmentType";
import CreateEquipmentTypeLoading from "./CreateEquipmentTypeLoading";
import { CreateEquipmentTypeInputs } from "@/app/api/settings/equipmentType/actions";
import { notFound } from "next/navigation";
import { fetchEquipmentType } from "@/app/api/settings/equipmentType";
interface SubComponents {
Loading: typeof CreateEquipmentTypeLoading;
}

type Props = {
id?: number
// type: TypeEnum;
};

const CreateEquipmentTypeWrapper: React.FC<Props> &
SubComponents = async ({ id }) => {
var result
var defaultValues: Partial<CreateEquipmentTypeInputs> | undefined
// console.log(type)
var qcChecks
if (id) {
result = await fetchEquipmentType(id);
const equipmentType = result
console.log(equipmentType)
defaultValues = {
id: equipmentType?.id,
code: equipmentType?.code,
name: equipmentType?.name,
description: equipmentType?.description,
};
}
return (
<CreateEquipmentType
isEditMode={Boolean(id)}
defaultValues={defaultValues}
/>
);
};
CreateEquipmentTypeWrapper.Loading = CreateEquipmentTypeLoading;

export default CreateEquipmentTypeWrapper;

+ 199
- 0
src/components/CreateEquipmentType/EquipmentTypeDetails.tsx Ver fichero

@@ -0,0 +1,199 @@
"use client";
import {
Box,
Button,
Card,
CardContent,
Grid,
Stack,
TextField,
Typography,
} from "@mui/material";
import { Check, Close, EditNote } from "@mui/icons-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 { NumberInputProps } from "./NumberInputProps";
import { CreateEquipmentTypeInputs } from "@/app/api/settings/equipmentType/actions";
import { RestartAlt } from "@mui/icons-material";
type Props = {
// isEditMode: boolean;
// type: TypeEnum;
isEditMode: boolean;
// type: TypeEnum;
defaultValues: Partial<CreateEquipmentTypeInputs> | undefined;
};

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

const {
register,
formState: { errors, defaultValues, touchedFields },
watch,
control,
setValue,
getValues,
reset,
resetField,
setError,
clearErrors,
} = useFormContext<CreateEquipmentTypeInputs>();
// 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<CreateItemInputs>, EntryError>>
// ): EntryError => {
// const error: EntryError = {};
// console.log(newRow);
// return Object.keys(error).length > 0 ? error : undefined;
// },
// []
// );
const handleCancel = () => {
router.replace(`/settings/equipmentType`);
};
return (
<Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}>
<Box>
<Typography variant="overline" display="block" marginBlockEnd={1}>
{t("Equipment Type 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={12}>
<Stack direction="row" justifyContent="flex-start" spacing={2} sx={{ mt: 2 }}>
<Button
name="submit"
variant="contained"
startIcon={<Check />}
type="submit"
// disabled={submitDisabled}
>
{isEditMode ? t("Save") : t("Confirm")}
</Button>
<Button
variant="outlined"
startIcon={<Close />}
onClick={handleCancel}
>
{t("Cancel")}
</Button>
<Button
variant="outlined"
startIcon={<RestartAlt />}
onClick={() => reset()}
>
{t("Reset")}
</Button>
</Stack>
</Grid>
{/* <Grid item xs={6}>
<InputDataGrid<CreateItemInputs, EntryError>
_formKey={"type"}
columns={typeColumns}
validateRow={validationTest}
/>
</Grid>
<Grid item xs={6}>
<InputDataGrid<CreateItemInputs, EntryError>
_formKey={"uom"}
columns={uomColumns}
validateRow={validationTest}
/>
</Grid>
<Grid item xs={12}>
<InputDataGrid<CreateItemInputs, EntryError>
_formKey={"weightUnit"}
columns={weightUnitColumns}
validateRow={validationTest}
/>
</Grid>*/}
</Grid>
</Box>
</CardContent>
</Card>
);
};
export default ProductDetails;

+ 5
- 0
src/components/CreateEquipmentType/NumberInputProps.ts Ver fichero

@@ -0,0 +1,5 @@
import { InputBaseComponentProps } from "@mui/material";

export var NumberInputProps: InputBaseComponentProps = {
step: 0.01,
};

+ 1
- 0
src/components/CreateEquipmentType/index.ts Ver fichero

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

+ 3
- 1
src/components/CreateItem/CreateItem.tsx Ver fichero

@@ -174,10 +174,11 @@ const CreateItem: React.FC<Props> = ({
{serverError}
</Typography>
)}
{tabIndex === 0 && <ProductDetails />}
{tabIndex === 0 && <ProductDetails isEditMode={isEditMode} />}
{tabIndex === 1 && <QcDetails apiRef={apiRef} />}
{/* {type === TypeEnum.MATERIAL && <MaterialDetails />} */}
{/* {type === TypeEnum.BYPRODUCT && <ByProductDetails />} */}
{/*
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
name="submit"
@@ -196,6 +197,7 @@ const CreateItem: React.FC<Props> = ({
{t("Cancel")}
</Button>
</Stack>
*/}
</Stack>
</FormProvider>
</>


+ 39
- 3
src/components/CreateItem/ProductDetails.tsx Ver fichero

@@ -1,6 +1,7 @@
"use client";
import {
Box,
Button,
Card,
CardContent,
Grid,
@@ -8,22 +9,28 @@ import {
TextField,
Typography,
} from "@mui/material";
import { Check, Close, EditNote } from "@mui/icons-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 { NumberInputProps } from "./NumberInputProps";
import { CreateItemInputs } from "@/app/api/settings/item/actions";
import { RestartAlt } from "@mui/icons-material";
type Props = {
// isEditMode: boolean;
// type: TypeEnum;
isEditMode: boolean;
// type: TypeEnum;
defaultValues: Partial<CreateItemInputs> | undefined;
qcChecks: ItemQc[]
};

const ProductDetails: React.FC<Props> = ({}) => {
const ProductDetails: React.FC<Props> = ({isEditMode}) => {
const {
t,
i18n: { language },
@@ -92,7 +99,9 @@ const ProductDetails: React.FC<Props> = ({}) => {
// },
// []
// );

const handleCancel = () => {
router.replace(`/settings/product`);
};
return (
<Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}>
@@ -191,6 +200,33 @@ const ProductDetails: React.FC<Props> = ({}) => {
helperText={errors.maxQty?.message}
/>
</Grid>
<Grid item xs={0}>
<Stack direction="row" justifyContent="flex-end" spacing={2} sx={{ mt: 2 }}>
<Button
name="submit"
variant="contained"
startIcon={<Check />}
type="submit"
// disabled={submitDisabled}
>
{isEditMode ? t("Save") : t("Confirm")}
</Button>
<Button
variant="outlined"
startIcon={<Close />}
onClick={handleCancel}
>
{t("Cancel")}
</Button>
<Button
variant="outlined"
startIcon={<RestartAlt />}
onClick={() => reset()}
>
{t("Reset")}
</Button>
</Stack>
</Grid>
{/* <Grid item xs={6}>
<InputDataGrid<CreateItemInputs, EntryError>
_formKey={"type"}


+ 147
- 0
src/components/EquipmentTypeSearch/EquipmentTypeSearch.tsx Ver fichero

@@ -0,0 +1,147 @@
"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import SearchBox, { Criterion } from "../SearchBox";
import { EquipmentTypeResult } from "@/app/api/settings/equipmentType";
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 axios from "axios";
import { BASE_API_URL, NEXT_PUBLIC_API_URL } from "@/config/api";
import axiosInstance from "@/app/(main)/axios/axiosInstance";

type Props = {
equipmentTypes: EquipmentTypeResult[];
};
type SearchQuery = Partial<Omit<EquipmentTypeResult, "id">>;
type SearchParamNames = keyof SearchQuery;

const EquipmentTypeSearch: React.FC<Props> = ({ equipmentTypes }) => {
const [filteredEquipmentTypes, setFilteredEquipmentTypes] = useState<EquipmentTypeResult[]>(equipmentTypes);
const { t } = useTranslation("common");
const router = useRouter();
const [filterObj, setFilterObj] = useState({});
const [pagingController, setPagingController] = useState({
pageNum: 1,
pageSize: 10,
// totalCount: 0,
});
const [totalCount, setTotalCount] = useState(0)
const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => {
var searchCriteria: Criterion<SearchParamNames>[] = [
{ label: t("Code"), paramName: "code", type: "text" },
{ label: t("Description"), paramName: "description", type: "text" },
];
return searchCriteria;
}, [t, equipmentTypes]);

const onDetailClick = useCallback(
(equipmentType: EquipmentTypeResult) => {
router.push(`/settings/equipmentType/edit?id=${equipmentType.id}`);
},
[router]
);

const onDeleteClick = useCallback((equipmentType: EquipmentTypeResult) => {}, [router]);

const columns = useMemo<Column<EquipmentTypeResult>[]>(
() => [
{
name: "id",
label: t("Details"),
onClick: onDetailClick,
buttonIcon: <EditNote />,
},
{
name: "code",
label: t("Code"),
},
{
name: "description",
label: t("Description"),
},
{
name: "action",
label: t(""),
buttonIcon: <GridDeleteIcon />,
onClick: onDeleteClick,
},
],
[filteredEquipmentTypes]
);

const refetchData = useCallback(
async (filterObj: SearchQuery) => {
const authHeader = axiosInstance.defaults.headers["Authorization"];
if (!authHeader) {
return; // Exit the function if the token is not set
}
const params = {
pageNum: pagingController.pageNum,
pageSize: pagingController.pageSize,
...filterObj,
};
try {
const response = await axiosInstance.get<EquipmentTypeResult[]>(
`${NEXT_PUBLIC_API_URL}/EquipmentType/getRecordByPage`,
{ params }
);
console.log(response);
if (response.status == 200) {
setFilteredEquipmentTypes(response.data.records);
setTotalCount(response.data.total)
return response; // Return the data from the response
} else {
throw "400";
}
} catch (error) {
console.error("Error fetching equipment types:", error);
throw error; // Rethrow the error for further handling
}
},
[axiosInstance, pagingController.pageNum, pagingController.pageSize]
);

useEffect(() => {
refetchData(filterObj);
}, [filterObj, pagingController.pageNum, pagingController.pageSize]);

const onReset = useCallback(() => {
setFilteredEquipmentTypes(equipmentTypes);
}, [equipmentTypes]);

return (
<>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
// setFilteredItems(
// equipmentTypes.filter((pm) => {
// return (
// pm.code.toLowerCase().includes(query.code.toLowerCase()) &&
// pm.name.toLowerCase().includes(query.name.toLowerCase())
// );
// })
// );
setFilterObj({
...query,
});
}}
onReset={onReset}
/>
<SearchResults<EquipmentTypeResult>
items={filteredEquipmentTypes}
columns={columns}
setPagingController={setPagingController}
pagingController={pagingController}
totalCount={totalCount}
isAutoPaging={false}
/>
</>
);
};

export default EquipmentTypeSearch;

+ 40
- 0
src/components/EquipmentTypeSearch/EquipmentTypeSearchLoading.tsx Ver fichero

@@ -0,0 +1,40 @@
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import Skeleton from "@mui/material/Skeleton";
import Stack from "@mui/material/Stack";
import React from "react";

// Can make this nicer
export const EquipmentTypeSearchLoading: React.FC = () => {
return (
<>
<Card>
<CardContent>
<Stack spacing={2}>
<Skeleton variant="rounded" height={60} />
<Skeleton variant="rounded" height={60} />
<Skeleton variant="rounded" height={60} />
<Skeleton
variant="rounded"
height={50}
width={100}
sx={{ alignSelf: "flex-end" }}
/>
</Stack>
</CardContent>
</Card>
<Card>
<CardContent>
<Stack spacing={2}>
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
<Skeleton variant="rounded" height={40} />
</Stack>
</CardContent>
</Card>
</>
);
};

export default EquipmentTypeSearchLoading;

+ 26
- 0
src/components/EquipmentTypeSearch/EquipmentTypeSearchWrapper.tsx Ver fichero

@@ -0,0 +1,26 @@
import { fetchAllEquipmentTypes, } from "@/app/api/settings/equipmentType";
import EquipmentTypeSearchLoading from "./EquipmentTypeSearchLoading";
import { SearchParams } from "@/app/utils/fetchUtil";
import { TypeEnum } from "@/app/utils/typeEnum";
import { notFound } from "next/navigation";
import EquipmentTypeSearch from "./EquipmentTypeSearch";

interface SubComponents {
Loading: typeof EquipmentTypeSearchLoading;
}

type Props = {
// type: TypeEnum;
};

const EquipmentTypeSearchWrapper: React.FC<Props> & SubComponents = async ({
// type,
}) => {
// console.log(type)
// var result = await fetchAllEquipmentTypes()
return <EquipmentTypeSearch equipmentTypes={[]} />;
};

EquipmentTypeSearchWrapper.Loading = EquipmentTypeSearchLoading;

export default EquipmentTypeSearchWrapper;

+ 1
- 0
src/components/EquipmentTypeSearch/index.ts Ver fichero

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

+ 1
- 1
src/components/NavigationContent/NavigationContent.tsx Ver fichero

@@ -221,7 +221,7 @@ const NavigationContent: React.FC = () => {
{
icon: <RequestQuote />,
label: "Equipment Type",
path: "/settings/user",
path: "/settings/equipmentType",
},
{
icon: <RequestQuote />,


+ 9
- 19
src/i18n/zh/common.json Ver fichero

@@ -1,22 +1,6 @@
{
"Overview": "概述",
"Qc Item": "品質檢驗項目",
"Dashboard": "儀表板",

"dashboard": "儀表板",
"Raw Material": "原料",
"Purchase Order": "採購訂單",
"Pick Order": "提料單",
"View item In-out And inventory Ledger": "存貨",
"Inventory": "存貨",
"Delivery": "送貨",
"Delivery Order": "送貨單",
"Scheduling": "生產計劃",
"Demand Forecast Setting": "粗排設定",
"Demand Forecast": "粗排",
"FG & Material Demand Forecast Detail": "成品 & 原料粗排細節",
"Detail Scheduling": "細排",
"FG Production Schedule": "成品生產計劃",
"Settings": "設定",
"Edit": "編輯",

"Search Criteria": "搜尋條件",
@@ -46,7 +30,6 @@
"Supplier": "供應商",
"Purchase Order":"採購單",
"Demand Forecast":"需求預測",
"Purchase Order":"採購單",
"Pick Order":"挑選貨單",
"Deliver Order":"交貨單",
"Project":"專案",
@@ -74,5 +57,12 @@
"scheduling":"排程",
"settings": "設定",
"items": "物料",
"edit":"編輯"
"edit":"編輯",
"Edit Equipment Type":"設備類型詳情",
"equipmentType":"設備類型",
"Description":"描述",
"Details": "詳情",
"Equipment Type Details":"設備類型詳情",
"Save":"儲存",
"Cancel":"取消"
}

+ 3
- 2
src/i18n/zh/project.json Ver fichero

@@ -5,8 +5,9 @@
"Actions": "動作",
"Product": "產品",
"Details": "詳情",
"View BoM": "查看 BoM"

"View BoM": "查看 BoM",
"description": "描述",
"details": "詳情"





Cargando…
Cancelar
Guardar