@flowselections/pick-schermen-kwekers 1.0.62 → 1.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
- package/dist-lib/components/pick/PickScherm.js +18 -7
- package/dist-lib/components/pick/QueueTable.d.ts +5 -1
- package/dist-lib/components/pick/QueueTable.d.ts.map +1 -1
- package/dist-lib/components/pick/QueueTable.js +14 -31
- package/dist-lib/hooks/usePickPrintStatus.d.ts +14 -0
- package/dist-lib/hooks/usePickPrintStatus.d.ts.map +1 -0
- package/dist-lib/hooks/usePickPrintStatus.js +47 -0
- package/dist-lib/hooks/usePickQueue.d.ts +2 -0
- package/dist-lib/hooks/usePickQueue.d.ts.map +1 -1
- package/dist-lib/hooks/usePickQueue.js +29 -8
- package/dist-lib/integrations/supabase/types.d.ts +504 -2
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/__tests__/pick143.test.js +1 -1
- package/dist-lib/lib/__tests__/pick163.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/pick163.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/pick163.test.js +68 -0
- package/dist-lib/lib/pick143.d.ts +7 -2
- package/dist-lib/lib/pick143.d.ts.map +1 -1
- package/dist-lib/lib/pick143.js +24 -5
- package/dist-lib/lib/pick159.js +1 -1
- package/dist-lib/lib/pickPerf.d.ts +11 -0
- package/dist-lib/lib/pickPerf.d.ts.map +1 -0
- package/dist-lib/lib/pickPerf.js +35 -0
- package/dist-lib/lib/pickPrintStatus.d.ts +36 -0
- package/dist-lib/lib/pickPrintStatus.d.ts.map +1 -0
- package/dist-lib/lib/pickPrintStatus.js +98 -0
- package/dist-lib/lib/pickRowState.d.ts +2 -1
- package/dist-lib/lib/pickRowState.d.ts.map +1 -1
- package/dist-lib/lib/pickRowState.js +4 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AA0DA,OAAO,EAaL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AA0DA,OAAO,EAaL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AA6D7B,UAAU,KAAK;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAwBD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,+BA0rEpD"}
|
|
@@ -21,6 +21,8 @@ import { getPickTranslator } from "../../lib/pickI18n.js";
|
|
|
21
21
|
import { friendlyPickError, getPickUiTexts } from "../../lib/pickUiText.js";
|
|
22
22
|
import { getPrintJobTexts } from "../../lib/pickPrintJobText.js";
|
|
23
23
|
import { defaultFilters, usePickDays, usePickHeartbeat, usePickQueue, } from "../../hooks/usePickQueue.js";
|
|
24
|
+
import { usePickPrintStatus } from "../../hooks/usePickPrintStatus.js";
|
|
25
|
+
import { activeDeviceKey } from "../../lib/pick159.js";
|
|
24
26
|
import { usePickDocumentTypes, usePickStatuses, useStationPrintPlek, } from "../../hooks/usePickConfig.js";
|
|
25
27
|
import { usePrintBatch, usePrintJob } from "../../hooks/usePrintJob.js";
|
|
26
28
|
import { useShippingNoteStatus } from "../../hooks/useShippingNoteStatus.js";
|
|
@@ -219,12 +221,17 @@ export function PickScherm({ station, onBack }) {
|
|
|
219
221
|
return () => clearTimeout(timer);
|
|
220
222
|
}, [searchInput]);
|
|
221
223
|
const effectiveFilters = useMemo(() => ({ ...filters, country: null, sortRules: [] }), [filters]);
|
|
222
|
-
const { items, total, loading, lockedIds, refresh, pendingCount, printedCount, urgentCount, realtimeOk, pickDay, rebuiltAt, syncError, } = usePickQueue({
|
|
224
|
+
const { items, total, loading, lockedIds, refresh, pendingCount, printedCount, countsLoading, urgentCount, realtimeOk, pickDay, rebuiltAt, syncError, } = usePickQueue({
|
|
223
225
|
stationId: station.id,
|
|
224
226
|
filters: effectiveFilters,
|
|
225
227
|
enabled: lang !== null,
|
|
226
228
|
pickDayOverride: chosenDay,
|
|
227
229
|
});
|
|
230
|
+
// 1.0.63: printstatus uit de Engine, één aanroep voor alle regels in beeld.
|
|
231
|
+
const printStatusIds = useMemo(() => (Array.isArray(items) ? items : []).map((i) => i.id), [items]);
|
|
232
|
+
const { result: printStatus, loading: printStatusLoading, inPrint, } = usePickPrintStatus(printStatusIds, activeDeviceKey() ? station.slug ?? null : null, lang !== null);
|
|
233
|
+
const inPrintRef = useRef(inPrint);
|
|
234
|
+
inPrintRef.current = inPrint;
|
|
228
235
|
/** Geprint maar nog niet gescand, van een eerdere pickdag (blijft open tot de scan). */
|
|
229
236
|
const viewDay = chosenDay ?? pickDay ?? null;
|
|
230
237
|
const { data: earlierRaw, refetch: refetchEarlier } = useQuery({
|
|
@@ -667,6 +674,10 @@ export function PickScherm({ station, onBack }) {
|
|
|
667
674
|
toast.warning(block);
|
|
668
675
|
return;
|
|
669
676
|
}
|
|
677
|
+
if (inPrintRef.current.has(item.id)) {
|
|
678
|
+
toast.info("Deze pakbon wordt al geprint. Wacht tot de printer klaar is.");
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
670
681
|
setBusyId(item.id);
|
|
671
682
|
try {
|
|
672
683
|
const claimed = await pickApi.claim({
|
|
@@ -918,7 +929,7 @@ export function PickScherm({ station, onBack }) {
|
|
|
918
929
|
return;
|
|
919
930
|
setBatchPrinting(true);
|
|
920
931
|
try {
|
|
921
|
-
const visible = (Array.isArray(items) ? items : []).filter((item) => !item.printed_at);
|
|
932
|
+
const visible = (Array.isArray(items) ? items : []).filter((item) => !item.printed_at && !inPrintRef.current.has(item.id));
|
|
922
933
|
const targets = [];
|
|
923
934
|
const skipped = [];
|
|
924
935
|
for (const item of visible) {
|
|
@@ -972,7 +983,7 @@ export function PickScherm({ station, onBack }) {
|
|
|
972
983
|
setBusyId("next");
|
|
973
984
|
let claimed = null;
|
|
974
985
|
try {
|
|
975
|
-
const target = firstVisibleTarget(itemsRef.current, lockedIds);
|
|
986
|
+
const target = firstVisibleTarget(itemsRef.current, lockedIds, inPrintRef.current);
|
|
976
987
|
const filtered = !!filters.search.trim() || !!filters.documentTypeId || filters.urgentOnly || !!filters.country;
|
|
977
988
|
if (target) {
|
|
978
989
|
// De rij die in beeld staat (ook met zoekfilter), niet de bovenste van de hele wachtrij.
|
|
@@ -1366,7 +1377,7 @@ export function PickScherm({ station, onBack }) {
|
|
|
1366
1377
|
? "Pickwachtrij laden…"
|
|
1367
1378
|
: checkDone > 0
|
|
1368
1379
|
? `Pakbonnen controleren (${checkDone} van ${checkTotal})…`
|
|
1369
|
-
: `Pakbonnen controleren (${checkTotal})…` }), _jsxs("span", { className: "tabular-nums", children: [loadPercent, "%"] })] }), _jsx("div", { className: "h-1.5 w-full overflow-hidden rounded-full bg-muted", children: _jsx("div", { className: "h-full rounded-full bg-primary transition-all duration-300", style: { width: `${Math.max(5, loadPercent)}%` } }) })] })), _jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:flex-wrap md:items-center md:justify-between", children: [_jsxs("div", { className: "grid grid-cols-[auto_minmax(0,1fr)] items-center gap-3", children: [_jsxs(Button, { variant: "outline", size: "lg", className: "h-12 shrink-0 px-3 sm:px-4", onClick: () => setLang(null), "aria-label": t("changeLanguage"), children: [_jsx(Globe, { className: "h-5 w-5 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: t("changeLanguage") })] }), _jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "truncate text-lg font-bold text-foreground sm:text-xl", children: station.name }), _jsxs("p", { className: "truncate text-sm text-muted-foreground", children: [pendingCount, " ", t("statusToPrint"), " \u00B7 ", printedCount, " ", t("statusPrinted"), openJobIds.length > 0 ? ` · ${openJobIds.length} wacht op printer` : ""] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "lg", className: "h-12 px-3", onClick: () => void shiftDay(-1), disabled: loadingDay || !(chosenDay ?? pickDay), "aria-label": ui.pickDayPrev, children: [_jsx(ChevronLeft, { className: "h-5 w-5 sm:mr-1" }), _jsx("span", { className: "hidden sm:inline", children: ui.pickDayPrev })] }), _jsx("div", { className: "flex h-12 items-center rounded-md border bg-muted px-4 text-sm font-semibold text-foreground", children: chosenDay ? dayLabel(chosenDay) : ui.pickDayToday }), _jsxs(Button, { variant: "outline", size: "lg", className: "h-12 px-3", onClick: () => void shiftDay(1), disabled: loadingDay || !(chosenDay ?? pickDay), "aria-label": ui.pickDayNext, children: [_jsx("span", { className: "hidden sm:inline", children: ui.pickDayNext }), _jsx(ChevronRight, { className: "h-5 w-5 sm:ml-1" })] }), chosenDay && (_jsx(Button, { variant: "secondary", size: "lg", className: "h-12 px-4", onClick: () => void chooseDay("current"), disabled: loadingDay, children: ui.pickDayBackToToday }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [!online && (_jsxs(Badge, { className: "bg-destructive text-destructive-foreground", children: [_jsx(WifiOff, { className: "mr-1 h-3.5 w-3.5" }), " ", t("offline")] })), _jsx(Button, { variant: "outline", size: "icon", className: "h-12 w-12 shrink-0", onClick: refresh, "aria-label": t("refresh"), children: _jsx(RefreshCw, { className: "h-4 w-4" }) }), _jsxs(Button, { variant: "outline", size: "lg", className: "hidden h-14 px-5 md:inline-flex", disabled: fetchingNotes, onClick: () => void fetchShippingNotes(), children: [fetchingNotes ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(FileDown, { className: "mr-2 h-5 w-5" })), fetchingNotes ? "Ophalen…" : "Verzendbrieven ophalen"] }), cartsPerPrint != null && (_jsxs(Button, { size: "lg", className: "hidden h-14 px-6 text-lg md:inline-flex", disabled: loading || batchPrinting || (busyId != null || actionBusy), onClick: () => void printNextCarts(), children: [batchPrinting ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), "Volgende printen (", cartsPerPrint, " karren)"] })), _jsxs(Button, { size: "lg", className: "hidden h-14 px-8 text-lg md:inline-flex", onClick: () => (pending ? confirmPending() : fetchNextLocked()), disabled: (busyId !== null || actionBusy) || fetchingData, children: [(busyId !== null || actionBusy) || fetchingData ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : pending && !readiness.ready ? (_jsx(RefreshCw, { className: "mr-2 h-5 w-5" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), pending && !readiness.ready ? "Pakbon ophalen" : t("printNext")] })] })] }), syncError && (_jsxs("div", { role: "alert", className: "flex items-start gap-2 rounded-md border-2 border-destructive/50 bg-destructive/5 p-3 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsxs("span", { children: [SYNC_ERROR_MESSAGE, _jsxs("details", { className: "mt-1 text-xs text-muted-foreground", children: [_jsx("summary", { children: "Details voor beheer" }), syncError] })] })] })), !plekLoading && !printPlek && (_jsxs("div", { className: "flex items-start gap-2 rounded-md border-2 border-destructive/50 bg-destructive/5 p-3 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: "Nog geen printplek gekoppeld \u2014 de opdracht blijft in de wachtrij staan." })] })), (cartMissing || rowGone) && (_jsxs("div", { role: "alert", className: "flex flex-col gap-2 rounded-md border-2 border-destructive/50 bg-destructive/5 p-3 text-sm text-destructive sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("span", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), rowGone ? ROW_GONE_MESSAGE : CART_MISSING_MESSAGE] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
1380
|
+
: `Pakbonnen controleren (${checkTotal})…` }), _jsxs("span", { className: "tabular-nums", children: [loadPercent, "%"] })] }), _jsx("div", { className: "h-1.5 w-full overflow-hidden rounded-full bg-muted", children: _jsx("div", { className: "h-full rounded-full bg-primary transition-all duration-300", style: { width: `${Math.max(5, loadPercent)}%` } }) })] })), _jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:flex-wrap md:items-center md:justify-between", children: [_jsxs("div", { className: "grid grid-cols-[auto_minmax(0,1fr)] items-center gap-3", children: [_jsxs(Button, { variant: "outline", size: "lg", className: "h-12 shrink-0 px-3 sm:px-4", onClick: () => setLang(null), "aria-label": t("changeLanguage"), children: [_jsx(Globe, { className: "h-5 w-5 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: t("changeLanguage") })] }), _jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "truncate text-lg font-bold text-foreground sm:text-xl", children: station.name }), _jsxs("p", { className: "truncate text-sm text-muted-foreground", children: [countsLoading ? "…" : pendingCount, " ", t("statusToPrint"), " \u00B7 ", countsLoading ? "…" : printedCount, " ", t("statusPrinted"), openJobIds.length > 0 ? ` · ${openJobIds.length} wacht op printer` : ""] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "lg", className: "h-12 px-3", onClick: () => void shiftDay(-1), disabled: loadingDay || !(chosenDay ?? pickDay), "aria-label": ui.pickDayPrev, children: [_jsx(ChevronLeft, { className: "h-5 w-5 sm:mr-1" }), _jsx("span", { className: "hidden sm:inline", children: ui.pickDayPrev })] }), _jsx("div", { className: "flex h-12 items-center rounded-md border bg-muted px-4 text-sm font-semibold text-foreground", children: chosenDay ? dayLabel(chosenDay) : ui.pickDayToday }), _jsxs(Button, { variant: "outline", size: "lg", className: "h-12 px-3", onClick: () => void shiftDay(1), disabled: loadingDay || !(chosenDay ?? pickDay), "aria-label": ui.pickDayNext, children: [_jsx("span", { className: "hidden sm:inline", children: ui.pickDayNext }), _jsx(ChevronRight, { className: "h-5 w-5 sm:ml-1" })] }), chosenDay && (_jsx(Button, { variant: "secondary", size: "lg", className: "h-12 px-4", onClick: () => void chooseDay("current"), disabled: loadingDay, children: ui.pickDayBackToToday }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [!online && (_jsxs(Badge, { className: "bg-destructive text-destructive-foreground", children: [_jsx(WifiOff, { className: "mr-1 h-3.5 w-3.5" }), " ", t("offline")] })), _jsx(Button, { variant: "outline", size: "icon", className: "h-12 w-12 shrink-0", onClick: refresh, "aria-label": t("refresh"), children: _jsx(RefreshCw, { className: "h-4 w-4" }) }), _jsxs(Button, { variant: "outline", size: "lg", className: "hidden h-14 px-5 md:inline-flex", disabled: fetchingNotes, onClick: () => void fetchShippingNotes(), children: [fetchingNotes ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(FileDown, { className: "mr-2 h-5 w-5" })), fetchingNotes ? "Ophalen…" : "Verzendbrieven ophalen"] }), cartsPerPrint != null && (_jsxs(Button, { size: "lg", className: "hidden h-14 px-6 text-lg md:inline-flex", disabled: loading || printStatusLoading || batchPrinting || (busyId != null || actionBusy), onClick: () => void printNextCarts(), children: [batchPrinting ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), "Volgende printen (", cartsPerPrint, " karren)"] })), _jsxs(Button, { size: "lg", className: "hidden h-14 px-8 text-lg md:inline-flex", onClick: () => (pending ? confirmPending() : fetchNextLocked()), disabled: (busyId !== null || actionBusy) || fetchingData || (!pending && printStatusLoading), children: [(busyId !== null || actionBusy) || fetchingData ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : pending && !readiness.ready ? (_jsx(RefreshCw, { className: "mr-2 h-5 w-5" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), pending && !readiness.ready ? "Pakbon ophalen" : t("printNext")] })] })] }), syncError && (_jsxs("div", { role: "alert", className: "flex items-start gap-2 rounded-md border-2 border-destructive/50 bg-destructive/5 p-3 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsxs("span", { children: [SYNC_ERROR_MESSAGE, _jsxs("details", { className: "mt-1 text-xs text-muted-foreground", children: [_jsx("summary", { children: "Details voor beheer" }), syncError] })] })] })), !plekLoading && !printPlek && (_jsxs("div", { className: "flex items-start gap-2 rounded-md border-2 border-destructive/50 bg-destructive/5 p-3 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: "Nog geen printplek gekoppeld \u2014 de opdracht blijft in de wachtrij staan." })] })), (cartMissing || rowGone) && (_jsxs("div", { role: "alert", className: "flex flex-col gap-2 rounded-md border-2 border-destructive/50 bg-destructive/5 p-3 text-sm text-destructive sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("span", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), rowGone ? ROW_GONE_MESSAGE : CART_MISSING_MESSAGE] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
1370
1381
|
setCartMissing(false);
|
|
1371
1382
|
setRowGone(false);
|
|
1372
1383
|
setPending(null);
|
|
@@ -1378,7 +1389,7 @@ export function PickScherm({ station, onBack }) {
|
|
|
1378
1389
|
const cart = plannedCart ?? { cartId: r.cartId, cartLabel: r.cartLabel ?? r.cartId };
|
|
1379
1390
|
setLastCartResults((prev) => prev.filter((x) => x.cartId !== r.cartId));
|
|
1380
1391
|
void reprintCart(lastPrinted, cart);
|
|
1381
|
-
}, children: "Opnieuw printen" })] }, r.cartId))) }) })), lastCartResults.length > 1 && (_jsxs("div", { className: "rounded-md border p-3 text-sm", "aria-label": "Resultaat per kar", children: [_jsx("p", { className: "mb-1 font-semibold text-foreground", children: "Resultaat per kar" }), _jsx("ul", { className: "space-y-0.5 text-muted-foreground", children: lastCartResults.map((r) => (_jsx("li", { className: r.outcome === "created" ? "text-foreground" : r.outcome === "error" ? "text-destructive" : "", children: cartResultLine(r) }, r.cartId))) })] })), _jsx(VroegeStickerWaarschuwing, { stationId: station.id }), _jsx(ShippingNoteScan, { stationId: station.id }), !pending && emptyNotice && (_jsx("p", { className: "text-sm text-muted-foreground", children: emptyNotice })), pending && (_jsxs(Card, { className: "border-2 border-primary", children: [_jsxs(CardContent, { className: "flex flex-col gap-4 p-4 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between sm:p-5", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("confirmPrintTitle") }), _jsx("p", { className: "truncate text-xl font-bold text-foreground sm:text-2xl", children: pending.document_number ?? t("document") }), _jsx("p", { className: "truncate text-sm text-muted-foreground", children: [pending.order_number, pending.customer_name].filter(Boolean).join(" · ") })] }), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [_jsx(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:w-auto", onClick: cancelPending, disabled: (busyId !== null || actionBusy), children: t("cancel") }), _jsxs(Button, { size: "lg", className: "h-14 w-full px-8 text-lg sm:w-auto", onClick: confirmPending, disabled: (busyId !== null || actionBusy) || fetchingData, variant: readiness.ready ? "default" : "secondary", children: [busyId === "confirm" || fetchingData ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : readiness.ready ? (_jsx(Printer, { className: "mr-2 h-5 w-5" })) : (_jsx(RefreshCw, { className: "mr-2 h-5 w-5" })), readiness.ready ? t("print") : "Pakbon ophalen"] })] })] }), !readiness.ready && (_jsx(CardContent, { className: "border-t p-4 sm:p-5", children: _jsxs("div", { className: "flex items-start gap-2 rounded-md border bg-muted/30 p-3 text-sm text-muted-foreground", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: fetchingData
|
|
1392
|
+
}, children: "Opnieuw printen" })] }, r.cartId))) }) })), lastCartResults.length > 1 && (_jsxs("div", { className: "rounded-md border p-3 text-sm", "aria-label": "Resultaat per kar", children: [_jsx("p", { className: "mb-1 font-semibold text-foreground", children: "Resultaat per kar" }), _jsx("ul", { className: "space-y-0.5 text-muted-foreground", children: lastCartResults.map((r) => (_jsx("li", { className: r.outcome === "created" ? "text-foreground" : r.outcome === "error" ? "text-destructive" : "", children: cartResultLine(r) }, r.cartId))) })] })), _jsx(VroegeStickerWaarschuwing, { stationId: station.id }), _jsx(ShippingNoteScan, { stationId: station.id }), !pending && emptyNotice && (_jsx("p", { className: "text-sm text-muted-foreground", children: emptyNotice })), pending && (_jsxs(Card, { className: "border-2 border-primary", children: [_jsxs(CardContent, { className: "flex flex-col gap-4 p-4 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between sm:p-5", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("confirmPrintTitle") }), _jsx("p", { className: "truncate text-xl font-bold text-foreground sm:text-2xl", children: pending.document_number ?? t("document") }), _jsx("p", { className: "truncate text-sm text-muted-foreground", children: [pending.order_number, pending.customer_name].filter(Boolean).join(" · ") })] }), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [_jsx(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:w-auto", onClick: cancelPending, disabled: (busyId !== null || actionBusy), children: t("cancel") }), _jsxs(Button, { size: "lg", className: "h-14 w-full px-8 text-lg sm:w-auto", onClick: confirmPending, disabled: (busyId !== null || actionBusy) || fetchingData || (!pending && printStatusLoading), variant: readiness.ready ? "default" : "secondary", children: [busyId === "confirm" || fetchingData ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : readiness.ready ? (_jsx(Printer, { className: "mr-2 h-5 w-5" })) : (_jsx(RefreshCw, { className: "mr-2 h-5 w-5" })), readiness.ready ? t("print") : "Pakbon ophalen"] })] })] }), !readiness.ready && (_jsx(CardContent, { className: "border-t p-4 sm:p-5", children: _jsxs("div", { className: "flex items-start gap-2 rounded-md border bg-muted/30 p-3 text-sm text-muted-foreground", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: fetchingData
|
|
1382
1393
|
? "De pakbon wordt opgevraagd. Zodra alles compleet is, verschijnt de printknop weer."
|
|
1383
1394
|
: planReason
|
|
1384
1395
|
? `${planReason} Klik op "Pakbon ophalen" om hem op te vragen.`
|
|
@@ -1434,8 +1445,8 @@ export function PickScherm({ station, onBack }) {
|
|
|
1434
1445
|
(message ?? "Verzendbriefstatus wordt opgehaald.") }), waiting && (note.state.attempts !== null || note.state.nextAttemptAt) && (_jsxs("p", { className: "text-xs text-muted-foreground", children: [note.state.attempts !== null ? `Pogingen: ${note.state.attempts}` : "", note.state.attempts !== null && note.state.nextAttemptAt ? " · " : "", note.state.nextAttemptAt
|
|
1435
1446
|
? `Volgende poging: ${formatSiteTime(note.state.nextAttemptAt, siteTz)}`
|
|
1436
1447
|
: ""] }))] })] }, note.jobId));
|
|
1437
|
-
})] }) })), _jsxs(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:hidden", "aria-expanded": filtersOpen, onClick: () => setFiltersOpen((v) => !v), children: [_jsx(Search, { className: "mr-2 h-4 w-4" }), " ", ui.filters] }), _jsx(Card, { className: filtersOpen ? "" : "hidden sm:block", children: _jsxs(CardContent, { className: "flex flex-wrap items-center gap-3 p-3 sm:p-4", children: [_jsxs("div", { className: "relative w-full min-w-0 flex-1 sm:min-w-64", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "h-12 pl-9 text-base", placeholder: t("search"), value: searchInput, onChange: (e) => setSearchInput(e.target.value) })] }), _jsxs(Select, { value: chosenDay ?? "current", onValueChange: (v) => void chooseDay(v), children: [_jsx(SelectTrigger, { className: "h-12 w-full sm:w-56", disabled: loadingDay, children: _jsx(SelectValue, { placeholder: ui.pickDay }) }), _jsxs(SelectContent, { className: "z-[100] bg-popover opacity-100", children: [_jsx(SelectItem, { value: "current", children: ui.pickDayToday }), safePickDays.map((d) => (_jsxs(SelectItem, { value: d.day, children: [dayLabel(d.day), d.orders > 0 ? ` (${d.orders})` : ""] }, d.day)))] })] }), _jsxs(Select, { value: filters.documentTypeId ?? "all", onValueChange: (v) => setFilters((f) => ({ ...f, documentTypeId: v === "all" ? null : v, page: 0 })), children: [_jsx(SelectTrigger, { className: "h-12 w-full sm:w-52", children: _jsx(SelectValue, { placeholder: ui.allDocumentTypes }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: ui.allDocumentTypes }), (Array.isArray(documentTypes) ? documentTypes : []).map((dt) => (_jsx(SelectItem, { value: dt.id, children: dt.name }, dt.id)))] })] }), _jsx(Button, { variant: filters.onlyPending ? "default" : "outline", className: "h-12", onClick: () => setFilters((f) => ({ ...f, onlyPending: !f.onlyPending, page: 0 })), children: ui.onlyPending }), _jsxs(Button, { variant: filters.urgentOnly ? "default" : "outline", className: "h-12", onClick: () => setFilters((f) => ({ ...f, urgentOnly: !f.urgentOnly, page: 0 })), children: [_jsx(Zap, { className: "mr-2 h-4 w-4" }), ui.onlyUrgent, urgentCount > 0 ? ` (${urgentCount})` : ""] })] }) }), !realtimeOk && (_jsx("p", { className: "text-sm text-muted-foreground", children: ui.connectionLost })), cartsPerPrint != null && (_jsx("div", { className: "flex justify-end md:hidden", children: _jsxs(Button, { className: "h-12", disabled: loading || batchPrinting || (busyId != null || actionBusy), onClick: () => void printNextCarts(), children: [batchPrinting ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Volgende printen (", cartsPerPrint, " karren)"] }) })), _jsx("div", { className: "md:hidden", children: _jsxs(Button, { variant: "outline", className: "h-12 w-full", disabled: fetchingNotes, onClick: () => void fetchShippingNotes(), children: [fetchingNotes ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(FileDown, { className: "mr-2 h-4 w-4" })), fetchingNotes ? "Ophalen…" : "Verzendbrieven ophalen"] }) }), loading ? (_jsxs("div", { className: "flex items-center justify-center py-16 text-muted-foreground", children: [_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" }), " ", t("loadingQueue")] })) : (_jsxs(_Fragment, { children: [earlierRows.length > 0 && (_jsxs("section", { className: "mb-4 rounded-lg border border-primary/40 bg-muted/40 p-3", "aria-label": "Nog niet gescand van eerdere dagen", children: [_jsxs("h3", { className: "mb-2 text-sm font-semibold text-foreground", children: ["Nog niet gescand van eerdere dagen (", earlierRows.length, ")"] }), _jsx("ul", { className: "divide-y divide-border", children: earlierRows.map((row) => (_jsxs("li", { className: "flex flex-wrap items-center justify-between gap-2 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-medium", children: row.document_number ?? row.order_number ?? "Pakbon" }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [pickDayShortLabel(pickDayOf(row)), row.customer_name ? ` · ${row.customer_name}` : ""] })] }), _jsx(Button, { size: "sm", variant: "outline", disabled: busyId !== null || actionBusy, onClick: async () => {
|
|
1448
|
+
})] }) })), _jsxs(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:hidden", "aria-expanded": filtersOpen, onClick: () => setFiltersOpen((v) => !v), children: [_jsx(Search, { className: "mr-2 h-4 w-4" }), " ", ui.filters] }), _jsx(Card, { className: filtersOpen ? "" : "hidden sm:block", children: _jsxs(CardContent, { className: "flex flex-wrap items-center gap-3 p-3 sm:p-4", children: [_jsxs("div", { className: "relative w-full min-w-0 flex-1 sm:min-w-64", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "h-12 pl-9 text-base", placeholder: t("search"), value: searchInput, onChange: (e) => setSearchInput(e.target.value) })] }), _jsxs(Select, { value: chosenDay ?? "current", onValueChange: (v) => void chooseDay(v), children: [_jsx(SelectTrigger, { className: "h-12 w-full sm:w-56", disabled: loadingDay, children: _jsx(SelectValue, { placeholder: ui.pickDay }) }), _jsxs(SelectContent, { className: "z-[100] bg-popover opacity-100", children: [_jsx(SelectItem, { value: "current", children: ui.pickDayToday }), safePickDays.map((d) => (_jsxs(SelectItem, { value: d.day, children: [dayLabel(d.day), d.orders > 0 ? ` (${d.orders})` : ""] }, d.day)))] })] }), _jsxs(Select, { value: filters.documentTypeId ?? "all", onValueChange: (v) => setFilters((f) => ({ ...f, documentTypeId: v === "all" ? null : v, page: 0 })), children: [_jsx(SelectTrigger, { className: "h-12 w-full sm:w-52", children: _jsx(SelectValue, { placeholder: ui.allDocumentTypes }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: ui.allDocumentTypes }), (Array.isArray(documentTypes) ? documentTypes : []).map((dt) => (_jsx(SelectItem, { value: dt.id, children: dt.name }, dt.id)))] })] }), _jsx(Button, { variant: filters.onlyPending ? "default" : "outline", className: "h-12", onClick: () => setFilters((f) => ({ ...f, onlyPending: !f.onlyPending, page: 0 })), children: ui.onlyPending }), _jsxs(Button, { variant: filters.urgentOnly ? "default" : "outline", className: "h-12", onClick: () => setFilters((f) => ({ ...f, urgentOnly: !f.urgentOnly, page: 0 })), children: [_jsx(Zap, { className: "mr-2 h-4 w-4" }), ui.onlyUrgent, urgentCount > 0 ? ` (${urgentCount})` : ""] })] }) }), !realtimeOk && (_jsx("p", { className: "text-sm text-muted-foreground", children: ui.connectionLost })), cartsPerPrint != null && (_jsx("div", { className: "flex justify-end md:hidden", children: _jsxs(Button, { className: "h-12", disabled: loading || printStatusLoading || batchPrinting || (busyId != null || actionBusy), onClick: () => void printNextCarts(), children: [batchPrinting ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Volgende printen (", cartsPerPrint, " karren)"] }) })), _jsx("div", { className: "md:hidden", children: _jsxs(Button, { variant: "outline", className: "h-12 w-full", disabled: fetchingNotes, onClick: () => void fetchShippingNotes(), children: [fetchingNotes ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(FileDown, { className: "mr-2 h-4 w-4" })), fetchingNotes ? "Ophalen…" : "Verzendbrieven ophalen"] }) }), loading ? (_jsxs("div", { className: "flex items-center justify-center py-16 text-muted-foreground", children: [_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" }), " ", t("loadingQueue")] })) : (_jsxs(_Fragment, { children: [earlierRows.length > 0 && (_jsxs("section", { className: "mb-4 rounded-lg border border-primary/40 bg-muted/40 p-3", "aria-label": "Nog niet gescand van eerdere dagen", children: [_jsxs("h3", { className: "mb-2 text-sm font-semibold text-foreground", children: ["Nog niet gescand van eerdere dagen (", earlierRows.length, ")"] }), _jsx("ul", { className: "divide-y divide-border", children: earlierRows.map((row) => (_jsxs("li", { className: "flex flex-wrap items-center justify-between gap-2 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-medium", children: row.document_number ?? row.order_number ?? "Pakbon" }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [pickDayShortLabel(pickDayOf(row)), row.customer_name ? ` · ${row.customer_name}` : ""] })] }), _jsx(Button, { size: "sm", variant: "outline", disabled: busyId !== null || actionBusy, onClick: async () => {
|
|
1438
1449
|
await printAllForItem(row);
|
|
1439
1450
|
void refetchEarlier();
|
|
1440
|
-
}, children: "Opnieuw printen" })] }, row.id))) })] })), _jsx(QueueTable, { items: items.filter((item) => readinessById[item.id]?.replaced !== true), lockedIds: lockedIds, statuses: Array.isArray(statuses) ? statuses : [], documentTypes: Array.isArray(documentTypes) ? documentTypes : [], busyId: busyId, readinessById: readinessById, siteTimeZone: siteTz, pickDay: chosenDay ?? pickDay ?? null, waitingIds: waitingQueueIds, onPick: handlePick, onReprint: handleReprintLocked, onPrintAll: printAllForItem, onSelectPrinted: selectPrintedForReprint, onMarkPrinted: markPrinted, onPreview: setPreviewItem, t: t })] })), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("span", { className: "text-center text-sm text-muted-foreground sm:text-left", children: [t("page"), " ", filters.page + 1, " ", t("of"), " ", totalPages] }), _jsxs("div", { className: "grid grid-cols-2 gap-2 sm:flex", children: [_jsx(Button, { variant: "outline", className: "h-12 w-full sm:w-auto", disabled: filters.page === 0, onClick: () => setFilters((f) => ({ ...f, page: Math.max(0, f.page - 1) })), children: t("previous") }), _jsx(Button, { variant: "outline", className: "h-12 w-full sm:w-auto", disabled: filters.page + 1 >= totalPages, onClick: () => setFilters((f) => ({ ...f, page: f.page + 1 })), children: t("next") })] })] }), _jsx("div", { className: "fixed inset-x-0 bottom-0 z-40 border-t bg-background/95 p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] backdrop-blur md:hidden", children: _jsxs(Button, { size: "lg", className: "h-14 w-full text-lg", onClick: () => (pending ? confirmPending() : fetchNextLocked()), disabled: (busyId !== null || actionBusy) || fetchingData, children: [(busyId !== null || actionBusy) || fetchingData ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : pending && !readiness.ready ? (_jsx(RefreshCw, { className: "mr-2 h-5 w-5" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), _jsxs("span", { className: "truncate", children: [pending && !readiness.ready ? "Pakbon ophalen" : t("printNext"), pending?.document_number ? ` · ${pending.document_number}` : ""] })] }) }), _jsx(PreviewDialog, { item: previewItem, stationSlug: station.slug, onClose: () => setPreviewItem(null) })] }));
|
|
1451
|
+
}, children: "Opnieuw printen" })] }, row.id))) })] })), _jsx(QueueTable, { items: items.filter((item) => readinessById[item.id]?.replaced !== true), lockedIds: lockedIds, statuses: Array.isArray(statuses) ? statuses : [], documentTypes: Array.isArray(documentTypes) ? documentTypes : [], busyId: busyId, readinessById: readinessById, siteTimeZone: siteTz, pickDay: chosenDay ?? pickDay ?? null, waitingIds: waitingQueueIds, printStatus: printStatus, printStatusLoading: printStatusLoading, onPick: handlePick, onReprint: handleReprintLocked, onPrintAll: printAllForItem, onSelectPrinted: selectPrintedForReprint, onMarkPrinted: markPrinted, onPreview: setPreviewItem, t: t })] })), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("span", { className: "text-center text-sm text-muted-foreground sm:text-left", children: [t("page"), " ", filters.page + 1, " ", t("of"), " ", totalPages] }), _jsxs("div", { className: "grid grid-cols-2 gap-2 sm:flex", children: [_jsx(Button, { variant: "outline", className: "h-12 w-full sm:w-auto", disabled: filters.page === 0, onClick: () => setFilters((f) => ({ ...f, page: Math.max(0, f.page - 1) })), children: t("previous") }), _jsx(Button, { variant: "outline", className: "h-12 w-full sm:w-auto", disabled: filters.page + 1 >= totalPages, onClick: () => setFilters((f) => ({ ...f, page: f.page + 1 })), children: t("next") })] })] }), _jsx("div", { className: "fixed inset-x-0 bottom-0 z-40 border-t bg-background/95 p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] backdrop-blur md:hidden", children: _jsxs(Button, { size: "lg", className: "h-14 w-full text-lg", onClick: () => (pending ? confirmPending() : fetchNextLocked()), disabled: (busyId !== null || actionBusy) || fetchingData || (!pending && printStatusLoading), children: [(busyId !== null || actionBusy) || fetchingData ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : pending && !readiness.ready ? (_jsx(RefreshCw, { className: "mr-2 h-5 w-5" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), _jsxs("span", { className: "truncate", children: [pending && !readiness.ready ? "Pakbon ophalen" : t("printNext"), pending?.document_number ? ` · ${pending.document_number}` : ""] })] }) }), _jsx(PreviewDialog, { item: previewItem, stationSlug: station.slug, onClose: () => setPreviewItem(null) })] }));
|
|
1441
1452
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PickDocumentType, PickQueueItem, PickStatus } from "../../lib/pickTypes.js";
|
|
2
|
+
import { type PrintStatusResult } from "../../lib/pickPrintStatus.js";
|
|
2
3
|
import { type PickTranslator } from "../../lib/pickI18n.js";
|
|
3
4
|
interface Props {
|
|
4
5
|
items: PickQueueItem[];
|
|
@@ -23,6 +24,9 @@ interface Props {
|
|
|
23
24
|
siteTimeZone?: string | null;
|
|
24
25
|
/** Rijen met een printopdracht die nog niet voltooid is. */
|
|
25
26
|
waitingIds?: Set<string>;
|
|
27
|
+
/** 1.0.63: printstatus uit de Engine (één aanroep per scherm). */
|
|
28
|
+
printStatus?: PrintStatusResult | null;
|
|
29
|
+
printStatusLoading?: boolean;
|
|
26
30
|
onPick: (item: PickQueueItem) => void;
|
|
27
31
|
onReprint?: (item: PickQueueItem) => void;
|
|
28
32
|
onPrintAll?: (item: PickQueueItem) => void;
|
|
@@ -32,6 +36,6 @@ interface Props {
|
|
|
32
36
|
readOnly?: boolean;
|
|
33
37
|
t?: PickTranslator;
|
|
34
38
|
}
|
|
35
|
-
export declare function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, waitingIds, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, siteTimeZone, pickDay, }: Props): import("react").JSX.Element;
|
|
39
|
+
export declare function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, waitingIds, printStatus, printStatusLoading, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, siteTimeZone, pickDay, }: Props): import("react").JSX.Element;
|
|
36
40
|
export {};
|
|
37
41
|
//# sourceMappingURL=QueueTable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueueTable.d.ts","sourceRoot":"","sources":["../../../src/components/pick/QueueTable.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"QueueTable.d.ts","sourceRoot":"","sources":["../../../src/components/pick/QueueTable.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAKvF,OAAO,EAA+B,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAGhG,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAe5E,UAAU,KAAK;IACb,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzO,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4DAA4D;IAC5D,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,kEAAkE;IAClE,WAAW,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,CAAC,EAAE,cAAc,CAAC;CACpB;AA8DD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,QAAQ,EACR,aAAa,EACb,MAAM,EACN,aAAa,EACb,UAAU,EACV,WAAkB,EAClB,kBAA0B,EAC1B,MAAM,EACN,SAAS,EACT,UAAU,EACV,eAAe,EACf,aAAa,EACb,SAAS,EAGT,QAAQ,EACR,CAAC,EAAE,UAAU,EACb,YAAmB,EACnB,OAAc,GACf,EAAE,KAAK,+BA2fP"}
|
|
@@ -5,9 +5,8 @@ import { Badge, Button, Table, TableBody, TableCell, TableHead, TableHeader, Tab
|
|
|
5
5
|
import { AlertTriangle, Check, Eye, Loader2, Lock, Printer, RefreshCw, RotateCcw } from "lucide-react";
|
|
6
6
|
import { cartColumnInfo, comparePickQueue, dedupeByUnit, displayCartCount, displayPageCount, sinceLabel, unitTitleOf } from "../../lib/pickTypes.js";
|
|
7
7
|
import { duplicateNameTag } from "../../lib/pickRowState.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { PRINT_MANUAL, PRINT_NOT_NEEDED_HINT, printStage, printStageLabel } from "../../lib/pick142.js";
|
|
8
|
+
import { PRINT_MANUAL } from "../../lib/pick142.js";
|
|
9
|
+
import { isInPrint, printStatusLabel } from "../../lib/pickPrintStatus.js";
|
|
11
10
|
import { CART_PLAN_MISMATCH_MESSAGE, orderNumbersLabel } from "../../lib/pick142.js";
|
|
12
11
|
import { isRowPrintable, rowWaitMessage, rowWaitOf } from "../../lib/pick143.js";
|
|
13
12
|
import { getPickTranslator } from "../../lib/pickI18n.js";
|
|
@@ -70,21 +69,8 @@ function priorityTone(priority, urgent) {
|
|
|
70
69
|
return "bg-secondary text-secondary-foreground";
|
|
71
70
|
return "bg-muted text-muted-foreground";
|
|
72
71
|
}
|
|
73
|
-
export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, waitingIds, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, siteTimeZone = null, pickDay = null, }) {
|
|
72
|
+
export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, waitingIds, printStatus = null, printStatusLoading = false, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, siteTimeZone = null, pickDay = null, }) {
|
|
74
73
|
const t = translator ?? getPickTranslator("nl");
|
|
75
|
-
// Echte printstatus per regel uit de printopdrachten (één aanvraag, ververst mee).
|
|
76
|
-
const jobIds = Array.from(new Set((Array.isArray(items) ? items : []).filter((i) => i.printed_at && i.print_job_id).map((i) => i.print_job_id))).sort();
|
|
77
|
-
const jobsQuery = useQuery({
|
|
78
|
-
queryKey: ["pick", "rowPrintJobs", jobIds.join(",")],
|
|
79
|
-
enabled: jobIds.length > 0,
|
|
80
|
-
queryFn: () => pickApi.printJobsStatus(jobIds),
|
|
81
|
-
refetchInterval: (q) => {
|
|
82
|
-
const data = Array.isArray(q.state.data) ? q.state.data : [];
|
|
83
|
-
return data.some((j) => printStage(j) === "rendering") ? 5000 : 30000;
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
const jobsLoaded = jobsQuery.isSuccess;
|
|
87
|
-
const jobsById = new Map((Array.isArray(jobsQuery.data) ? jobsQuery.data : []).map((j) => [j.id, j]));
|
|
88
74
|
// Volgorde identiek aan de keuze van "volgende uitprinten" (zie
|
|
89
75
|
// comparePickQueue): niet-geprinte regels bovenaan, en bij gelijke stand op
|
|
90
76
|
// kar-nummer, zodat K1 boven K2 boven K3 staat en het printen van boven naar
|
|
@@ -117,7 +103,7 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
|
|
|
117
103
|
}, children: [_jsxs(TableCell, { className: "font-medium", children: [_jsxs("div", { className: "flex items-center gap-2", children: [unitTitleOf(item), dupTag && _jsxs("span", { className: "text-xs font-normal text-muted-foreground", children: ["(", dupTag, ")"] }), replaced && (_jsx("span", { className: "rounded bg-destructive/10 px-1.5 py-0.5 text-xs font-semibold text-destructive", title: readiness?.reason ?? undefined, children: "Vervangen" })), replaced && readiness?.reason && (_jsx("span", { className: "text-xs font-normal text-destructive", children: readiness.reason })), waiting && (_jsx("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs font-semibold text-muted-foreground", children: "Wacht op printer" })), sentElsewhereLines(item).map((line) => (_jsx("span", { className: "text-xs font-normal text-muted-foreground", children: line }, line))), warnings.length > 0 && (_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive", "aria-label": t("warning") }))] }), _jsx("div", { className: "text-xs text-muted-foreground", children: doc?.name ?? "-" })] }), _jsx(TableCell, { children: orderNumbersLabel(item) }), _jsx(TableCell, { children: item.customer_name }), _jsx(TableCell, { className: "text-right", children: item.line_count }), _jsx(TableCell, { className: "text-right", children: (() => {
|
|
118
104
|
const info = cartColumnInfo(item);
|
|
119
105
|
return (_jsxs("div", { className: "flex flex-col items-end", children: [_jsx("span", { children: info.carts }), info.cartLabel && (_jsx("span", { className: "text-xs text-muted-foreground", children: info.cartLabel })), info.reason && (_jsx("span", { className: "text-xs text-muted-foreground", children: info.reason }))] }));
|
|
120
|
-
})() }), _jsx(TableCell, { className: "text-right", children: printedSlipCount(item) ?? "—" }), _jsx(TableCell, { className: "text-right", children: displayPageCount(item.line_count) }), _jsxs(TableCell, { children: [_jsx(
|
|
106
|
+
})() }), _jsx(TableCell, { className: "text-right", children: printedSlipCount(item) ?? "—" }), _jsx(TableCell, { className: "text-right", children: displayPageCount(item.line_count) }), _jsxs(TableCell, { children: [_jsx(EnginePrintBadge, { item: item, result: printStatus, loading: printStatusLoading }), printed && (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: new Date(item.printed_at).toLocaleTimeString([], {
|
|
121
107
|
hour: "2-digit",
|
|
122
108
|
minute: "2-digit",
|
|
123
109
|
}) }))] }), _jsx(TableCell, { children: _jsx("span", { className: "rounded px-2 py-1 text-xs font-semibold " +
|
|
@@ -134,7 +120,7 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
|
|
|
134
120
|
}, children: _jsx(Check, { className: "h-5 w-5" }) })), blockedMessage(readinessById[item.id], siteTimeZone, item) && !printed ? (_jsx("span", { className: "max-w-56 text-right text-xs font-medium text-destructive", children: blockedMessage(readinessById[item.id], siteTimeZone, item) })) : printed ? (_jsxs(Button, { size: "sm", variant: "ghost", disabled: readOnly || busyId === item.id || checking || replaced, onClick: (e) => {
|
|
135
121
|
e.stopPropagation();
|
|
136
122
|
(onPrintAll ?? onReprint ?? onPick)(item);
|
|
137
|
-
}, children: [checking ? (_jsx(Loader2, { className: "mr-1 h-4 w-4 animate-spin" })) : ready ? (_jsx(RotateCcw, { className: "mr-1 h-4 w-4" })) : (_jsx(RefreshCw, { className: "mr-1 h-4 w-4" })), replaced ? "Vervangen" : checking ? "Pakbon controleren" : ready ? t("print") : "Pakbon ophalen"] })) : locked ? (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(Lock, { className: "h-3.5 w-3.5" }), " ", t("inProgress")] })) : (_jsxs(Button, { size: "sm", variant: "outline", disabled: readOnly || busyId === item.id || checking || replaced, onClick: (e) => {
|
|
123
|
+
}, children: [checking ? (_jsx(Loader2, { className: "mr-1 h-4 w-4 animate-spin" })) : ready ? (_jsx(RotateCcw, { className: "mr-1 h-4 w-4" })) : (_jsx(RefreshCw, { className: "mr-1 h-4 w-4" })), replaced ? "Vervangen" : checking ? "Pakbon controleren" : ready ? t("print") : "Pakbon ophalen"] })) : isInPrint(printStatus?.byId.get(item.id)) || (printStatusLoading && !printed) ? (_jsxs(Button, { size: "sm", variant: "outline", disabled: true, onClick: (e) => e.stopPropagation(), children: [_jsx(Loader2, { className: "mr-1 h-4 w-4 animate-spin" }), printStatusLoading ? "…" : "Wordt geprint"] })) : locked ? (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(Lock, { className: "h-3.5 w-3.5" }), " ", t("inProgress")] })) : (_jsxs(Button, { size: "sm", variant: "outline", disabled: readOnly || busyId === item.id || checking || replaced, onClick: (e) => {
|
|
138
124
|
e.stopPropagation();
|
|
139
125
|
(onPrintAll ?? onPick)(item);
|
|
140
126
|
}, children: [checking ? (_jsx(Loader2, { className: "mr-1 h-4 w-4 animate-spin" })) : !ready ? (_jsx(RefreshCw, { className: "mr-1 h-4 w-4" })) : (_jsx(Printer, { className: "mr-1 h-4 w-4" })), replaced ? "Vervangen" : checking ? "Pakbon controleren" : ready ? t("print") : "Pakbon ophalen"] }))] }) })] }, item.id));
|
|
@@ -161,7 +147,7 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
|
|
|
161
147
|
}, children: [_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_auto] items-start gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsxs("span", { className: "truncate text-lg font-bold text-foreground", children: [unitTitleOf(item), dupTag && _jsxs("span", { className: "text-xs font-normal text-muted-foreground", children: ["(", dupTag, ")"] }), replaced && (_jsx("span", { className: "rounded bg-destructive/10 px-1.5 py-0.5 text-xs font-semibold text-destructive", title: readiness?.reason ?? undefined, children: "Vervangen" })), replaced && readiness?.reason && (_jsx("span", { className: "text-xs font-normal text-destructive", children: readiness.reason })), waiting && (_jsx("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs font-semibold text-muted-foreground", children: "Wacht op printer" }))] }), warnings.length > 0 && (_jsx(AlertTriangle, { className: "h-4 w-4 shrink-0 text-destructive", "aria-label": t("warning") }))] }), _jsx("p", { className: "truncate text-xs text-muted-foreground", children: doc?.name ?? "-" })] }), _jsxs("div", { className: "flex shrink-0 items-start gap-1", children: [onPreview && (_jsx("button", { type: "button", "aria-label": "Voorbeeld " + item.document_number, title: "Voorbeeld " + item.document_number, className: "inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground", onClick: (e) => {
|
|
162
148
|
e.stopPropagation();
|
|
163
149
|
onPreview(item);
|
|
164
|
-
}, children: _jsx(Eye, { className: "h-5 w-5" }) })), _jsxs("div", { className: "flex shrink-0 flex-col items-end gap-1", children: [_jsx(
|
|
150
|
+
}, children: _jsx(Eye, { className: "h-5 w-5" }) })), _jsxs("div", { className: "flex shrink-0 flex-col items-end gap-1", children: [_jsx(EnginePrintBadge, { item: item, result: printStatus, loading: printStatusLoading }), printed && (_jsx("span", { className: "text-xs text-muted-foreground", children: new Date(item.printed_at).toLocaleTimeString([], {
|
|
165
151
|
hour: "2-digit",
|
|
166
152
|
minute: "2-digit",
|
|
167
153
|
}) })), _jsx("span", { className: "rounded px-2 py-0.5 text-xs font-semibold " +
|
|
@@ -185,7 +171,7 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
|
|
|
185
171
|
})(), _jsx(CartSteps, { printed: printed, waiting: waiting }), _jsxs("div", { className: "mt-3", children: [blockedMessage(readiness, siteTimeZone, item) && !printed ? (_jsx("p", { className: "rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm font-medium text-destructive", children: blockedMessage(readiness, siteTimeZone, item) })) : printed ? (_jsxs(Button, { size: "lg", variant: "outline", className: "h-12 w-full", disabled: readOnly || busyId === item.id || checking || replaced, onClick: (e) => {
|
|
186
172
|
e.stopPropagation();
|
|
187
173
|
(onPrintAll ?? onReprint ?? onPick)(item);
|
|
188
|
-
}, children: [checking ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : ready ? (_jsx(RotateCcw, { className: "mr-2 h-4 w-4" })) : (_jsx(RefreshCw, { className: "mr-2 h-4 w-4" })), replaced ? "Vervangen" : checking ? "Pakbon controleren" : ready ? t("print") : "Pakbon ophalen"] })) : locked ? (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(Lock, { className: "h-3.5 w-3.5" }), " ", t("inProgress")] })) : (_jsxs(Button, { size: "lg", className: "h-12 w-full", disabled: readOnly || busyId === item.id || checking || replaced, onClick: (e) => {
|
|
174
|
+
}, children: [checking ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : ready ? (_jsx(RotateCcw, { className: "mr-2 h-4 w-4" })) : (_jsx(RefreshCw, { className: "mr-2 h-4 w-4" })), replaced ? "Vervangen" : checking ? "Pakbon controleren" : ready ? t("print") : "Pakbon ophalen"] })) : isInPrint(printStatus?.byId.get(item.id)) || (printStatusLoading && !printed) ? (_jsxs(Button, { size: "sm", variant: "outline", disabled: true, onClick: (e) => e.stopPropagation(), children: [_jsx(Loader2, { className: "mr-1 h-4 w-4 animate-spin" }), printStatusLoading ? "…" : "Wordt geprint"] })) : locked ? (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(Lock, { className: "h-3.5 w-3.5" }), " ", t("inProgress")] })) : (_jsxs(Button, { size: "lg", className: "h-12 w-full", disabled: readOnly || busyId === item.id || checking || replaced, onClick: (e) => {
|
|
189
175
|
e.stopPropagation();
|
|
190
176
|
(onPrintAll ?? onPick)(item);
|
|
191
177
|
}, children: [checking ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : !ready ? (_jsx(RefreshCw, { className: "mr-2 h-4 w-4" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), replaced ? "Vervangen" : checking ? "Pakbon controleren" : ready ? t("print") : "Pakbon ophalen"] })), !printed && onMarkPrinted && (_jsxs("details", { className: "mt-2 text-sm", onClick: (e) => e.stopPropagation(), children: [_jsx("summary", { className: "cursor-pointer select-none text-muted-foreground", children: "Meer" }), _jsxs(Button, { size: "sm", variant: "ghost", className: "mt-1 w-full", disabled: readOnly || busyId === item.id, onClick: (e) => {
|
|
@@ -196,16 +182,13 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
|
|
|
196
182
|
}), safeItems.length === 0 && (_jsx("div", { className: "rounded-lg border py-10 text-center text-muted-foreground", children: t("emptyQueue") }))] })] }));
|
|
197
183
|
}
|
|
198
184
|
/** Statuslabel van een regel: alleen de echte stand uit de printopdracht, nooit een aanname. */
|
|
199
|
-
function
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (!
|
|
185
|
+
function EnginePrintBadge({ item, result, loading }) {
|
|
186
|
+
const status = result?.byId.get(item.id);
|
|
187
|
+
// Handmatig gemarkeerd: geprint zonder printopdracht.
|
|
188
|
+
if (!loading && status?.code === "geen" && item.printed_at && !item.print_job_id) {
|
|
203
189
|
return _jsx(Badge, { variant: "secondary", children: PRINT_MANUAL });
|
|
204
|
-
if (!job && !jobsLoaded)
|
|
205
|
-
return _jsx(Badge, { variant: "secondary", children: "Status laden\u2026" });
|
|
206
|
-
const stage = printStage(job);
|
|
207
|
-
if (stage === "not_needed") {
|
|
208
|
-
return _jsx(Badge, { variant: "outline", className: "text-muted-foreground", title: PRINT_NOT_NEEDED_HINT, children: printStageLabel(job) });
|
|
209
190
|
}
|
|
210
|
-
|
|
191
|
+
const l = printStatusLabel({ status, loading: loading && !result, beschikbaar: result ? result.beschikbaar : true, reden: result?.reden ?? null });
|
|
192
|
+
const variant = l.tone === "failed" ? "destructive" : l.tone === "todo" ? "default" : l.tone === "unknown" ? "outline" : "secondary";
|
|
193
|
+
return (_jsxs("div", { className: "flex flex-col items-start gap-0.5", children: [_jsx(Badge, { variant: variant, title: l.reason ?? undefined, children: l.label }), l.reason && _jsx("span", { className: "max-w-56 text-xs text-muted-foreground", children: l.reason })] }));
|
|
211
194
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type PrintStatusResult } from "../lib/pickPrintStatus.js";
|
|
2
|
+
/**
|
|
3
|
+
* Eén aanroep voor alle zichtbare regels. Openbaar station (slug):
|
|
4
|
+
* pickstation_print_status; ingelogd scherm: logistics_print_status direct.
|
|
5
|
+
* Fout: "niet beschikbaar" met reden, nooit terugvallen op printed_at.
|
|
6
|
+
*/
|
|
7
|
+
export declare function fetchPrintStatus(ids: string[], slug: string | null): Promise<PrintStatusResult>;
|
|
8
|
+
export declare function usePickPrintStatus(ids: string[], slug: string | null, enabled?: boolean): {
|
|
9
|
+
result: PrintStatusResult | null;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
inPrint: Set<string>;
|
|
12
|
+
refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<PrintStatusResult, Error>>;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=usePickPrintStatus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePickPrintStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickPrintStatus.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgC,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAQ9F;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgBrG;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,UAAO;;;;;EAkBpF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { supabase } from "@flowselections/core";
|
|
4
|
+
import { keyedRpc } from "../lib/pick159.js";
|
|
5
|
+
import { inPrintIds, parsePrintStatus } from "../lib/pickPrintStatus.js";
|
|
6
|
+
import { pickMeasure } from "../lib/pickPerf.js";
|
|
7
|
+
const db = keyedRpc(supabase);
|
|
8
|
+
const MAX_IDS = 500;
|
|
9
|
+
/**
|
|
10
|
+
* Eén aanroep voor alle zichtbare regels. Openbaar station (slug):
|
|
11
|
+
* pickstation_print_status; ingelogd scherm: logistics_print_status direct.
|
|
12
|
+
* Fout: "niet beschikbaar" met reden, nooit terugvallen op printed_at.
|
|
13
|
+
*/
|
|
14
|
+
export async function fetchPrintStatus(ids, slug) {
|
|
15
|
+
const list = ids.slice(0, MAX_IDS);
|
|
16
|
+
const { data, error } = await pickMeasure("printstatus", () => slug
|
|
17
|
+
? db.rpc("pickstation_print_status", { p_slug: slug, p_queue_item_ids: list })
|
|
18
|
+
: db.rpc("logistics_print_status", { p_queue_item_ids: list }));
|
|
19
|
+
if (error) {
|
|
20
|
+
const missing = /could not find|does not exist|PGRST202/i.test(error.message);
|
|
21
|
+
return {
|
|
22
|
+
beschikbaar: false,
|
|
23
|
+
reden: missing ? "Printstatus nog niet beschikbaar: de Logistiek Engine is te oud." : "Printstatus kon niet worden opgehaald.",
|
|
24
|
+
byId: new Map(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return parsePrintStatus(data);
|
|
28
|
+
}
|
|
29
|
+
export function usePickPrintStatus(ids, slug, enabled = true) {
|
|
30
|
+
const sorted = useMemo(() => Array.from(new Set(ids)).sort(), [ids]);
|
|
31
|
+
const q = useQuery({
|
|
32
|
+
queryKey: ["pick", "printStatus", slug ?? "-", sorted.join(",")],
|
|
33
|
+
enabled: enabled && sorted.length > 0,
|
|
34
|
+
queryFn: () => fetchPrintStatus(sorted, slug),
|
|
35
|
+
refetchInterval: (query) => {
|
|
36
|
+
const d = query.state.data;
|
|
37
|
+
return d && inPrintIds(d).size > 0 ? 3000 : 20000;
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const inPrint = useMemo(() => inPrintIds(q.data), [q.data]);
|
|
41
|
+
return {
|
|
42
|
+
result: q.data ?? null,
|
|
43
|
+
loading: sorted.length > 0 && q.data === undefined,
|
|
44
|
+
inPrint,
|
|
45
|
+
refetch: q.refetch,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -29,6 +29,8 @@ export declare function usePickQueue(args: {
|
|
|
29
29
|
pendingCount: number;
|
|
30
30
|
printedCount: number;
|
|
31
31
|
urgentCount: number;
|
|
32
|
+
/** Tellingen nog niet geladen: kopregel toont "…". */
|
|
33
|
+
countsLoading: boolean;
|
|
32
34
|
loading: boolean;
|
|
33
35
|
error: string | null;
|
|
34
36
|
lockedIds: Set<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePickQueue.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickQueue.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAY,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"usePickQueue.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickQueue.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAY,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAK9E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,EAAE,YAS5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;;;;;;;IAqNG,sDAAsD;;;;;;IAMtD,gEAAgE;;IAEhE,6EAA6E;;;EAIhF;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM;;EAuBhG;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,iFAOnF;AACD,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,OAAO,UAAO;;;YAQzC;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAEpF"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
3
3
|
import { pickApi, pickDb } from "../lib/pickApi.js";
|
|
4
4
|
import { safeArray } from "../lib/pickTypes.js";
|
|
5
|
+
import { isRowOpen } from "../lib/pick143.js";
|
|
6
|
+
import { pickMark, pickMeasure } from "../lib/pickPerf.js";
|
|
5
7
|
export const defaultFilters = {
|
|
6
8
|
country: null,
|
|
7
9
|
search: "",
|
|
@@ -64,7 +66,7 @@ export function usePickQueue(args) {
|
|
|
64
66
|
const pickDayQuery = useQuery({
|
|
65
67
|
queryKey: ["pick", "pickDay"],
|
|
66
68
|
enabled: enabled && !syncQuery.isLoading,
|
|
67
|
-
queryFn: () => pickApi.currentPickDay(),
|
|
69
|
+
queryFn: () => pickMeasure("pickdag", () => pickApi.currentPickDay()),
|
|
68
70
|
staleTime: 30000,
|
|
69
71
|
});
|
|
70
72
|
const pickDay = pickDayOverride ?? pickDayQuery.data ?? null;
|
|
@@ -96,7 +98,7 @@ export function usePickQueue(args) {
|
|
|
96
98
|
queryKey: key,
|
|
97
99
|
// Pas laden als de pickdag bekend is, anders flitst een oude lijst.
|
|
98
100
|
enabled: enabled && (pickDayOverride != null || pickDayQuery.isFetched),
|
|
99
|
-
queryFn: () => pickApi.queue({
|
|
101
|
+
queryFn: () => pickMeasure("wachtrij", () => pickApi.queue({
|
|
100
102
|
stationId,
|
|
101
103
|
screenId,
|
|
102
104
|
country: filters.country,
|
|
@@ -108,15 +110,16 @@ export function usePickQueue(args) {
|
|
|
108
110
|
sortRules: filters.sortRules,
|
|
109
111
|
page: filters.page,
|
|
110
112
|
pageSize: filters.pageSize,
|
|
111
|
-
}),
|
|
113
|
+
})),
|
|
112
114
|
// Vorige lijst alleen vasthouden bij filteren/bladeren binnen hetzelfde station en dezelfde pickdag.
|
|
113
115
|
placeholderData: (prev, prevQuery) => (prevQuery && sameQueueScope(prevQuery.queryKey, key) ? prev : undefined),
|
|
114
116
|
});
|
|
115
117
|
const countsQuery = useQuery({
|
|
116
118
|
queryKey: ["pick", "dayCounts", stationId ?? "-", screenId ?? "-", pickDay ?? "-"],
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
// 1.0.63: pas tellen als de pickdag bekend is (anders telt de database alle
|
|
120
|
+
// dagen en springt de kopregel), en geen oude telling van een andere dag tonen.
|
|
121
|
+
enabled: enabled && pickDay != null,
|
|
122
|
+
queryFn: () => pickMeasure("dagtelling", () => pickApi.dayCounts({ stationId, screenId, pickDay })),
|
|
120
123
|
});
|
|
121
124
|
// Locks komen primair via realtime binnen; deze poll is alleen terugval.
|
|
122
125
|
const locksQuery = useQuery({
|
|
@@ -131,6 +134,7 @@ export function usePickQueue(args) {
|
|
|
131
134
|
queryClient.invalidateQueries({ queryKey: ["pick", "dayCounts"] });
|
|
132
135
|
queryClient.invalidateQueries({ queryKey: ["pick", "countryCounts"] });
|
|
133
136
|
queryClient.invalidateQueries({ queryKey: ["pick", "dashboard"] });
|
|
137
|
+
queryClient.invalidateQueries({ queryKey: ["pick", "printStatus"] });
|
|
134
138
|
}, [queryClient]);
|
|
135
139
|
/**
|
|
136
140
|
* Realtime-meldingen komen bij een Engine-sync in tientallen tegelijk binnen.
|
|
@@ -175,14 +179,31 @@ export function usePickQueue(args) {
|
|
|
175
179
|
pickDb.removeChannel(channel);
|
|
176
180
|
};
|
|
177
181
|
}, [enabled, stationId, invalidate]);
|
|
182
|
+
// Laadtijd: van openen tot de eerste lijst binnen is.
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (enabled)
|
|
185
|
+
pickMark("start");
|
|
186
|
+
}, [enabled]);
|
|
187
|
+
const firstReady = useRef(false);
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
if (!firstReady.current && queueQuery.isSuccess) {
|
|
190
|
+
firstReady.current = true;
|
|
191
|
+
pickMark("lijst-klaar");
|
|
192
|
+
}
|
|
193
|
+
}, [queueQuery.isSuccess]);
|
|
194
|
+
// Afgeronde of geannuleerde rijen (bv. na een kar-vervanging) nooit tonen,
|
|
195
|
+
// ook niet uit de vastgehouden vorige lijst.
|
|
196
|
+
const openItems = useMemo(() => safeArray(queueQuery.data?.items).filter((i) => isRowOpen(i)), [queueQuery.data]);
|
|
178
197
|
const lockedIds = useMemo(() => new Set(safeArray(locksQuery.data).map((l) => l.queue_item_id)), [locksQuery.data]);
|
|
179
198
|
return {
|
|
180
|
-
items:
|
|
199
|
+
items: openItems,
|
|
181
200
|
total: queueQuery.data?.total ?? 0,
|
|
182
201
|
pickDay,
|
|
183
202
|
pendingCount: countsQuery.data?.pending ?? 0,
|
|
184
203
|
printedCount: countsQuery.data?.printed ?? 0,
|
|
185
204
|
urgentCount: countsQuery.data?.urgent ?? 0,
|
|
205
|
+
/** Tellingen nog niet geladen: kopregel toont "…". */
|
|
206
|
+
countsLoading: countsQuery.data === undefined,
|
|
186
207
|
loading: queueQuery.isPending,
|
|
187
208
|
error: queueQuery.error instanceof Error ? queueQuery.error.message : null,
|
|
188
209
|
lockedIds,
|