Browse Source

update

create_edit_user
MSI\derek 2 months ago
parent
commit
f84e7dbbe0
13 changed files with 627 additions and 427 deletions
  1. +415
    -363
      package-lock.json
  2. +1
    -0
      package.json
  3. +6
    -3
      src/app/(main)/po/edit/page.tsx
  4. +0
    -3
      src/app/(main)/po/page.tsx
  5. +3
    -0
      src/components/PoDetail/EscalationForm.tsx
  6. +61
    -5
      src/components/PoDetail/PoDetail.tsx
  7. +18
    -7
      src/components/PoDetail/PoQcStockInModal.tsx
  8. +5
    -2
      src/components/PoDetail/PutawayForm.tsx
  9. +8
    -4
      src/components/PoDetail/QcForm.tsx
  10. +37
    -11
      src/components/PoDetail/QrModal.tsx
  11. +8
    -0
      src/components/PoDetail/StockInForm.tsx
  12. +59
    -26
      src/components/PoSearch/PoSearch.tsx
  13. +6
    -3
      src/components/PoSearch/PoSearchWrapper.tsx

+ 415
- 363
package-lock.json
File diff suppressed because it is too large
View File


+ 1
- 0
package.json View File

@@ -41,6 +41,7 @@
"react-intl": "^6.5.5", "react-intl": "^6.5.5",
"react-qr-barcode-scanner": "^2.1.5", "react-qr-barcode-scanner": "^2.1.5",
"react-select": "^5.8.0", "react-select": "^5.8.0",
"react-toastify": "^11.0.5",
"reactstrap": "^9.2.2", "reactstrap": "^9.2.2",
"styled-components": "^6.1.8", "styled-components": "^6.1.8",
"sweetalert2": "^11.10.3" "sweetalert2": "^11.10.3"


+ 6
- 3
src/app/(main)/po/edit/page.tsx View File

@@ -6,17 +6,18 @@ import { I18nProvider, getServerI18n } from "@/i18n";
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import isString from "lodash/isString"; import isString from "lodash/isString";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { Suspense } from "react";


type Props = {} & SearchParams; type Props = {} & SearchParams;


const PoEdit: React.FC<Props> = async ({ searchParams }) => { const PoEdit: React.FC<Props> = async ({ searchParams }) => {
const type = "po"; const type = "po";
const { t } = await getServerI18n(type); const { t } = await getServerI18n(type);
console.log(searchParams["id"])
console.log(searchParams["id"]);
const id = isString(searchParams["id"]) const id = isString(searchParams["id"])
? parseInt(searchParams["id"]) ? parseInt(searchParams["id"])
: undefined; : undefined;
console.log(id)
console.log(id);
if (!id) { if (!id) {
notFound(); notFound();
} }
@@ -24,7 +25,9 @@ const PoEdit: React.FC<Props> = async ({ searchParams }) => {
<> <>
{/* <Typography variant="h4">{t("Create Material")}</Typography> */} {/* <Typography variant="h4">{t("Create Material")}</Typography> */}
<I18nProvider namespaces={[type]}> <I18nProvider namespaces={[type]}>
<PoDetail id={id} />
<Suspense fallback={<PoDetail.Loading />}>
<PoDetail id={id} />
</Suspense>
</I18nProvider> </I18nProvider>
</> </>
); );


+ 0
- 3
src/app/(main)/po/page.tsx View File

@@ -26,9 +26,6 @@ const PurchaseOrder: React.FC = async () => {
flexWrap="wrap" flexWrap="wrap"
rowGap={2} rowGap={2}
> >
<Typography variant="h4" marginInlineEnd={2}>
{t("Purchase Order")}
</Typography>
{/* <Button {/* <Button
variant="contained" variant="contained"
startIcon={<Add />} startIcon={<Add />}


+ 3
- 0
src/components/PoDetail/EscalationForm.tsx View File

@@ -36,6 +36,7 @@ import { stockInLineStatusMap } from "@/app/utils/formatUtil";
interface Props { interface Props {
itemDetail: StockInLine; itemDetail: StockInLine;
// qc: QcItemWithChecks[]; // qc: QcItemWithChecks[];
disabled: boolean
} }
type EntryError = type EntryError =
| { | {
@@ -46,6 +47,7 @@ type EntryError =
const EscalationForm: React.FC<Props> = ({ const EscalationForm: React.FC<Props> = ({
// qc, // qc,
itemDetail, itemDetail,
disabled
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const apiRef = useGridApiRef(); const apiRef = useGridApiRef();
@@ -116,6 +118,7 @@ const EscalationForm: React.FC<Props> = ({
valueAsNumber: true, valueAsNumber: true,
max: itemDetail.acceptedQty max: itemDetail.acceptedQty
})} })}
disabled={disabled}
defaultValue={itemDetail.acceptedQty} defaultValue={itemDetail.acceptedQty}
error={Boolean(errors.acceptedQty)} error={Boolean(errors.acceptedQty)}
helperText={errors.acceptedQty?.message} helperText={errors.acceptedQty?.message}


+ 61
- 5
src/components/PoDetail/PoDetail.tsx View File

@@ -9,6 +9,7 @@ import {
import { import {
Box, Box,
Button, Button,
ButtonProps,
Collapse, Collapse,
Grid, Grid,
IconButton, IconButton,
@@ -72,6 +73,8 @@ import ReactQrCodeScannerModal, {
ScannerConfig, ScannerConfig,
} from "../ReactQrCodeScanner/ReactQrCodeScanner"; } from "../ReactQrCodeScanner/ReactQrCodeScanner";
import QrModal from "./QrModal"; import QrModal from "./QrModal";
import { PlayArrow } from "@mui/icons-material";
import DoneIcon from "@mui/icons-material/Done";


type Props = { type Props = {
po: PoResult; po: PoResult;
@@ -97,7 +100,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
const params = useSearchParams(); const params = useSearchParams();
const [currPoStatus, setCurrPoStatus] = useState(purchaseOrder.status); const [currPoStatus, setCurrPoStatus] = useState(purchaseOrder.status);


const handleComplete = useCallback(async () => {
const handleCompletePo = useCallback(async () => {
const checkRes = await checkPolAndCompletePo(purchaseOrder.id); const checkRes = await checkPolAndCompletePo(purchaseOrder.id);
console.log(checkRes); console.log(checkRes);
const newPo = await fetchPoInClient(purchaseOrder.id); const newPo = await fetchPoInClient(purchaseOrder.id);
@@ -226,6 +229,49 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
setPutAwayOpen(true); setPutAwayOpen(true);
}, []); }, []);


const buttonData = useMemo(() => {
switch (purchaseOrder.status.toLowerCase()) {
case "pending":
return {
buttonName: "start",
title: t("Do you want to start?"),
confirmButtonText: t("Start"),
successTitle: t("Start Success"),
errorTitle: t("Start Fail"),
buttonText: t("Start PO"),
buttonIcon: <PlayArrow />,
buttonColor: "success",
disabled: false,
onClick: handleStartPo,
};
case "receiving":
return {
buttonName: "complete",
title: t("Do you want to complete?"),
confirmButtonText: t("Complete"),
successTitle: t("Complete Success"),
errorTitle: t("Complete Fail"),
buttonText: t("Complete PO"),
buttonIcon: <DoneIcon />,
buttonColor: "info",
disabled: false,
onClick: handleCompletePo,
};
default:
return {
buttonName: "complete",
title: t("Do you want to complete?"),
confirmButtonText: t("Complete"),
successTitle: t("Complete Success"),
errorTitle: t("Complete Fail"),
buttonText: t("Complete PO"),
buttonIcon: <DoneIcon />,
buttonColor: "info",
disabled: true,
};
// break;
}
}, [purchaseOrder, handleStartPo, handleCompletePo]);
return ( return (
<> <>
<Stack <Stack
@@ -242,19 +288,29 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
</Grid> </Grid>
</Grid> </Grid>
<Grid container xs={12} justifyContent="start"> <Grid container xs={12} justifyContent="start">
{purchaseOrder.status.toLowerCase() === "pending" && (
<Grid item>
<Button
onClick={buttonData.onClick}
disabled={buttonData.disabled}
color={buttonData.buttonColor as ButtonProps["color"]}
startIcon={buttonData.buttonIcon}
>
{t(buttonData.buttonText)}
</Button>
</Grid>
{/* {purchaseOrder.status.toLowerCase() === "pending" && (
<Grid item> <Grid item>
<Button onClick={handleStartPo}>Start</Button> <Button onClick={handleStartPo}>Start</Button>
</Grid> </Grid>
)} )}
{purchaseOrder.status.toLowerCase() === "receiving" && ( {purchaseOrder.status.toLowerCase() === "receiving" && (
<Grid item> <Grid item>
<Button onClick={handleComplete}>Complete</Button>
<Button onClick={handleCompletePo}>Complete</Button>
</Grid> </Grid>
)}
)} */}
</Grid> </Grid>
{/* <Grid container xs={12} justifyContent="space-between"> {/* <Grid container xs={12} justifyContent="space-between">
<Button onClick={handleComplete}>Complete</Button>
<Button onClick={handleCompletePo}>Complete</Button>
</Grid> */} </Grid> */}
<Grid container xs={12} justifyContent="space-between"> <Grid container xs={12} justifyContent="space-between">
<Grid item xs={8}> <Grid item xs={8}>


+ 18
- 7
src/components/PoDetail/PoQcStockInModal.tsx View File

@@ -13,6 +13,7 @@ import {
Dispatch, Dispatch,
SetStateAction, SetStateAction,
useCallback, useCallback,
useContext,
useEffect, useEffect,
useMemo, useMemo,
useState, useState,
@@ -36,6 +37,8 @@ import dayjs from "dayjs";
import arraySupport from "dayjs/plugin/arraySupport"; import arraySupport from "dayjs/plugin/arraySupport";
import { downloadFile } from "@/app/utils/commonUtil"; import { downloadFile } from "@/app/utils/commonUtil";
import { fetchPoQrcode } from "@/app/api/pdf/actions"; import { fetchPoQrcode } from "@/app/api/pdf/actions";
import UploadContext from "../UploadProvider/UploadProvider";
import useUploadContext from "../UploadProvider/useUploadContext";


dayjs.extend(arraySupport); dayjs.extend(arraySupport);
interface CommonProps extends Omit<ModalProps, "children"> { interface CommonProps extends Omit<ModalProps, "children"> {
@@ -97,6 +100,8 @@ const PoQcStockInModal: React.FC<Props> = ({
qc, qc,
warehouse, warehouse,
}) => { }) => {
const { setIsUploading } = useUploadContext();

const [serverError, setServerError] = useState(""); const [serverError, setServerError] = useState("");
const { t } = useTranslation(); const { t } = useTranslation();
const params = useSearchParams(); const params = useSearchParams();
@@ -188,9 +193,10 @@ const PoQcStockInModal: React.FC<Props> = ({


const onSubmit = useCallback<SubmitHandler<ModalFormInput & {}>>( const onSubmit = useCallback<SubmitHandler<ModalFormInput & {}>>(
async (data, event) => { async (data, event) => {
setBtnIsLoading(true);
setIsUploading(true)
formProps.clearErrors(); formProps.clearErrors();
let hasErrors = false; let hasErrors = false;
setBtnIsLoading(true);
console.log(errors); console.log(errors);
console.log(data); console.log(data);
console.log(itemDetail); console.log(itemDetail);
@@ -240,10 +246,12 @@ const PoQcStockInModal: React.FC<Props> = ({
console.log(args); console.log(args);
setServerError(t("An error has occurred. Please try again later.")); setServerError(t("An error has occurred. Please try again later."));
setBtnIsLoading(false); setBtnIsLoading(false);
setIsUploading(false)
return; return;
} }
console.log(args); console.log(args);
// setBtnIsLoading(false); // setBtnIsLoading(false);
// setIsUploading(false)
// return // return
const res = await updateStockInLine(args); const res = await updateStockInLine(args);
if (Boolean(res.id)) { if (Boolean(res.id)) {
@@ -286,7 +294,7 @@ const PoQcStockInModal: React.FC<Props> = ({
} }
// add loading // add loading
setBtnIsLoading(false); setBtnIsLoading(false);
setIsUploading(false)
setItemDetail(undefined); setItemDetail(undefined);
closeHandler({}, "backdropClick"); closeHandler({}, "backdropClick");
} }
@@ -295,6 +303,7 @@ const PoQcStockInModal: React.FC<Props> = ({
} catch (e) { } catch (e) {
// server error // server error
setBtnIsLoading(false); setBtnIsLoading(false);
setIsUploading(false)
setServerError(t("An error has occurred. Please try again later.")); setServerError(t("An error has occurred. Please try again later."));
console.log(e); console.log(e);
} }
@@ -304,6 +313,7 @@ const PoQcStockInModal: React.FC<Props> = ({


const printQrcode = useCallback(async () => { const printQrcode = useCallback(async () => {
setBtnIsLoading(true); setBtnIsLoading(true);
setIsUploading(true)
const postData = { stockInLineIds: [itemDetail.id] }; const postData = { stockInLineIds: [itemDetail.id] };
// const postData = { stockInLineIds: [42,43,44] }; // const postData = { stockInLineIds: [42,43,44] };
const response = await fetchPoQrcode(postData); const response = await fetchPoQrcode(postData);
@@ -312,9 +322,10 @@ const PoQcStockInModal: React.FC<Props> = ({
downloadFile(new Uint8Array(response.blobValue), response.filename!!); downloadFile(new Uint8Array(response.blobValue), response.filename!!);
} }
setBtnIsLoading(false); setBtnIsLoading(false);
setIsUploading(false)
}, [itemDetail, fetchPoQrcode, downloadFile]); }, [itemDetail, fetchPoQrcode, downloadFile]);


const renderSubmitButton = useMemo((): Boolean => {
const renderSubmitButton = useMemo((): boolean => {
if (itemDetail) { if (itemDetail) {
const status = itemDetail.status; const status = itemDetail.status;
console.log(status); console.log(status);
@@ -355,16 +366,16 @@ const PoQcStockInModal: React.FC<Props> = ({
onSubmit={formProps.handleSubmit(onSubmit)} onSubmit={formProps.handleSubmit(onSubmit)}
> >
{itemDetail !== undefined && type === "qc" && ( {itemDetail !== undefined && type === "qc" && (
<QcForm qc={qc!!} itemDetail={itemDetail} />
<QcForm qc={qc!!} itemDetail={itemDetail} disabled={renderSubmitButton}/>
)} )}
{itemDetail !== undefined && type === "stockIn" && ( {itemDetail !== undefined && type === "stockIn" && (
<StockInForm itemDetail={itemDetail} />
<StockInForm itemDetail={itemDetail} disabled={renderSubmitButton}/>
)} )}
{itemDetail !== undefined && type === "escalation" && ( {itemDetail !== undefined && type === "escalation" && (
<EscalationForm itemDetail={itemDetail} />
<EscalationForm itemDetail={itemDetail} disabled={renderSubmitButton}/>
)} )}
{itemDetail !== undefined && type === "putaway" && ( {itemDetail !== undefined && type === "putaway" && (
<PutawayForm itemDetail={itemDetail} warehouse={warehouse!!} />
<PutawayForm itemDetail={itemDetail} warehouse={warehouse!!} disabled={renderSubmitButton}/>
)} )}
<Stack direction="row" justifyContent="flex-end" gap={1}> <Stack direction="row" justifyContent="flex-end" gap={1}>
{renderSubmitButton ? ( {renderSubmitButton ? (


+ 5
- 2
src/components/PoDetail/PutawayForm.tsx View File

@@ -48,6 +48,7 @@ import { QrCodeInfo } from "@/app/api/qrcode";
interface Props { interface Props {
itemDetail: StockInLine; itemDetail: StockInLine;
warehouse: WarehouseResult[]; warehouse: WarehouseResult[];
disabled: boolean
// qc: QcItemWithChecks[]; // qc: QcItemWithChecks[];
} }
type EntryError = type EntryError =
@@ -70,7 +71,7 @@ const style = {
width: "auto", width: "auto",
}; };


const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse }) => {
const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const apiRef = useGridApiRef(); const apiRef = useGridApiRef();
const { const {
@@ -326,12 +327,13 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse }) => {
valueAsNumber: true, valueAsNumber: true,
})} })}
// defaultValue={itemDetail.acceptedQty} // defaultValue={itemDetail.acceptedQty}
disabled={disabled}
error={Boolean(errors.acceptedQty)} error={Boolean(errors.acceptedQty)}
helperText={errors.acceptedQty?.message} helperText={errors.acceptedQty?.message}
/> />
</Grid> </Grid>
<Grid item xs={1}> <Grid item xs={1}>
<Button onClick={onOpenScanner}>bind</Button>
<Button disabled={disabled} onClick={onOpenScanner}>bind</Button>
</Grid> </Grid>
<Grid item xs={5.5}> <Grid item xs={5.5}>
{/* <Controller {/* <Controller
@@ -377,6 +379,7 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse }) => {
<TextField <TextField
{...params} {...params}
// label={"Select warehouse"} // label={"Select warehouse"}
disabled={disabled}
error={Boolean(errors.warehouseId?.message)} error={Boolean(errors.warehouseId?.message)}
helperText={errors.warehouseId?.message} helperText={errors.warehouseId?.message}
// helperText={warehouseHelperText} // helperText={warehouseHelperText}


+ 8
- 4
src/components/PoDetail/QcForm.tsx View File

@@ -40,6 +40,7 @@ import axiosInstance from "@/app/(main)/axios/axiosInstance";
interface Props { interface Props {
itemDetail: StockInLine; itemDetail: StockInLine;
qc: QcItemWithChecks[]; qc: QcItemWithChecks[];
disabled: boolean
} }
type EntryError = type EntryError =
| { | {
@@ -49,7 +50,7 @@ type EntryError =


type PoQcRow = TableRow<Partial<PurchaseQcResult>, EntryError>; type PoQcRow = TableRow<Partial<PurchaseQcResult>, EntryError>;
// fetchQcItemCheck // fetchQcItemCheck
const QcForm: React.FC<Props> = ({ qc, itemDetail }) => {
const QcForm: React.FC<Props> = ({ qc, itemDetail, disabled }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const apiRef = useGridApiRef(); const apiRef = useGridApiRef();
const { const {
@@ -102,7 +103,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => {
field: "qcItemId", field: "qcItemId",
headerName: "qc Check", headerName: "qc Check",
flex: 1, flex: 1,
editable: true,
editable: !disabled,
valueFormatter(params) { valueFormatter(params) {
const row = params.id ? params.api.getRow<PoQcRow>(params.id) : null; const row = params.id ? params.api.getRow<PoQcRow>(params.id) : null;
if (!row) { if (!row) {
@@ -150,7 +151,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => {
field: "failQty", field: "failQty",
headerName: "failQty", headerName: "failQty",
flex: 1, flex: 1,
editable: true,
editable: !disabled,
type: "number", type: "number",
renderEditCell(params: GridRenderEditCellParams<PoQcRow>) { renderEditCell(params: GridRenderEditCellParams<PoQcRow>) {
// const recordQty = params.row.qty // const recordQty = params.row.qty
@@ -226,7 +227,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => {
valueAsNumber: true, valueAsNumber: true,
max: itemDetail.acceptedQty, max: itemDetail.acceptedQty,
})} })}
// disabled
disabled={disabled}
error={Boolean(errors.acceptedQty)} error={Boolean(errors.acceptedQty)}
helperText={errors.acceptedQty?.message} helperText={errors.acceptedQty?.message}
/> />
@@ -253,6 +254,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => {
required: "sampleRate required!", required: "sampleRate required!",
valueAsNumber: true, valueAsNumber: true,
})} })}
disabled={disabled}
error={Boolean(errors.sampleRate)} error={Boolean(errors.sampleRate)}
helperText={errors.sampleRate?.message} helperText={errors.sampleRate?.message}
/> />
@@ -266,6 +268,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => {
required: "sampleWeight required!", required: "sampleWeight required!",
valueAsNumber: true, valueAsNumber: true,
})} })}
disabled={disabled}
error={Boolean(errors.sampleWeight)} error={Boolean(errors.sampleWeight)}
helperText={errors.sampleWeight?.message} helperText={errors.sampleWeight?.message}
/> />
@@ -279,6 +282,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => {
required: "totalWeight required!", required: "totalWeight required!",
valueAsNumber: true, valueAsNumber: true,
})} })}
disabled={disabled}
error={Boolean(errors.totalWeight)} error={Boolean(errors.totalWeight)}
helperText={errors.totalWeight?.message} helperText={errors.totalWeight?.message}
/> />


+ 37
- 11
src/components/PoDetail/QrModal.tsx View File

@@ -1,6 +1,6 @@
"use client"; "use client";


import { Box, Button, Grid, Modal, ModalProps, Stack } from "@mui/material";
import { Box, Button, Grid, Modal, ModalProps, Stack, Typography } from "@mui/material";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import ReactQrCodeScanner, { import ReactQrCodeScanner, {
ScannerConfig, ScannerConfig,
@@ -18,6 +18,7 @@ import { WarehouseResult } from "@/app/api/warehouse";
import { QrCodeInfo } from "@/app/api/qrcode"; import { QrCodeInfo } from "@/app/api/qrcode";
import { Check } from "@mui/icons-material"; import { Check } from "@mui/icons-material";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useSearchParams } from "next/navigation";


interface Props extends Omit<ModalProps, "children"> { interface Props extends Omit<ModalProps, "children"> {
warehouse: WarehouseResult[]; warehouse: WarehouseResult[];
@@ -36,8 +37,10 @@ const style = {
const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => { const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [serverError, setServerError] = useState(""); const [serverError, setServerError] = useState("");
const params = useSearchParams();
const formProps = useForm<ModalFormInput>({ const formProps = useForm<ModalFormInput>({
defaultValues: { defaultValues: {
// acceptedQty
// ...itemDetail, // ...itemDetail,
}, },
}); });
@@ -70,13 +73,27 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {
); );


const [itemDetail, setItemDetail] = useState<StockInLine>(); const [itemDetail, setItemDetail] = useState<StockInLine>();

const [disabledSubmit, setDisabledSubmit] = useState(false);
const [unavailableText, setUnavailableText] = useState<string | undefined>(undefined)
const fetchStockInLine = useCallback( const fetchStockInLine = useCallback(
async (stockInLineId: number) => { async (stockInLineId: number) => {
setUnavailableText(undefined)
const res = await fetchStockInLineInfo(stockInLineId); const res = await fetchStockInLineInfo(stockInLineId);
setItemDetail(res);
if (res.status.toLowerCase() === "received") {
console.log(res.acceptedQty)
formProps.setValue("acceptedQty", res.acceptedQty)
setDisabledSubmit(false)
setItemDetail(res);
} else if (res.status.toLowerCase() === "completed") {
setDisabledSubmit(true)
} else {
//
setUnavailableText("Item Not Available")
setDisabledSubmit(true)
}
// return
}, },
[fetchStockInLineInfo]
[formProps, itemDetail, fetchStockInLineInfo]
); );


useEffect(() => { useEffect(() => {
@@ -86,8 +103,11 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {
const onSubmit = useCallback<SubmitHandler<ModalFormInput & {}>>( const onSubmit = useCallback<SubmitHandler<ModalFormInput & {}>>(
async (data, event) => { async (data, event) => {
let hasErrors = false; let hasErrors = false;
console.log("errors");
console.log(errors); console.log(errors);
console.log("data");
console.log(data); console.log(data);
console.log("itemDetail");
console.log(itemDetail); console.log(itemDetail);
try { try {
// add checking // add checking
@@ -95,11 +115,13 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {


//////////////////////// modify this mess later ////////////////////// //////////////////////// modify this mess later //////////////////////
const args = { const args = {
// id: itemDetail.id,
// purchaseOrderId: parseInt(params.get("id")!!),
// purchaseOrderLineId: itemDetail.purchaseOrderLineId,
// itemId: itemDetail.itemId,
// ...data,
id: itemDetail?.id,
purchaseOrderId: parseInt(params.get("id")!!),
purchaseOrderLineId: itemDetail?.purchaseOrderLineId,
itemId: itemDetail?.itemId,
acceptedQty: data.acceptedQty,
warehouseId: data.warehouseId,
// ...data,
// productionDate: productionDate, // productionDate: productionDate,
} as StockInLineEntry & ModalFormInput; } as StockInLineEntry & ModalFormInput;
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@@ -139,20 +161,24 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {
<Grid container xs={12}> <Grid container xs={12}>
<Grid item xs={12}> <Grid item xs={12}>
{itemDetail != undefined ? ( {itemDetail != undefined ? (
unavailableText != undefined ? <Typography variant="h4" marginInlineEnd={2}>{unavailableText}</Typography>
: (
<> <>
<PutawayForm itemDetail={itemDetail} warehouse={warehouse} />
<PutawayForm itemDetail={itemDetail} warehouse={warehouse} disabled={false}/>
<Stack direction="row" justifyContent="flex-end" gap={1}> <Stack direction="row" justifyContent="flex-end" gap={1}>
<Button <Button
name="submit" name="submit"
variant="contained" variant="contained"
startIcon={<Check />} startIcon={<Check />}
type="submit" type="submit"
// disabled={submitDisabled}
disabled={disabledSubmit}
> >
{t("submit")} {t("submit")}
</Button> </Button>
</Stack> </Stack>
</> </>

)
) : ( ) : (
<ReactQrCodeScanner scannerConfig={scannerConfig} /> <ReactQrCodeScanner scannerConfig={scannerConfig} />
)} )}


+ 8
- 0
src/components/PoDetail/StockInForm.tsx View File

@@ -43,6 +43,7 @@ import dayjs from "dayjs";
interface Props { interface Props {
itemDetail: StockInLine; itemDetail: StockInLine;
// qc: QcItemWithChecks[]; // qc: QcItemWithChecks[];
disabled: boolean
} }
type EntryError = type EntryError =
| { | {
@@ -55,6 +56,7 @@ type EntryError =
const StockInForm: React.FC<Props> = ({ const StockInForm: React.FC<Props> = ({
// qc, // qc,
itemDetail, itemDetail,
disabled
}) => { }) => {
const { const {
t, t,
@@ -116,6 +118,7 @@ const StockInForm: React.FC<Props> = ({
{...register("productLotNo", { {...register("productLotNo", {
// required: "productLotNo required!", // required: "productLotNo required!",
})} })}
disabled={disabled}
// error={Boolean(errors.productLotNo)} // error={Boolean(errors.productLotNo)}
// helperText={errors.productLotNo?.message} // helperText={errors.productLotNo?.message}
/> />
@@ -136,6 +139,7 @@ const StockInForm: React.FC<Props> = ({
sx={{ width: "100%" }} sx={{ width: "100%" }}
label={t("receiptDate")} label={t("receiptDate")}
value={dayjs(watch("receiptDate"))} value={dayjs(watch("receiptDate"))}
disabled={disabled}
onChange={(date) => { onChange={(date) => {
if (!date) return if (!date) return
// setValue("receiptDate", date.format(INPUT_DATE_FORMAT)); // setValue("receiptDate", date.format(INPUT_DATE_FORMAT));
@@ -162,6 +166,7 @@ const StockInForm: React.FC<Props> = ({
{...register("acceptedQty", { {...register("acceptedQty", {
required: "acceptedQty required!", required: "acceptedQty required!",
})} })}
disabled={disabled}
error={Boolean(errors.acceptedQty)} error={Boolean(errors.acceptedQty)}
helperText={errors.acceptedQty?.message} helperText={errors.acceptedQty?.message}
/> />
@@ -173,6 +178,7 @@ const StockInForm: React.FC<Props> = ({
// {...register("acceptedWeight", { // {...register("acceptedWeight", {
// required: "acceptedWeight required!", // required: "acceptedWeight required!",
// })} // })}
disabled={disabled}
error={Boolean(errors.acceptedWeight)} error={Boolean(errors.acceptedWeight)}
helperText={errors.acceptedWeight?.message} helperText={errors.acceptedWeight?.message}
/> />
@@ -193,6 +199,7 @@ const StockInForm: React.FC<Props> = ({
sx={{ width: "100%" }} sx={{ width: "100%" }}
label={t("productionDate")} label={t("productionDate")}
value={productionDate ? dayjs(productionDate) : undefined} value={productionDate ? dayjs(productionDate) : undefined}
disabled={disabled}
onChange={(date) => { onChange={(date) => {
if (!date) return if (!date) return
setValue("productionDate", date.format(INPUT_DATE_FORMAT)); setValue("productionDate", date.format(INPUT_DATE_FORMAT));
@@ -228,6 +235,7 @@ const StockInForm: React.FC<Props> = ({
sx={{ width: "100%" }} sx={{ width: "100%" }}
label={t("expiryDate")} label={t("expiryDate")}
value={expiryDate ? dayjs(expiryDate) : undefined} value={expiryDate ? dayjs(expiryDate) : undefined}
disabled={disabled}
onChange={(date) => { onChange={(date) => {
console.log(date) console.log(date)
if (!date) return if (!date) return


+ 59
- 26
src/components/PoSearch/PoSearch.tsx View File

@@ -7,14 +7,18 @@ import { useRouter, useSearchParams } from "next/navigation";
import SearchBox, { Criterion } from "../SearchBox"; import SearchBox, { Criterion } from "../SearchBox";
import SearchResults, { Column } from "../SearchResults"; import SearchResults, { Column } from "../SearchResults";
import { EditNote } from "@mui/icons-material"; import { EditNote } from "@mui/icons-material";
import { Button, Grid, Tab, Tabs, TabsProps, Typography } from "@mui/material";
import QrModal from "../PoDetail/QrModal";
import { WarehouseResult } from "@/app/api/warehouse";


type Props = { type Props = {
po: PoResult[]; po: PoResult[];
warehouse: WarehouseResult[];
}; };
type SearchQuery = Partial<Omit<PoResult, "id">>; type SearchQuery = Partial<Omit<PoResult, "id">>;
type SearchParamNames = keyof SearchQuery; type SearchParamNames = keyof SearchQuery;


const PoSearch: React.FC<Props> = ({ po }) => {
const PoSearch: React.FC<Props> = ({ po, warehouse }) => {
const [filteredPo, setFilteredPo] = useState<PoResult[]>(po); const [filteredPo, setFilteredPo] = useState<PoResult[]>(po);
const { t } = useTranslation("po"); const { t } = useTranslation("po");
const router = useRouter(); const router = useRouter();
@@ -27,7 +31,6 @@ const PoSearch: React.FC<Props> = ({ po }) => {
return searchCriteria; return searchCriteria;
}, [t, po]); }, [t, po]);


const onDetailClick = useCallback( const onDetailClick = useCallback(
(po: PoResult) => { (po: PoResult) => {
router.push(`/po/edit?id=${po.id}`); router.push(`/po/edit?id=${po.id}`);
@@ -35,10 +38,7 @@ const PoSearch: React.FC<Props> = ({ po }) => {
[router] [router]
); );


const onDeleteClick = useCallback(
(po: PoResult) => {},
[router]
);
const onDeleteClick = useCallback((po: PoResult) => {}, [router]);


const columns = useMemo<Column<PoResult>[]>( const columns = useMemo<Column<PoResult>[]>(
() => [ () => [
@@ -68,12 +68,12 @@ const PoSearch: React.FC<Props> = ({ po }) => {
// name: "name", // name: "name",
// label: t("Name"), // label: t("Name"),
// }, // },
// {
// name: "action",
// label: t(""),
// buttonIcon: <GridDeleteIcon />,
// onClick: onDeleteClick,
// },
// {
// name: "action",
// label: t(""),
// buttonIcon: <GridDeleteIcon />,
// onClick: onDeleteClick,
// },
], ],
[filteredPo] [filteredPo]
); );
@@ -82,23 +82,56 @@ const PoSearch: React.FC<Props> = ({ po }) => {
setFilteredPo(po); setFilteredPo(po);
}, [po]); }, [po]);


const [isOpenScanner, setOpenScanner] = useState(false);
const onOpenScanner = useCallback(() => {
setOpenScanner(true);
}, []);

const onCloseScanner = useCallback(() => {
setOpenScanner(false);
}, []);

return ( return (
<> <>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
setFilteredPo(
po.filter((p) => {
return (
p.code.toLowerCase().includes(query.code.toLowerCase())
// p.name.toLowerCase().includes(query.name.toLowerCase())
<Grid container>
<Grid item xs={8}>
<Typography variant="h4" marginInlineEnd={2}>
{t("Purchase Order")}
</Typography>
</Grid>
<Grid
item
xs={4}
display="flex"
justifyContent="end"
alignItems="end"
>
<QrModal
open={isOpenScanner}
onClose={onCloseScanner}
warehouse={warehouse}
/>
<Button onClick={onOpenScanner}>bind</Button>
</Grid>
</Grid>
<>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
setFilteredPo(
po.filter((p) => {
return p.code
.toLowerCase()
.includes(query.code.toLowerCase());
// p.name.toLowerCase().includes(query.name.toLowerCase())
})
); );
})
);
}}
onReset={onReset}
/>
<SearchResults<PoResult> items={filteredPo} columns={columns}/>
}}
onReset={onReset}
/>
<SearchResults<PoResult> items={filteredPo} columns={columns} />
</>
</> </>
); );
}; };


+ 6
- 3
src/components/PoSearch/PoSearchWrapper.tsx View File

@@ -10,6 +10,7 @@ import { fetchPoList, PoResult } from "@/app/api/po";
import dayjs from "dayjs"; import dayjs from "dayjs";
import arraySupport from "dayjs/plugin/arraySupport"; import arraySupport from "dayjs/plugin/arraySupport";
import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import { fetchWarehouseList } from "@/app/api/warehouse";
dayjs.extend(arraySupport); dayjs.extend(arraySupport);


interface SubComponents { interface SubComponents {
@@ -26,9 +27,11 @@ const PoSearchWrapper: React.FC<Props> & SubComponents = async (
} }
) => { ) => {
const [ const [
po
po,
warehouse,
] = await Promise.all([ ] = await Promise.all([
fetchPoList()
fetchPoList(),
fetchWarehouseList(),
]); ]);
console.log(po) console.log(po)
const fixPoDate = po.map((p) => { const fixPoDate = po.map((p) => {
@@ -37,7 +40,7 @@ const PoSearchWrapper: React.FC<Props> & SubComponents = async (
orderDate: dayjs(p.orderDate).format(OUTPUT_DATE_FORMAT) orderDate: dayjs(p.orderDate).format(OUTPUT_DATE_FORMAT)
}) })
}) })
return <PoSearch po={fixPoDate} />;
return <PoSearch po={fixPoDate} warehouse={warehouse}/>;
}; };


PoSearchWrapper.Loading = PoSearchLoading; PoSearchWrapper.Loading = PoSearchLoading;


Loading…
Cancel
Save