Переглянути джерело

[rough schedule detail] update detail page

create_edit_user
jason.lam 3 місяці тому
джерело
коміт
031d646428
8 змінених файлів з 446 додано та 1 видалено
  1. +49
    -0
      src/app/(main)/scheduling/rough/edit/page.tsx
  2. +1
    -0
      src/components/Breadcrumb/Breadcrumb.tsx
  3. +39
    -0
      src/components/General/GeneralLoading.tsx
  4. +6
    -1
      src/components/RoughSchedule/RoughSchedileSearchView.tsx
  5. +101
    -0
      src/components/RoughScheduleDetail/DetailInfoCard.tsx
  6. +50
    -0
      src/components/RoughScheduleDetail/RoughScheduleDetailWrapper.tsx
  7. +199
    -0
      src/components/RoughScheduleDetail/RoughScheudleDetailView.tsx
  8. +1
    -0
      src/components/RoughScheduleDetail/index.ts

+ 49
- 0
src/app/(main)/scheduling/rough/edit/page.tsx Переглянути файл

@@ -0,0 +1,49 @@
import { TypeEnum } from "@/app/utils/typeEnum";
import RoughSchedule from "@/components/RoughSchedule";
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 RoughScheduleDetailView from "@/components/RoughScheduleDetail/RoughScheudleDetailView";

export const metadata: Metadata = {
title: "Rough Scheduling Detail",
};

const roughSchedulingDetail: React.FC = async () => {
const project = TypeEnum.PRODUCT
const { t } = await getServerI18n(project);
// preloadClaims();

return (
<>
<Stack
direction="row"
justifyContent="space-between"
flexWrap="wrap"
rowGap={2}
>
<Typography variant="h4" marginInlineEnd={2}>
{t("Rough Scheduling Detail")}
</Typography>
{/* <Button
variant="contained"
startIcon={<Add />}
LinkComponent={Link}
href="product/create"
>
{t("Create product")}
</Button> */}
</Stack>
<Suspense fallback={<RoughScheduleDetailView.Loading />}>
<RoughScheduleDetailView />
</Suspense>
</>
);
};

export default roughSchedulingDetail;

+ 1
- 0
src/components/Breadcrumb/Breadcrumb.tsx Переглянути файл

@@ -15,6 +15,7 @@ const pathToLabelMap: { [path: string]: string } = {
"/settings/qcItem": "Qc Item",
"/settings/rss": "Rough Schedule Setting",
"/scheduling/rough": "Rough Scheduling",
"/scheduling/rough/edit": "Rough Scheduling Detail",
"/scheduling/detail": "Detail Scheduling",
};



+ 39
- 0
src/components/General/GeneralLoading.tsx Переглянути файл

@@ -0,0 +1,39 @@
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";

export const GeneralLoading: 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 GeneralLoading;

+ 6
- 1
src/components/RoughSchedule/RoughSchedileSearchView.tsx Переглянути файл

@@ -74,12 +74,17 @@ const RSOverview: React.FC<Props> = ({ records }) => {
[router]
);

const onDetailClick = (record: any) => {
console.log("[debug] record", record);
router.push(`/scheduling/rough/edit?id=${record.id}`);
}

const columns = useMemo<Column<ItemsResult>[]>(
() => [
{
name: "id",
label: t("Details"),
onClick: ()=>{},
onClick: (record)=>onDetailClick(record),
buttonIcon: <EditNote />,
},
{


+ 101
- 0
src/components/RoughScheduleDetail/DetailInfoCard.tsx Переглянути файл

@@ -0,0 +1,101 @@
"use client";
import {
Box,
Card,
CardContent,
Grid,
Stack,
TextField,
Typography,
} from "@mui/material";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import InputDataGrid from "../InputDataGrid";
import {useCallback, useEffect, useMemo, useState} from "react";
import { GridColDef, GridRowModel } from "@mui/x-data-grid";
import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid";
import { TypeEnum } from "@/app/utils/typeEnum";
import { CreateItemInputs } from "@/app/api/settings/item/actions";
import {NumberInputProps} from "@/components/CreateItem/NumberInputProps";

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

const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing}) => {
const {
t,
i18n: { language },
} = useTranslation();

const {
register,
formState: { errors, defaultValues, touchedFields },
} = useFormContext<CreateItemInputs>();

const [details, setDetails] = useState(null);

useEffect(()=>{
console.log("[debug] record details", recordDetails)
setDetails(recordDetails);
},[recordDetails])

useEffect(()=>{
console.log("[debug] isEdit", isEditing)
},[isEditing])

return (
<Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}>
<Box>
<Typography variant="overline" display="block" marginBlockEnd={1}>
{t("Schedule Detail")}
</Typography>
<Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
<Grid item xs={6}>
<TextField
label={t("Date")}
fullWidth
{...register("scheduledPeriod", {
required: "name required!",
})}
defaultValue={details?.scheduledPeriod}
disabled={!isEditing}
error={Boolean(errors.name)}
helperText={errors.name?.message}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Total FG Type")}
fullWidth
{...register("productCount", {
required: "code required!",
})}
defaultValue={details?.productCount}
disabled={!isEditing}
error={Boolean(errors.code)}
helperText={errors.code?.message}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Total Estimated Production Count")}
fullWidth
{...register("productionCount", {
required: "type required!",
})}
disabled={!isEditing}
defaultValue={details?.productionCount}
error={Boolean(errors.type)}
helperText={errors.type?.message}
/>
</Grid>
</Grid>
</Box>
</CardContent>
</Card>
);
};
export default DetailInfoCard;

+ 50
- 0
src/components/RoughScheduleDetail/RoughScheduleDetailWrapper.tsx Переглянути файл

@@ -0,0 +1,50 @@
import { CreateItemInputs } from "@/app/api/settings/item/actions";
import { fetchItem } from "@/app/api/settings/item";
import GeneralLoading from "@/components/General/GeneralLoading";
import RoughScheduleDetailView from "@/components/RoughScheduleDetail/RoughScheudleDetailView";
interface SubComponents {
Loading: typeof GeneralLoading;
}

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

const RoughScheduleDetailWrapper: (id: { id: any }) => Promise<JSX.Element> = async ({ id: any }) => {
var result
var defaultValues: Partial<CreateItemInputs> | undefined
// console.log(type)
var qcChecks
if (id) {
result = await fetchItem(id);
const item = result.item
qcChecks = result.qcChecks
const activeRows = qcChecks.filter(it => it.isActive).map(i => i.id)
console.log(qcChecks)
defaultValues = {
type: item?.type,
id: item?.id,
code: item?.code,
name: item?.name,
description: item?.description,
remarks: item?.remarks,
shelfLife: item?.shelfLife,
countryOfOrigin: item?.countryOfOrigin,
maxQty: item?.maxQty,
qcChecks: qcChecks,
qcChecks_active: activeRows
};
}
return (
<RoughScheduleDetailView
isEditMode={Boolean(id)}
defaultValues={defaultValues}
qcChecks={qcChecks || []}
/>
);
};
RoughScheduleDetailWrapper.Loading = GeneralLoading;

export default RoughScheduleDetailWrapper;

+ 199
- 0
src/components/RoughScheduleDetail/RoughScheudleDetailView.tsx Переглянути файл

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

import { useCallback, useEffect, useMemo, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { useTranslation } from "react-i18next";
import {
CreateItemInputs,
saveItem,
} from "@/app/api/settings/item/actions";
import {
FormProvider,
SubmitErrorHandler,
SubmitHandler,
useForm,
} from "react-hook-form";
import { deleteDialog } from "../Swal/CustomAlerts";
import {Box, Button, Grid, Link, Stack, Tab, Tabs, TabsProps, Typography} from "@mui/material";
import {Add, Check, Close, EditNote} from "@mui/icons-material";
import {ItemQc, ItemsResult} from "@/app/api/settings/item";
import { useGridApiRef } from "@mui/x-data-grid";
import ProductDetails from "@/components/CreateItem/ProductDetails";
import QcDetails from "@/components/CreateItem/QcDetails";
import DetailInfoCard from "@/components/RoughScheduleDetail/DetailInfoCard";

type Props = {
isEditMode: boolean;
// type: TypeEnum;
defaultValues: Partial<CreateItemInputs> | undefined;
qcChecks: ItemQc[]
};

const RoughScheduleDetailView: React.FC<Props> = ({
isEditMode,
// type,
defaultValues,
qcChecks
}) => {
// console.log(type)
const apiRef = useGridApiRef();
const params = useSearchParams()
console.log(params.get("id"))
const [serverError, setServerError] = useState("");
const [tabIndex, setTabIndex] = useState(0);
const { t } = useTranslation();
const router = useRouter();
const [isEdit, setIsEdit] = useState(false);
//const title = "Rough Schedule Detail"
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 = "Product";
redirPath = "scheduling/rough/edit";
// }
// 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<CreateItemInputs>({
defaultValues: defaultValues ? defaultValues : {
},
});
const errors = formProps.formState.errors;

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

const handleCancel = () => {
router.replace(`/scheduling/rough`);
};

const onSubmit = useCallback<SubmitHandler<CreateItemInputs & {}>>(
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;
}
} 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<CreateItemInputs>>(
(errors) => {},
[]
);

const onClickEdit = () =>{
setIsEdit(!isEdit)
}

return (
<>
<FormProvider {...formProps}>
<Stack
spacing={2}
component="form"
onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
>
{/*<Grid>*/}
{/* <Typography mb={2} variant="h4">*/}
{/* {t(`${mode} ${title}`)}*/}
{/* </Typography>*/}
{/*</Grid>*/}
<DetailInfoCard
recordDetails={{
id: 1,
scheduledPeriod: "2025-05-11 to 2025-05-17",
scheduledAt: "2025-05-07",
productCount: 13,
productionCount: 21000
}}
isEditing={isEdit}
/>
<Stack
direction="row"
justifyContent="space-between"
flexWrap="wrap"
rowGap={2}
>
<Button
variant="contained"
onClick={onClickEdit}
// startIcon={<Add />}
//LinkComponent={Link}
//href="qcCategory/create"
>
{isEdit ? t("Save") : t("Edit")}
</Button>
</Stack>

<Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable">
<Tab label={t("View By Schedule")} iconPosition="end"/>
<Tab label={t("View By Material")} iconPosition="end" />
</Tabs>
{serverError && (
<Typography variant="body2" color="error" alignSelf="flex-end">
{serverError}
</Typography>
)}
{tabIndex === 0 && <ProductDetails />}
{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 RoughScheduleDetailView;

+ 1
- 0
src/components/RoughScheduleDetail/index.ts Переглянути файл

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

Завантаження…
Відмінити
Зберегти