|
- "use client";
-
- import { PurchaseQcResult, PurchaseQCInput } from "@/app/api/po/actions";
- import {
- Box,
- Card,
- CardContent,
- Checkbox,
- FormControl,
- FormControlLabel,
- Grid,
- Radio,
- RadioGroup,
- Stack,
- Tab,
- Tabs,
- TabsProps,
- TextField,
- Tooltip,
- Typography,
- } from "@mui/material";
- import { useFormContext, Controller } from "react-hook-form";
- import { useTranslation } from "react-i18next";
- import StyledDataGrid from "../StyledDataGrid";
- import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from "react";
- import {
- GridColDef,
- GridRowIdGetter,
- GridRowModel,
- useGridApiContext,
- GridRenderCellParams,
- GridRenderEditCellParams,
- useGridApiRef,
- GridRowSelectionModel,
- } from "@mui/x-data-grid";
- import InputDataGrid from "../InputDataGrid";
- import { TableRow } from "../InputDataGrid/InputDataGrid";
- import TwoLineCell from "./TwoLineCell";
- import QcSelect from "./QcSelect";
- import { GridEditInputCell } from "@mui/x-data-grid";
- import { StockInLine } from "@/app/api/po";
- import { stockInLineStatusMap } from "@/app/utils/formatUtil";
- import { fetchQcItemCheck, fetchQcResult } from "@/app/api/qc/actions";
- import { QcItemWithChecks, QcData } from "@/app/api/qc";
- import axios from "@/app/(main)/axios/axiosInstance";
- import { NEXT_PUBLIC_API_URL } from "@/config/api";
- import axiosInstance from "@/app/(main)/axios/axiosInstance";
- import EscalationComponent from "./EscalationComponent";
- import QcDataGrid from "./QCDatagrid";
- import StockInFormVer2 from "./StockInFormVer2";
- import { dummyEscalationHistory, dummyQCData } from "./dummyQcTemplate";
- import { ModalFormInput } from "@/app/api/po/actions";
- import { escape } from "lodash";
- import { PanoramaSharp } from "@mui/icons-material";
- import EscalationLogTable from "../DashboardPage/escalation/EscalationLogTable";
- import { EscalationResult } from "@/app/api/escalation";
-
- interface Props {
- itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] };
- qc: QcItemWithChecks[];
- disabled: boolean;
- qcItems: QcData[]
- setQcItems: Dispatch<SetStateAction<QcData[]>>
- }
-
- type EntryError =
- | {
- [field in keyof QcData]?: string;
- }
- | undefined;
-
- type QcRow = TableRow<Partial<QcData>, EntryError>;
- // fetchQcItemCheck
- const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcItems }) => {
- const { t } = useTranslation("purchaseOrder");
- const apiRef = useGridApiRef();
- const {
- register,
- formState: { errors, defaultValues, touchedFields },
- watch,
- control,
- setValue,
- getValues,
- reset,
- resetField,
- setError,
- clearErrors,
- } = useFormContext<PurchaseQCInput>();
-
- const [tabIndex, setTabIndex] = useState(0);
- const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel>();
- const [escalationHistory, setEscalationHistory] = useState(dummyEscalationHistory);
- // const [qcResult, setQcResult] = useState();
- const qcAccept = watch("qcAccept");
- const qcDecision = watch("qcDecision"); //WIP
- const qcResult = watch("qcResult");
- console.log(qcResult);
- // const [qcAccept, setQcAccept] = useState(true);
- // const [qcItems, setQcItems] = useState(dummyQCData)
-
- const column = useMemo<GridColDef[]>(
- () => [
- {
- field: "escalation",
- headerName: t("escalation"),
- flex: 1,
- },
- {
- field: "supervisor",
- headerName: t("supervisor"),
- flex: 1,
- },
- ], []
- )
- const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
- (_e, newValue) => {
- setTabIndex(newValue);
- },
- [],
- );
-
- //// validate form
- const accQty = watch("acceptQty");
- const validateForm = useCallback(() => {
- if (qcDecision == 1) {
- if (accQty > itemDetail.acceptedQty) {
- setError("acceptQty", {
- message: `${t("acceptQty must not greater than")} ${
- itemDetail.acceptedQty
- }`,
- type: "required",
- });
- }
- if (accQty < 1) {
- setError("acceptQty", {
- message: t("minimal value is 1"),
- type: "required",
- });
- }
- if (isNaN(accQty)) {
- setError("acceptQty", {
- message: t("value must be a number"),
- type: "required",
- });
- }
- }
- }, [accQty, qcDecision]);
-
- useEffect(() => {
- clearErrors();
- validateForm();
- }, [clearErrors, validateForm]);
-
- const columns = useMemo<GridColDef[]>(
- () => [
- {
- field: "escalation",
- headerName: t("escalation"),
- flex: 1,
- },
- {
- field: "supervisor",
- headerName: t("supervisor"),
- flex: 1,
- },
- ],
- [],
- );
- /// validate datagrid
- const validation = useCallback(
- (newRow: GridRowModel<QcRow>): EntryError => {
- const error: EntryError = {};
- // const { qcItemId, failQty } = newRow;
- return Object.keys(error).length > 0 ? error : undefined;
- },
- [],
- );
-
- function BooleanEditCell(params: GridRenderEditCellParams) {
- const apiRef = useGridApiContext();
- const { id, field, value } = params;
-
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- apiRef.current.setEditCellValue({ id, field, value: e.target.checked });
- apiRef.current.stopCellEditMode({ id, field }); // commit immediately
- };
-
- return <Checkbox checked={!!value} onChange={handleChange} sx={{ p: 0 }} />;
- }
-
- const qcColumns: GridColDef[] = [
- {
- field: "code",
- headerName: t("qcItem"),
- flex: 2,
- renderCell: (params) => (
- <Box>
- <b>{`${params.api.getRowIndexRelativeToVisibleRows(params.id) + 1}. ${params.value}`}</b><br/>
- {params.row.name}<br/>
- </Box>
- ),
- },
- {
- field: 'qcPassed',
- headerName: t("qcResult"),
- flex: 1.5,
- renderCell: (params) => {
- const currentValue = params.row;
- const index = params.api.getRowIndexRelativeToVisibleRows(params.id);
- // console.log(currentValue.row);
- return (
- <FormControl>
- <RadioGroup
- row
- aria-labelledby="demo-radio-buttons-group-label"
- value={currentValue.qcPassed === undefined ? "" : (currentValue.qcPassed ? "true" : "false")}
- // value={currentValue.qcPassed === undefined ? (currentValue.failQty!==undefined?(currentValue.failQty==0?"true":"false"):"") : (currentValue.qcPassed ? "true" : "false")}
- onChange={(e) => {
- const value = e.target.value;
- setQcItems((prev) =>
- prev.map((r): QcData => (r.id === params.id ? { ...r, qcPassed: value === "true" } : r))
- );
- // setValue(`qcResult.${index}.qcPassed`, value == "true");
- }}
- name={`qcPassed-${params.id}`}
- >
- <FormControlLabel
- value="true"
- control={<Radio />}
- label="合格"
- disabled={disabled || itemDetail.status == "escalated"}
- sx={{
- color: currentValue.qcPassed === true ? "green" : "inherit",
- "& .Mui-checked": {color: "green"}
- }}
- />
- <FormControlLabel
- value="false"
- control={<Radio />}
- label="不合格"
- disabled={disabled || itemDetail.status == "escalated"}
- sx={{
- color: currentValue.qcPassed === false ? "red" : "inherit",
- "& .Mui-checked": {color: "red"}
- }}
- />
- </RadioGroup>
- </FormControl>
- );
- },
- },
- {
- field: "failQty",
- headerName: t("failedQty"),
- flex: 1,
- // editable: true,
- renderCell: (params) => (
- <TextField
- type="number"
- size="small"
- value={!params.row.qcPassed? (params.value ?? '') : '0'}
- disabled={params.row.qcPassed || disabled || itemDetail.status == "escalated"}
- onChange={(e) => {
- const v = e.target.value;
- const next = v === '' ? undefined : Number(v);
- if (Number.isNaN(next)) return;
- setQcItems((prev) =>
- prev.map((r) => (r.id === params.id ? { ...r, failQty: next } : r))
- );
- // setValue(`failQty`,failQty);
- }}
- onClick={(e) => e.stopPropagation()}
- onMouseDown={(e) => e.stopPropagation()}
- onKeyDown={(e) => e.stopPropagation()}
- inputProps={{ min: 0 }}
- sx={{ width: '100%' }}
- />
- ),
- },
- {
- field: "remarks",
- headerName: t("remarks"),
- flex: 2,
- renderCell: (params) => (
- <TextField
- size="small"
- value={params.value ?? ''}
- disabled={disabled || itemDetail.status == "escalated"}
- onChange={(e) => {
- const remarks = e.target.value;
- // const next = v === '' ? undefined : Number(v);
- // if (Number.isNaN(next)) return;
- setQcItems((prev) =>
- prev.map((r) => (r.id === params.id ? { ...r, remarks: remarks } : r))
- );
- }}
- // {...register(`qcResult.${params.row.rowIndex}.remarks`, {
- // required: "remarks required!",
- // })}
- onClick={(e) => e.stopPropagation()}
- onMouseDown={(e) => e.stopPropagation()}
- onKeyDown={(e) => e.stopPropagation()}
- inputProps={{ min: 0 }}
- sx={{ width: '100%' }}
- />
- ),
- },
- ]
-
- // Set initial value for acceptQty
- useEffect(() => {
- if (itemDetail?.demandQty > 0) { //!== undefined) {
- setValue("acceptQty", itemDetail.demandQty); // THIS NEED TO UPDATE TO NOT USE DEMAND QTY
- } else {
- setValue("acceptQty", itemDetail?.acceptedQty);
- }
- }, [itemDetail?.demandQty, itemDetail?.acceptedQty, setValue]);
-
- // const [openCollapse, setOpenCollapse] = useState(false)
- const [isCollapsed, setIsCollapsed] = useState<boolean>(true);
-
- const onFailedOpenCollapse = useCallback((qcItems: PurchaseQcResult[]) => {
- const isFailed = qcItems.some((qc) => !qc.qcPassed)
- console.log(isFailed)
- if (isFailed) {
- setIsCollapsed(true)
- } else {
- setIsCollapsed(false)
- }
- }, [])
-
- // const handleRadioChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
- // const value = event.target.value === 'true';
- // setValue("qcAccept", value);
- // }, [setValue]);
-
-
- useEffect(() => {
- console.log("ItemDetail in QC:", itemDetail);
- console.log("Qc Result in QC:", qcResult);
-
- }, [itemDetail]);
-
- const setQcDecision = (status : string | undefined) => {
- const param = status?.toLowerCase();
- if (param !== undefined && param !== null) {
- if (param == "completed") {
- return 1;
- } else if (param == "rejected") {
- return 2;
- } else if (param == "escalated") {
- return 3;
- } else { return undefined; }
- } else {
- return undefined;
- }
- }
-
-
- useEffect(() => {
- // onFailedOpenCollapse(qcItems) // This function is no longer needed
- }, [qcItems]);
-
- return (
- <>
- <Grid container justifyContent="flex-start" alignItems="flex-start">
- <Grid
- container
- justifyContent="flex-start"
- alignItems="flex-start"
- spacing={2}
- sx={{ mt: 0.5 }}
- >
- <Grid item xs={12}>
- <Tabs
- value={tabIndex}
- onChange={handleTabChange}
- variant="scrollable"
- >
- <Tab label={t("QC Info")} iconPosition="end" />
- <Tab label={t("Escalation History")} iconPosition="end" />
- </Tabs>
- </Grid>
- {tabIndex == 0 && (
- <>
- <Grid item xs={12}>
-
- <Box sx={{ mb: 2, p: 2, backgroundColor: '#f5f5f5', borderRadius: 1 }}>
- <Typography variant="h5" component="h2" sx={{ fontWeight: 'bold', color: '#333' }}>
- Group A - 急凍貨類 (QCA1-MEAT01)
- </Typography>
- <Typography variant="subtitle1" sx={{ color: '#666' }}>
- <b>品檢類型</b>:IQC
- </Typography>
- <Typography variant="subtitle2" sx={{ color: '#666' }}>
- 記錄探測溫度的時間,請在1小時内完成卸貨盤點入庫,以保障食品安全<br/>
- 監察方法:目視檢查、嗅覺檢查和使用適當的食物溫度計,檢查食物溫度是否符合指標
- </Typography>
- </Box>
- {/* <QcDataGrid<ModalFormInput, QcData, EntryError>
- apiRef={apiRef}
- columns={qcColumns}
- _formKey="qcResult"
- validateRow={validation}
- /> */}
- <StyledDataGrid
- columns={qcColumns}
- rows={qcResult && qcResult.length > 0 ? qcResult : qcItems}
- // rows={disabled? qcResult:qcItems}
- autoHeight
- />
- </Grid>
- </>
- )}
- {tabIndex == 1 && (
- <>
- {/* <Grid item xs={12}>
- <StockInFormVer2
- itemDetail={itemDetail}
- disabled={false}
- />
- </Grid> */}
- {/* <Grid item xs={12}>
- <Typography variant="h6" display="block" marginBlockEnd={1}>
- {t("Escalation Info")}
- </Typography>
- </Grid> */}
- <Grid item xs={12}>
- <EscalationLogTable items={itemDetail.escResult || []}/>
- {/* <StyledDataGrid
- rows={escalationHistory}
- columns={columns}
- onRowSelectionModelChange={(newRowSelectionModel) => {
- setRowSelectionModel(newRowSelectionModel);
- }}
- /> */}
- </Grid>
- </>
- )}
- <Grid item xs={12}>
- <FormControl>
- <Controller
- name="qcDecision"
- // name="qcAccept"
- control={control}
- defaultValue={setQcDecision(itemDetail?.status)}
- // defaultValue={true}
- render={({ field }) => (
- <RadioGroup
- row
- aria-labelledby="demo-radio-buttons-group-label"
- {...field}
- value={field.value}
- // value={field.value?.toString() || "true"}
- onChange={(e) => {
- const value = e.target.value.toString();// === 'true';
- if (value != "1" && Boolean(errors.acceptQty)) {
- // if (!value && Boolean(errors.acceptQty)) {
- setValue("acceptQty", itemDetail.acceptedQty ?? 0);
- }
- field.onChange(value);
- }}
- >
- <FormControlLabel disabled={disabled}
- value="1" control={<Radio />} label="接受" />
- <Box sx={{mr:2}}>
- <TextField
- type="number"
- label={t("acceptQty")}
- sx={{ width: '150px' }}
- value={(qcDecision == 1)? accQty : 0 }
- // value={qcAccept? accQty : 0 }
- disabled={qcDecision != 1 || disabled}
- // disabled={!qcAccept || disabled}
- {...register("acceptQty", {
- required: "acceptQty required!",
- })}
- error={Boolean(errors.acceptQty)}
- helperText={errors.acceptQty?.message}
- />
- </Box>
- <FormControlLabel disabled={disabled}
- value="2" control={<Radio />}
- sx={{"& .Mui-checked": {color: "red"}}}
- label="不接受" />
- <FormControlLabel disabled={disabled}
- value="3" control={<Radio />}
- sx={{"& .Mui-checked": {color: "blue"}}}
- label="上報品檢結果" />
- </RadioGroup>
- )}
- />
- </FormControl>
- </Grid>
- {qcDecision == 3 && (
- // {!qcAccept && (
- <Grid item xs={12}>
- <EscalationComponent
- forSupervisor={false}
- isCollapsed={isCollapsed}
- setIsCollapsed={setIsCollapsed}
- />
- </Grid>)}
- {/* {qcAccept && <Grid item xs={12}>
- <Typography variant="h6" display="block" marginBlockEnd={1}>
- {t("Escalation Result")}
- </Typography>
- </Grid>
- <Grid item xs={12}>
- <EscalationComponent
- forSupervisor={true}
- isCollapsed={isCollapsed}
- setIsCollapsed={setIsCollapsed}
- />
- </Grid>} */}
- </Grid>
- </Grid>
- </>
- );
- };
- export default QcFormVer2;
|