"use client"; import React, { useState, useEffect, useCallback, useRef } from "react"; import { Box, Typography, Card, CardContent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, CircularProgress, Stack, IconButton, Collapse, Link as MuiLink, } from "@mui/material"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ExpandLessIcon from "@mui/icons-material/ExpandLess"; import NextLink from "next/link"; import { useTranslation } from "react-i18next"; import dayjs from "dayjs"; import type { Dayjs } from "dayjs"; import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { fetchDrinkProductionQty, DrinkProductionQtyResponse, } from "@/app/api/jo/actions"; const REFRESH_INTERVAL = 10 * 60 * 1000; // 10 分鐘 const formatQty = (qty: number | null | undefined): string => { if (qty === null || qty === undefined || Number.isNaN(qty)) return "-"; return qty.toLocaleString(undefined, { maximumFractionDigits: 2 }); }; const formatProductionDate = (value: string | null | undefined): string => { if (!value) return "-"; const parsed = dayjs(value); return parsed.isValid() ? parsed.format("YYYY-MM-DD") : value; }; const getRowKey = (row: DrinkProductionQtyResponse, idx: number): string => `${row.itemCode || "unknown"}-${idx}`; const DrinkProductionQtyDashboard: React.FC = () => { const { t } = useTranslation(["common", "jo", "productionProcess"]); const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [selectedDate, setSelectedDate] = useState(dayjs()); const [expandedRowKeys, setExpandedRowKeys] = useState>( new Set(), ); const refreshCountRef = useRef(0); const [lastDataRefreshTime, setLastDataRefreshTime] = useState( null, ); const loadData = useCallback(async () => { setLoading(true); try { const result = await fetchDrinkProductionQty( selectedDate.format("YYYY-MM-DD"), ); setData(result || []); setExpandedRowKeys(new Set()); setLastDataRefreshTime(dayjs()); refreshCountRef.current += 1; } catch (error) { console.error("Error fetching drink production qty:", error); setData([]); setExpandedRowKeys(new Set()); } finally { setLoading(false); } }, [selectedDate]); useEffect(() => { loadData(); const interval = setInterval(() => { loadData(); }, REFRESH_INTERVAL); return () => clearInterval(interval); }, [loadData]); const toggleRowExpanded = (rowKey: string) => { setExpandedRowKeys((prev) => { const next = new Set(prev); if (next.has(rowKey)) { next.delete(rowKey); } else { next.add(rowKey); } return next; }); }; return ( {t("Drink Production Qty Dashboard")} { if (newValue) setSelectedDate(newValue); }} format="YYYY-MM-DD" slotProps={{ textField: { size: "small", sx: { minWidth: 160 } }, }} /> {t("Auto-refresh every 10 minutes")} |  {t("Last updated")}:{" "} {lastDataRefreshTime ? lastDataRefreshTime.format("HH:mm:ss") : "--:--:--"} {loading ? ( ) : ( {t("Item Code")} {t("Goods Name")} {t("Unit")} {t("Stock Req. Qty")} {t("Production Qty")} {data.length === 0 ? ( {t("No data available")} ) : ( data.map((row, idx) => { const rowKey = getRowKey(row, idx); const jobOrders = row.jobOrders ?? []; const isExpanded = expandedRowKeys.has(rowKey); const hasJobOrders = jobOrders.length > 0; return ( {hasJobOrders ? ( toggleRowExpanded(rowKey)} > {isExpanded ? ( ) : ( )} ) : null} {row.itemCode || "-"} {row.itemName || "-"} {row.uom || "-"} {formatQty(row.totalReqQty)} {formatQty(row.totalQty)} {hasJobOrders && (
{t("Job Order Code")} {t("Production Date")} {t("Stock Req. Qty")} {t("Production Qty")} {jobOrders.map((jo) => ( {jo.jobOrderId > 0 ? ( {jo.jobOrderCode || `JO-${jo.jobOrderId}`} ) : ( jo.jobOrderCode || "-" )} {formatProductionDate( jo.productionDate, )} {formatQty(jo.reqQty)} {formatQty(jo.productionQty)} ))}
)} ); }) )}
)}
); }; export default DrinkProductionQtyDashboard;