"use client"; import { InventoryLotLineResult, InventoryResult } from "@/app/api/inventory"; import { updateInventoryLotLineStatus } from "@/app/api/inventory/actions"; import { arrayToDateString } from "@/app/utils/formatUtil"; import { msg, msgError } from "@/components/Swal/CustomAlerts"; import HighlightOffIcon from "@mui/icons-material/HighlightOff"; import { Box, FormControl, IconButton, InputLabel, MenuItem, Select, SelectChangeEvent, Typography, } from "@mui/material"; import { useCallback, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { Column } from "../SearchResults"; import SearchResults, { defaultPagingController, defaultSetPagingController, } from "../SearchResults/SearchResults"; import BadItemHandleModal from "./BadItemHandleModal"; const LOT_STATUSES = ["available", "unavailable"] as const; interface Props { inventoryLotLines: InventoryLotLineResult[] | null; setPagingController: defaultSetPagingController; pagingController: typeof defaultPagingController; totalCount: number; inventory: InventoryResult | null; currentUserId?: number; onBadItemHandleSuccess?: (payload: { inventoryLotLineId: number; qty: number; }) => void | Promise; onLotLinesChanged?: () => void | Promise; } const StockIssueLotLineTable: React.FC = ({ inventoryLotLines, pagingController, setPagingController, totalCount, inventory, currentUserId, onBadItemHandleSuccess, onLotLinesChanged, }) => { const { t } = useTranslation(["stockIssue", "common"]); const [modalOpen, setModalOpen] = useState(false); const [selectedLotLine, setSelectedLotLine] = useState(null); const [statusUpdatingIds, setStatusUpdatingIds] = useState>( new Set(), ); const statusInFlightRef = useRef>(new Set()); const displayLotLines = useMemo( () => inventoryLotLines ?? [], [inventoryLotLines], ); const isBadItemEnabled = useCallback((line: InventoryLotLineResult) => { const qty = line.availableQty ?? 0; return qty > 0; }, []); const handleBadItemClick = useCallback((lotLine: InventoryLotLineResult) => { if (!isBadItemEnabled(lotLine)) return; setSelectedLotLine(lotLine); setModalOpen(true); }, [isBadItemEnabled]); const handleStatusChange = useCallback( async (line: InventoryLotLineResult, event: SelectChangeEvent) => { const nextStatus = event.target.value; if (!nextStatus || nextStatus === line.status) return; if (statusInFlightRef.current.has(line.id)) return; statusInFlightRef.current.add(line.id); setStatusUpdatingIds((prev) => new Set(prev).add(line.id)); try { const res = await updateInventoryLotLineStatus({ inventoryLotLineId: line.id, status: nextStatus, }); if (res?.code && res.code !== "SUCCESS") { throw new Error(res.message ?? t("Failed to submit")); } msg(t("Saved successfully")); await onLotLinesChanged?.(); } catch (e: unknown) { msgError(e instanceof Error ? e.message : t("Failed to submit")); } finally { statusInFlightRef.current.delete(line.id); setStatusUpdatingIds((prev) => { const next = new Set(prev); next.delete(line.id); return next; }); } }, [t, onLotLinesChanged], ); const formatStatusLabel = useCallback( (status: string) => { const key = status?.toLowerCase(); if (key === "available") return t("available"); if (key === "unavailable") return t("unavailable"); return status; }, [t], ); const columns = useMemo[]>( () => [ { name: "lotNo", label: t("Lot No") }, { name: "availableQty", label: t("Available Qty"), align: "right", headerAlign: "right", type: "integer", }, { name: "uom", label: t("Stock UoM") }, { name: "expiryDate", label: t("Expiry Date"), renderCell: (params) => arrayToDateString(params.expiryDate), }, { name: "warehouse", label: t("Warehouse"), renderCell: (params) => params.warehouse?.code ?? "", }, { name: "status", label: t("Status"), renderCell: (row) => ( {t("Status")} ), }, { name: "id", label: t("Bad Item Handle"), align: "center", headerAlign: "center", renderCell: (row) => ( handleBadItemClick(row)} title={t("Bad Item Handle")} > ), }, ], [ t, handleStatusChange, formatStatusLabel, statusUpdatingIds, isBadItemEnabled, handleBadItemClick, currentUserId, ], ); return ( <> {inventory ? `${t("Item selected")}: ${inventory.itemCode} | ${inventory.itemName} (${t(inventory.itemType, { ns: "common", defaultValue: inventory.itemType })})` : t("No items are selected yet.")} items={displayLotLines} columns={columns} pagingController={pagingController} setPagingController={setPagingController} totalCount={totalCount} /> setModalOpen(false)} lotLine={selectedLotLine} inventory={inventory} currentUserId={currentUserId} onSuccess={async (payload) => { await onBadItemHandleSuccess?.(payload); }} /> ); }; export default StockIssueLotLineTable;