"use client"; import { Autocomplete, Badge, Box, Button, CircularProgress, Tab, Tabs, TextField, Tooltip, Typography, } from "@mui/material"; import React, { Suspense } from "react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import DoWorkbenchPickShell from "./DoWorkbenchPickShell"; import type { PrinterCombo } from "@/app/api/settings/printer"; import GoodPickExecutionWorkbenchRecord from "./GoodPickExecutionWorkbenchRecord"; import { useTranslation } from "react-i18next"; import WorkbenchTicketReleaseTableTab from "./WorkbenchTicketReleaseTable"; import { Stack } from "@mui/system"; import Swal from "sweetalert2"; import { printDNWorkbench } from "@/app/api/do/actions"; import { fetchWorkbenchEtraLaneSummary, fetchWorkbenchReleasedDoPickOrdersForSelectionToday, type WorkbenchEtraShopLaneGroup, } from "@/app/api/doworkbench/actions"; import FinishedGoodCartonDashboardTab from "../FinishedGoodSearch/FinishedGoodCartonDashboardTab"; import TruckRoutingSummaryTabWorkbench from "./TruckRoutingSummaryTabWorkbench"; const ALLOWED_WORKBENCH_TABS = new Set([0, 1, 2, 3, 4, 5, 6]); /** Backend Etra summary: each lane `total` = distinct incomplete (`pending`/`released`) `delivery_order_pick_order` rows for that day. */ function sumIncompleteEtraDopoTickets(groups: WorkbenchEtraShopLaneGroup[]): number { let n = 0; for (const g of groups) { for (const lane of g.lanes) { n += Number(lane.total) || 0; } } return n; } type Props = { defaultTabIndex?: 0 | 1; printerCombo?: PrinterCombo[]; }; function TabPanel(props: { value: number; index: number; children: React.ReactNode }) { const { value, index, children } = props; if (value !== index) return null; return {children}; } const DoWorkbenchTabsInner: React.FC = ({ defaultTabIndex = 0, printerCombo = [] }) => { const searchParams = useSearchParams(); const router = useRouter(); const pathname = usePathname(); const urlTabStr = searchParams.get("tab"); const urlTicketRaw = searchParams.get("ticketNo"); const urlTicketNo = urlTicketRaw && urlTicketRaw.trim() !== "" ? decodeURIComponent(urlTicketRaw.trim()) : null; const urlTargetDateRaw = searchParams.get("targetDate"); const urlTargetDate = urlTargetDateRaw && urlTargetDateRaw.trim() !== "" ? decodeURIComponent(urlTargetDateRaw.trim()) : null; const [tab, setTab] = React.useState(defaultTabIndex); const [a4Printer, setA4Printer] = React.useState(null); const [labelPrinter, setLabelPrinter] = React.useState(null); const [releasedOrderCount, setReleasedOrderCount] = React.useState(0); const [etraIncompleteDopoCount, setEtraIncompleteDopoCount] = React.useState(0); const { t } = useTranslation( ); const a4Printers = React.useMemo( () => (printerCombo || []).filter((printer) => printer.type === "A4"), [printerCombo], ); const labelPrinters = React.useMemo( () => (printerCombo || []).filter((printer) => printer.type === "Label"), [printerCombo], ); const refreshWorkbenchCounts = React.useCallback(async () => { const [releasedRes, etraRes] = await Promise.allSettled([ fetchWorkbenchReleasedDoPickOrdersForSelectionToday(), fetchWorkbenchEtraLaneSummary(), ]); if (releasedRes.status === "fulfilled") { setReleasedOrderCount(releasedRes.value.length); } else { console.error("Error fetching workbench released order count:", releasedRes.reason); setReleasedOrderCount(0); } if (etraRes.status === "fulfilled") { setEtraIncompleteDopoCount(sumIncompleteEtraDopoTickets(etraRes.value)); } else { console.error("Error fetching workbench Etra incomplete count:", etraRes.reason); setEtraIncompleteDopoCount(0); } }, []); React.useEffect(() => { void refreshWorkbenchCounts(); }, [refreshWorkbenchCounts]); React.useEffect(() => { const onAssigned = () => { void refreshWorkbenchCounts(); }; window.addEventListener("pickOrderAssigned", onAssigned); return () => window.removeEventListener("pickOrderAssigned", onAssigned); }, [refreshWorkbenchCounts]); /** Opening Etra tab refreshes badge (completion does not always dispatch `pickOrderAssigned`). */ const etraTabMountSkipRef = React.useRef(false); React.useEffect(() => { if (!etraTabMountSkipRef.current) { etraTabMountSkipRef.current = true; return; } if (tab === 1) void refreshWorkbenchCounts(); }, [tab, refreshWorkbenchCounts]); React.useEffect(() => { if (urlTabStr == null || urlTabStr === "") return; const n = parseInt(urlTabStr, 10); if (!Number.isNaN(n) && ALLOWED_WORKBENCH_TABS.has(n)) { setTab(n); } }, [urlTabStr]); const handleTabChange = React.useCallback( (_: React.SyntheticEvent, newTab: number) => { setTab(newTab); const params = new URLSearchParams(searchParams.toString()); params.set("tab", String(newTab)); /* ticketNo / targetDate deep-link only for "Finished Good Record" (mine) */ if (newTab !== 2) { params.delete("ticketNo"); params.delete("targetDate"); } const qs = params.toString(); router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false }); }, [pathname, router, searchParams], ); const handleAllDraft = React.useCallback(async () => { try { if (!a4Printer) { await Swal.fire({ position: "bottom-end", icon: "warning", text: t("Please select a printer first"), showConfirmButton: false, timer: 1500, }); return; } const releasedOrders = await fetchWorkbenchReleasedDoPickOrdersForSelectionToday(); if (releasedOrders.length === 0) { await Swal.fire({ title: "", text: t("No released pick order records found."), icon: "info", }); return; } const confirmResult = await Swal.fire({ title: t("Batch Print"), text: `${t("Confirm print: (")}${releasedOrders.length}${t("piece(s))")}`, icon: "question", showCancelButton: true, confirmButtonText: t("Confirm"), cancelButtonText: t("Cancel"), confirmButtonColor: "#8dba00", cancelButtonColor: "#F04438", }); if (!confirmResult.isConfirmed) return; Swal.fire({ title: t("Printing..."), text: t("Please wait..."), allowOutsideClick: false, allowEscapeKey: false, didOpen: () => Swal.showLoading(), }); for (const order of releasedOrders) { const printRequest = { printerId: a4Printer.id, printQty: 1, isDraft: true, numOfCarton: 0, deliveryOrderPickOrderId: order.id, }; const response = await printDNWorkbench(printRequest); if (!response.success) { console.error(`Workbench print draft failed for deliveryOrderPickOrderId ${order.id}:`, response.message); } } Swal.close(); await Swal.fire({ position: "bottom-end", icon: "success", text: t("Printed Successfully."), showConfirmButton: false, timer: 1500, }); await refreshWorkbenchCounts(); } catch (error) { Swal.close(); console.error("Error in workbench handleAllDraft:", error); await Swal.fire({ icon: "error", text: t("An error occurred during batch print"), }); } }, [a4Printer, t, refreshWorkbenchCounts]); return ( {t("A4 Printer")}: option.name || option.label || option.code || `Printer ${option.id}`} value={a4Printer} onChange={(_, newValue) => setA4Printer(newValue)} sx={{ minWidth: 200 }} size="small" renderInput={(params) => ( )} /> {t("Label Printer")}: option.name || option.label || option.code || `Printer ${option.id}`} value={labelPrinter} onChange={(_, newValue) => setLabelPrinter(newValue)} sx={{ minWidth: 200 }} size="small" renderInput={(params) => ( )} /> 99 ? 5 : etraIncompleteDopoCount > 0 ? 4 : 2, }} label={ 0 ? t("Etra incomplete badge tooltip", { count: etraIncompleteDopoCount }) : t("Etra incomplete badge tooltip none") } > 99 ? "99+" : etraIncompleteDopoCount} invisible={etraIncompleteDopoCount === 0} sx={{ "& .MuiBadge-badge": { fontWeight: 800, fontSize: "0.7rem", minWidth: 18, height: 18, lineHeight: "18px", px: 0.5, right: -8, top: 2, }, }} > 0 ? 1 : 0 }} > {t("Etra Pick Order Detail")} } /> ); }; const DoWorkbenchTabs: React.FC = (props) => ( } > ); export default DoWorkbenchTabs;