|
|
|
@@ -29,6 +29,7 @@ import { |
|
|
|
import ChevronLeft from "@mui/icons-material/ChevronLeft"; |
|
|
|
import ChevronRight from "@mui/icons-material/ChevronRight"; |
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
import type { StockInLine } from "@/app/api/stockIn"; |
|
|
|
import { fetchItemForPutAway } from "@/app/api/stockIn/actions"; |
|
|
|
import QcStockInModal from "../Qc/QcStockInModal"; |
|
|
|
import { useSession } from "next-auth/react"; |
|
|
|
@@ -178,7 +179,7 @@ function isWaitingQcPutAway( |
|
|
|
return s !== "completed" && s !== "rejected"; |
|
|
|
} |
|
|
|
|
|
|
|
/** FP-MTMS Version Checklist | Functions Ref. No. 40 | v1.0.9 | 2026-08-10 */ |
|
|
|
/** FP-MTMS Version Checklist | Functions Ref. No. 40 | v1.0.10 | 2026-10-15 */ |
|
|
|
const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
onSelectProcess, |
|
|
|
printerCombo, |
|
|
|
@@ -191,6 +192,8 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
const { data: session } = useSession() as { data: SessionWithTokens | null }; |
|
|
|
const sessionToken = session as SessionWithTokens | null; |
|
|
|
const [loading, setLoading] = useState(false); |
|
|
|
/** Bumps on Search/Reset so the same criteria still refetch. */ |
|
|
|
const [listReloadKey, setListReloadKey] = useState(0); |
|
|
|
const [productionCache, setProductionCache] = useState< |
|
|
|
AllJoborderProductProcessInfoResponse[] |
|
|
|
>([]); |
|
|
|
@@ -234,6 +237,8 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
() => printerOptions[0] ?? null, |
|
|
|
); |
|
|
|
const printInFlightRef = useRef(false); |
|
|
|
const loadSeqRef = useRef(0); |
|
|
|
const hasLoadedOnceRef = useRef(false); |
|
|
|
const [printingSilId, setPrintingSilId] = useState<number | null>(null); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
@@ -328,6 +333,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
const handleApplySearch = useCallback( |
|
|
|
(inputs: Record<SearchParam | `${SearchParam}To`, string>) => { |
|
|
|
const selectedProcessType = (inputs.processType || "all") as ProcessFilter; |
|
|
|
setListReloadKey((k) => k + 1); |
|
|
|
onListPersistedStateChange((prev) => ({ |
|
|
|
...prev, |
|
|
|
filter: selectedProcessType, |
|
|
|
@@ -342,6 +348,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
); |
|
|
|
|
|
|
|
const handleResetSearch = useCallback(() => { |
|
|
|
setListReloadKey((k) => k + 1); |
|
|
|
onListPersistedStateChange((prev) => ({ |
|
|
|
...prev, |
|
|
|
filter: "all", |
|
|
|
@@ -355,8 +362,10 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
}, [disableDateFilter, onListPersistedStateChange]); |
|
|
|
|
|
|
|
/** Load all tab datasets once per search; tab switches use cache only. */ |
|
|
|
const loadAllCaches = useCallback(async () => { |
|
|
|
setLoading(true); |
|
|
|
const loadAllCaches = useCallback(async (options?: { silent?: boolean }) => { |
|
|
|
const silent = options?.silent === true; |
|
|
|
const seq = ++loadSeqRef.current; |
|
|
|
if (!silent) setLoading(true); |
|
|
|
try { |
|
|
|
const typeParam = filter === "all" ? undefined : filter; |
|
|
|
const base = { |
|
|
|
@@ -391,6 +400,8 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
}), |
|
|
|
]); |
|
|
|
|
|
|
|
if (seq !== loadSeqRef.current) return; |
|
|
|
|
|
|
|
const prodContent = (prod?.content || []).filter((p) => !isPutawayCompleted(p)); |
|
|
|
const qcContent = (pendingQc?.content || []).filter((p) => !isPutawayCompleted(p)); |
|
|
|
const putawayContent = putawayed?.content || []; |
|
|
|
@@ -405,6 +416,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
setCarriedOverCount(prod?.carriedOverCount ?? 0); |
|
|
|
} catch (e) { |
|
|
|
console.error(e); |
|
|
|
if (seq !== loadSeqRef.current || silent) return; |
|
|
|
setProductionCache([]); |
|
|
|
setPendingQcCache([]); |
|
|
|
setPutawayedCache([]); |
|
|
|
@@ -413,12 +425,14 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
setPutawayedCount(0); |
|
|
|
setCarriedOverCount(0); |
|
|
|
} finally { |
|
|
|
setLoading(false); |
|
|
|
if (seq === loadSeqRef.current) setLoading(false); |
|
|
|
} |
|
|
|
}, [appliedSearch, disableDateFilter, filter]); |
|
|
|
}, [appliedSearch, disableDateFilter, filter, listReloadKey]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
void loadAllCaches(); |
|
|
|
const silent = hasLoadedOnceRef.current; |
|
|
|
hasLoadedOnceRef.current = true; |
|
|
|
void loadAllCaches(silent ? { silent: true } : undefined); |
|
|
|
}, [loadAllCaches]); |
|
|
|
|
|
|
|
const offPlanRows = useMemo(() => { |
|
|
|
@@ -670,9 +684,12 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
closeConfirm(); |
|
|
|
} |
|
|
|
}, [pendingConfirmAction, closeConfirm]); |
|
|
|
const closeNewModal = useCallback(() => { |
|
|
|
const closeNewModal = useCallback((updatedStockInLine?: StockInLine) => { |
|
|
|
setOpenModal(false); |
|
|
|
}, []); |
|
|
|
if (updatedStockInLine) { |
|
|
|
void loadAllCaches({ silent: true }); |
|
|
|
} |
|
|
|
}, [loadAllCaches]); |
|
|
|
|
|
|
|
const handlePrintLabel = useCallback( |
|
|
|
async (process: AllJoborderProductProcessInfoResponse) => { |
|
|
|
|