@@ -41,6 +41,7 @@ | |||
"react-intl": "^6.5.5", | |||
"react-qr-barcode-scanner": "^2.1.5", | |||
"react-select": "^5.8.0", | |||
"react-toastify": "^11.0.5", | |||
"reactstrap": "^9.2.2", | |||
"styled-components": "^6.1.8", | |||
"sweetalert2": "^11.10.3" | |||
@@ -6,17 +6,18 @@ import { I18nProvider, getServerI18n } from "@/i18n"; | |||
import { Typography } from "@mui/material"; | |||
import isString from "lodash/isString"; | |||
import { notFound } from "next/navigation"; | |||
import { Suspense } from "react"; | |||
type Props = {} & SearchParams; | |||
const PoEdit: React.FC<Props> = async ({ searchParams }) => { | |||
const type = "po"; | |||
const { t } = await getServerI18n(type); | |||
console.log(searchParams["id"]) | |||
console.log(searchParams["id"]); | |||
const id = isString(searchParams["id"]) | |||
? parseInt(searchParams["id"]) | |||
: undefined; | |||
console.log(id) | |||
console.log(id); | |||
if (!id) { | |||
notFound(); | |||
} | |||
@@ -24,7 +25,9 @@ const PoEdit: React.FC<Props> = async ({ searchParams }) => { | |||
<> | |||
{/* <Typography variant="h4">{t("Create Material")}</Typography> */} | |||
<I18nProvider namespaces={[type]}> | |||
<PoDetail id={id} /> | |||
<Suspense fallback={<PoDetail.Loading />}> | |||
<PoDetail id={id} /> | |||
</Suspense> | |||
</I18nProvider> | |||
</> | |||
); | |||
@@ -26,9 +26,6 @@ const PurchaseOrder: React.FC = async () => { | |||
flexWrap="wrap" | |||
rowGap={2} | |||
> | |||
<Typography variant="h4" marginInlineEnd={2}> | |||
{t("Purchase Order")} | |||
</Typography> | |||
{/* <Button | |||
variant="contained" | |||
startIcon={<Add />} | |||
@@ -36,6 +36,7 @@ import { stockInLineStatusMap } from "@/app/utils/formatUtil"; | |||
interface Props { | |||
itemDetail: StockInLine; | |||
// qc: QcItemWithChecks[]; | |||
disabled: boolean | |||
} | |||
type EntryError = | |||
| { | |||
@@ -46,6 +47,7 @@ type EntryError = | |||
const EscalationForm: React.FC<Props> = ({ | |||
// qc, | |||
itemDetail, | |||
disabled | |||
}) => { | |||
const { t } = useTranslation(); | |||
const apiRef = useGridApiRef(); | |||
@@ -116,6 +118,7 @@ const EscalationForm: React.FC<Props> = ({ | |||
valueAsNumber: true, | |||
max: itemDetail.acceptedQty | |||
})} | |||
disabled={disabled} | |||
defaultValue={itemDetail.acceptedQty} | |||
error={Boolean(errors.acceptedQty)} | |||
helperText={errors.acceptedQty?.message} | |||
@@ -9,6 +9,7 @@ import { | |||
import { | |||
Box, | |||
Button, | |||
ButtonProps, | |||
Collapse, | |||
Grid, | |||
IconButton, | |||
@@ -72,6 +73,8 @@ import ReactQrCodeScannerModal, { | |||
ScannerConfig, | |||
} from "../ReactQrCodeScanner/ReactQrCodeScanner"; | |||
import QrModal from "./QrModal"; | |||
import { PlayArrow } from "@mui/icons-material"; | |||
import DoneIcon from "@mui/icons-material/Done"; | |||
type Props = { | |||
po: PoResult; | |||
@@ -97,7 +100,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => { | |||
const params = useSearchParams(); | |||
const [currPoStatus, setCurrPoStatus] = useState(purchaseOrder.status); | |||
const handleComplete = useCallback(async () => { | |||
const handleCompletePo = useCallback(async () => { | |||
const checkRes = await checkPolAndCompletePo(purchaseOrder.id); | |||
console.log(checkRes); | |||
const newPo = await fetchPoInClient(purchaseOrder.id); | |||
@@ -226,6 +229,49 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => { | |||
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 ( | |||
<> | |||
<Stack | |||
@@ -242,19 +288,29 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => { | |||
</Grid> | |||
</Grid> | |||
<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> | |||
<Button onClick={handleStartPo}>Start</Button> | |||
</Grid> | |||
)} | |||
{purchaseOrder.status.toLowerCase() === "receiving" && ( | |||
<Grid item> | |||
<Button onClick={handleComplete}>Complete</Button> | |||
<Button onClick={handleCompletePo}>Complete</Button> | |||
</Grid> | |||
)} | |||
)} */} | |||
</Grid> | |||
{/* <Grid container xs={12} justifyContent="space-between"> | |||
<Button onClick={handleComplete}>Complete</Button> | |||
<Button onClick={handleCompletePo}>Complete</Button> | |||
</Grid> */} | |||
<Grid container xs={12} justifyContent="space-between"> | |||
<Grid item xs={8}> | |||
@@ -13,6 +13,7 @@ import { | |||
Dispatch, | |||
SetStateAction, | |||
useCallback, | |||
useContext, | |||
useEffect, | |||
useMemo, | |||
useState, | |||
@@ -36,6 +37,8 @@ import dayjs from "dayjs"; | |||
import arraySupport from "dayjs/plugin/arraySupport"; | |||
import { downloadFile } from "@/app/utils/commonUtil"; | |||
import { fetchPoQrcode } from "@/app/api/pdf/actions"; | |||
import UploadContext from "../UploadProvider/UploadProvider"; | |||
import useUploadContext from "../UploadProvider/useUploadContext"; | |||
dayjs.extend(arraySupport); | |||
interface CommonProps extends Omit<ModalProps, "children"> { | |||
@@ -97,6 +100,8 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
qc, | |||
warehouse, | |||
}) => { | |||
const { setIsUploading } = useUploadContext(); | |||
const [serverError, setServerError] = useState(""); | |||
const { t } = useTranslation(); | |||
const params = useSearchParams(); | |||
@@ -188,9 +193,10 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
const onSubmit = useCallback<SubmitHandler<ModalFormInput & {}>>( | |||
async (data, event) => { | |||
setBtnIsLoading(true); | |||
setIsUploading(true) | |||
formProps.clearErrors(); | |||
let hasErrors = false; | |||
setBtnIsLoading(true); | |||
console.log(errors); | |||
console.log(data); | |||
console.log(itemDetail); | |||
@@ -240,10 +246,12 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
console.log(args); | |||
setServerError(t("An error has occurred. Please try again later.")); | |||
setBtnIsLoading(false); | |||
setIsUploading(false) | |||
return; | |||
} | |||
console.log(args); | |||
// setBtnIsLoading(false); | |||
// setIsUploading(false) | |||
// return | |||
const res = await updateStockInLine(args); | |||
if (Boolean(res.id)) { | |||
@@ -286,7 +294,7 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
} | |||
// add loading | |||
setBtnIsLoading(false); | |||
setIsUploading(false) | |||
setItemDetail(undefined); | |||
closeHandler({}, "backdropClick"); | |||
} | |||
@@ -295,6 +303,7 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
} catch (e) { | |||
// server error | |||
setBtnIsLoading(false); | |||
setIsUploading(false) | |||
setServerError(t("An error has occurred. Please try again later.")); | |||
console.log(e); | |||
} | |||
@@ -304,6 +313,7 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
const printQrcode = useCallback(async () => { | |||
setBtnIsLoading(true); | |||
setIsUploading(true) | |||
const postData = { stockInLineIds: [itemDetail.id] }; | |||
// const postData = { stockInLineIds: [42,43,44] }; | |||
const response = await fetchPoQrcode(postData); | |||
@@ -312,9 +322,10 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
downloadFile(new Uint8Array(response.blobValue), response.filename!!); | |||
} | |||
setBtnIsLoading(false); | |||
setIsUploading(false) | |||
}, [itemDetail, fetchPoQrcode, downloadFile]); | |||
const renderSubmitButton = useMemo((): Boolean => { | |||
const renderSubmitButton = useMemo((): boolean => { | |||
if (itemDetail) { | |||
const status = itemDetail.status; | |||
console.log(status); | |||
@@ -355,16 +366,16 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
onSubmit={formProps.handleSubmit(onSubmit)} | |||
> | |||
{itemDetail !== undefined && type === "qc" && ( | |||
<QcForm qc={qc!!} itemDetail={itemDetail} /> | |||
<QcForm qc={qc!!} itemDetail={itemDetail} disabled={renderSubmitButton}/> | |||
)} | |||
{itemDetail !== undefined && type === "stockIn" && ( | |||
<StockInForm itemDetail={itemDetail} /> | |||
<StockInForm itemDetail={itemDetail} disabled={renderSubmitButton}/> | |||
)} | |||
{itemDetail !== undefined && type === "escalation" && ( | |||
<EscalationForm itemDetail={itemDetail} /> | |||
<EscalationForm itemDetail={itemDetail} disabled={renderSubmitButton}/> | |||
)} | |||
{itemDetail !== undefined && type === "putaway" && ( | |||
<PutawayForm itemDetail={itemDetail} warehouse={warehouse!!} /> | |||
<PutawayForm itemDetail={itemDetail} warehouse={warehouse!!} disabled={renderSubmitButton}/> | |||
)} | |||
<Stack direction="row" justifyContent="flex-end" gap={1}> | |||
{renderSubmitButton ? ( | |||
@@ -48,6 +48,7 @@ import { QrCodeInfo } from "@/app/api/qrcode"; | |||
interface Props { | |||
itemDetail: StockInLine; | |||
warehouse: WarehouseResult[]; | |||
disabled: boolean | |||
// qc: QcItemWithChecks[]; | |||
} | |||
type EntryError = | |||
@@ -70,7 +71,7 @@ const style = { | |||
width: "auto", | |||
}; | |||
const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse }) => { | |||
const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => { | |||
const { t } = useTranslation(); | |||
const apiRef = useGridApiRef(); | |||
const { | |||
@@ -326,12 +327,13 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse }) => { | |||
valueAsNumber: true, | |||
})} | |||
// defaultValue={itemDetail.acceptedQty} | |||
disabled={disabled} | |||
error={Boolean(errors.acceptedQty)} | |||
helperText={errors.acceptedQty?.message} | |||
/> | |||
</Grid> | |||
<Grid item xs={1}> | |||
<Button onClick={onOpenScanner}>bind</Button> | |||
<Button disabled={disabled} onClick={onOpenScanner}>bind</Button> | |||
</Grid> | |||
<Grid item xs={5.5}> | |||
{/* <Controller | |||
@@ -377,6 +379,7 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse }) => { | |||
<TextField | |||
{...params} | |||
// label={"Select warehouse"} | |||
disabled={disabled} | |||
error={Boolean(errors.warehouseId?.message)} | |||
helperText={errors.warehouseId?.message} | |||
// helperText={warehouseHelperText} | |||
@@ -40,6 +40,7 @@ import axiosInstance from "@/app/(main)/axios/axiosInstance"; | |||
interface Props { | |||
itemDetail: StockInLine; | |||
qc: QcItemWithChecks[]; | |||
disabled: boolean | |||
} | |||
type EntryError = | |||
| { | |||
@@ -49,7 +50,7 @@ type EntryError = | |||
type PoQcRow = TableRow<Partial<PurchaseQcResult>, EntryError>; | |||
// fetchQcItemCheck | |||
const QcForm: React.FC<Props> = ({ qc, itemDetail }) => { | |||
const QcForm: React.FC<Props> = ({ qc, itemDetail, disabled }) => { | |||
const { t } = useTranslation(); | |||
const apiRef = useGridApiRef(); | |||
const { | |||
@@ -102,7 +103,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => { | |||
field: "qcItemId", | |||
headerName: "qc Check", | |||
flex: 1, | |||
editable: true, | |||
editable: !disabled, | |||
valueFormatter(params) { | |||
const row = params.id ? params.api.getRow<PoQcRow>(params.id) : null; | |||
if (!row) { | |||
@@ -150,7 +151,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => { | |||
field: "failQty", | |||
headerName: "failQty", | |||
flex: 1, | |||
editable: true, | |||
editable: !disabled, | |||
type: "number", | |||
renderEditCell(params: GridRenderEditCellParams<PoQcRow>) { | |||
// const recordQty = params.row.qty | |||
@@ -226,7 +227,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => { | |||
valueAsNumber: true, | |||
max: itemDetail.acceptedQty, | |||
})} | |||
// disabled | |||
disabled={disabled} | |||
error={Boolean(errors.acceptedQty)} | |||
helperText={errors.acceptedQty?.message} | |||
/> | |||
@@ -253,6 +254,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => { | |||
required: "sampleRate required!", | |||
valueAsNumber: true, | |||
})} | |||
disabled={disabled} | |||
error={Boolean(errors.sampleRate)} | |||
helperText={errors.sampleRate?.message} | |||
/> | |||
@@ -266,6 +268,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => { | |||
required: "sampleWeight required!", | |||
valueAsNumber: true, | |||
})} | |||
disabled={disabled} | |||
error={Boolean(errors.sampleWeight)} | |||
helperText={errors.sampleWeight?.message} | |||
/> | |||
@@ -279,6 +282,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail }) => { | |||
required: "totalWeight required!", | |||
valueAsNumber: true, | |||
})} | |||
disabled={disabled} | |||
error={Boolean(errors.totalWeight)} | |||
helperText={errors.totalWeight?.message} | |||
/> | |||
@@ -1,6 +1,6 @@ | |||
"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 ReactQrCodeScanner, { | |||
ScannerConfig, | |||
@@ -18,6 +18,7 @@ import { WarehouseResult } from "@/app/api/warehouse"; | |||
import { QrCodeInfo } from "@/app/api/qrcode"; | |||
import { Check } from "@mui/icons-material"; | |||
import { useTranslation } from "react-i18next"; | |||
import { useSearchParams } from "next/navigation"; | |||
interface Props extends Omit<ModalProps, "children"> { | |||
warehouse: WarehouseResult[]; | |||
@@ -36,8 +37,10 @@ const style = { | |||
const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => { | |||
const { t } = useTranslation(); | |||
const [serverError, setServerError] = useState(""); | |||
const params = useSearchParams(); | |||
const formProps = useForm<ModalFormInput>({ | |||
defaultValues: { | |||
// acceptedQty | |||
// ...itemDetail, | |||
}, | |||
}); | |||
@@ -70,13 +73,27 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => { | |||
); | |||
const [itemDetail, setItemDetail] = useState<StockInLine>(); | |||
const [disabledSubmit, setDisabledSubmit] = useState(false); | |||
const [unavailableText, setUnavailableText] = useState<string | undefined>(undefined) | |||
const fetchStockInLine = useCallback( | |||
async (stockInLineId: number) => { | |||
setUnavailableText(undefined) | |||
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(() => { | |||
@@ -86,8 +103,11 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => { | |||
const onSubmit = useCallback<SubmitHandler<ModalFormInput & {}>>( | |||
async (data, event) => { | |||
let hasErrors = false; | |||
console.log("errors"); | |||
console.log(errors); | |||
console.log("data"); | |||
console.log(data); | |||
console.log("itemDetail"); | |||
console.log(itemDetail); | |||
try { | |||
// add checking | |||
@@ -95,11 +115,13 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => { | |||
//////////////////////// modify this mess later ////////////////////// | |||
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, | |||
} as StockInLineEntry & ModalFormInput; | |||
////////////////////////////////////////////////////////////////////// | |||
@@ -139,20 +161,24 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => { | |||
<Grid container xs={12}> | |||
<Grid item xs={12}> | |||
{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}> | |||
<Button | |||
name="submit" | |||
variant="contained" | |||
startIcon={<Check />} | |||
type="submit" | |||
// disabled={submitDisabled} | |||
disabled={disabledSubmit} | |||
> | |||
{t("submit")} | |||
</Button> | |||
</Stack> | |||
</> | |||
) | |||
) : ( | |||
<ReactQrCodeScanner scannerConfig={scannerConfig} /> | |||
)} | |||
@@ -43,6 +43,7 @@ import dayjs from "dayjs"; | |||
interface Props { | |||
itemDetail: StockInLine; | |||
// qc: QcItemWithChecks[]; | |||
disabled: boolean | |||
} | |||
type EntryError = | |||
| { | |||
@@ -55,6 +56,7 @@ type EntryError = | |||
const StockInForm: React.FC<Props> = ({ | |||
// qc, | |||
itemDetail, | |||
disabled | |||
}) => { | |||
const { | |||
t, | |||
@@ -116,6 +118,7 @@ const StockInForm: React.FC<Props> = ({ | |||
{...register("productLotNo", { | |||
// required: "productLotNo required!", | |||
})} | |||
disabled={disabled} | |||
// error={Boolean(errors.productLotNo)} | |||
// helperText={errors.productLotNo?.message} | |||
/> | |||
@@ -136,6 +139,7 @@ const StockInForm: React.FC<Props> = ({ | |||
sx={{ width: "100%" }} | |||
label={t("receiptDate")} | |||
value={dayjs(watch("receiptDate"))} | |||
disabled={disabled} | |||
onChange={(date) => { | |||
if (!date) return | |||
// setValue("receiptDate", date.format(INPUT_DATE_FORMAT)); | |||
@@ -162,6 +166,7 @@ const StockInForm: React.FC<Props> = ({ | |||
{...register("acceptedQty", { | |||
required: "acceptedQty required!", | |||
})} | |||
disabled={disabled} | |||
error={Boolean(errors.acceptedQty)} | |||
helperText={errors.acceptedQty?.message} | |||
/> | |||
@@ -173,6 +178,7 @@ const StockInForm: React.FC<Props> = ({ | |||
// {...register("acceptedWeight", { | |||
// required: "acceptedWeight required!", | |||
// })} | |||
disabled={disabled} | |||
error={Boolean(errors.acceptedWeight)} | |||
helperText={errors.acceptedWeight?.message} | |||
/> | |||
@@ -193,6 +199,7 @@ const StockInForm: React.FC<Props> = ({ | |||
sx={{ width: "100%" }} | |||
label={t("productionDate")} | |||
value={productionDate ? dayjs(productionDate) : undefined} | |||
disabled={disabled} | |||
onChange={(date) => { | |||
if (!date) return | |||
setValue("productionDate", date.format(INPUT_DATE_FORMAT)); | |||
@@ -228,6 +235,7 @@ const StockInForm: React.FC<Props> = ({ | |||
sx={{ width: "100%" }} | |||
label={t("expiryDate")} | |||
value={expiryDate ? dayjs(expiryDate) : undefined} | |||
disabled={disabled} | |||
onChange={(date) => { | |||
console.log(date) | |||
if (!date) return | |||
@@ -7,14 +7,18 @@ import { useRouter, useSearchParams } from "next/navigation"; | |||
import SearchBox, { Criterion } from "../SearchBox"; | |||
import SearchResults, { Column } from "../SearchResults"; | |||
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 = { | |||
po: PoResult[]; | |||
warehouse: WarehouseResult[]; | |||
}; | |||
type SearchQuery = Partial<Omit<PoResult, "id">>; | |||
type SearchParamNames = keyof SearchQuery; | |||
const PoSearch: React.FC<Props> = ({ po }) => { | |||
const PoSearch: React.FC<Props> = ({ po, warehouse }) => { | |||
const [filteredPo, setFilteredPo] = useState<PoResult[]>(po); | |||
const { t } = useTranslation("po"); | |||
const router = useRouter(); | |||
@@ -27,7 +31,6 @@ const PoSearch: React.FC<Props> = ({ po }) => { | |||
return searchCriteria; | |||
}, [t, po]); | |||
const onDetailClick = useCallback( | |||
(po: PoResult) => { | |||
router.push(`/po/edit?id=${po.id}`); | |||
@@ -35,10 +38,7 @@ const PoSearch: React.FC<Props> = ({ po }) => { | |||
[router] | |||
); | |||
const onDeleteClick = useCallback( | |||
(po: PoResult) => {}, | |||
[router] | |||
); | |||
const onDeleteClick = useCallback((po: PoResult) => {}, [router]); | |||
const columns = useMemo<Column<PoResult>[]>( | |||
() => [ | |||
@@ -68,12 +68,12 @@ const PoSearch: React.FC<Props> = ({ po }) => { | |||
// name: "name", | |||
// label: t("Name"), | |||
// }, | |||
// { | |||
// name: "action", | |||
// label: t(""), | |||
// buttonIcon: <GridDeleteIcon />, | |||
// onClick: onDeleteClick, | |||
// }, | |||
// { | |||
// name: "action", | |||
// label: t(""), | |||
// buttonIcon: <GridDeleteIcon />, | |||
// onClick: onDeleteClick, | |||
// }, | |||
], | |||
[filteredPo] | |||
); | |||
@@ -82,23 +82,56 @@ const PoSearch: React.FC<Props> = ({ po }) => { | |||
setFilteredPo(po); | |||
}, [po]); | |||
const [isOpenScanner, setOpenScanner] = useState(false); | |||
const onOpenScanner = useCallback(() => { | |||
setOpenScanner(true); | |||
}, []); | |||
const onCloseScanner = useCallback(() => { | |||
setOpenScanner(false); | |||
}, []); | |||
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} /> | |||
</> | |||
</> | |||
); | |||
}; | |||
@@ -10,6 +10,7 @@ import { fetchPoList, PoResult } from "@/app/api/po"; | |||
import dayjs from "dayjs"; | |||
import arraySupport from "dayjs/plugin/arraySupport"; | |||
import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | |||
import { fetchWarehouseList } from "@/app/api/warehouse"; | |||
dayjs.extend(arraySupport); | |||
interface SubComponents { | |||
@@ -26,9 +27,11 @@ const PoSearchWrapper: React.FC<Props> & SubComponents = async ( | |||
} | |||
) => { | |||
const [ | |||
po | |||
po, | |||
warehouse, | |||
] = await Promise.all([ | |||
fetchPoList() | |||
fetchPoList(), | |||
fetchWarehouseList(), | |||
]); | |||
console.log(po) | |||
const fixPoDate = po.map((p) => { | |||
@@ -37,7 +40,7 @@ const PoSearchWrapper: React.FC<Props> & SubComponents = async ( | |||
orderDate: dayjs(p.orderDate).format(OUTPUT_DATE_FORMAT) | |||
}) | |||
}) | |||
return <PoSearch po={fixPoDate} />; | |||
return <PoSearch po={fixPoDate} warehouse={warehouse}/>; | |||
}; | |||
PoSearchWrapper.Loading = PoSearchLoading; | |||