@flowselections/pick-schermen-kwekers 1.0.21 → 1.0.23

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.
Files changed (67) hide show
  1. package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
  2. package/dist-lib/components/pick/PickScherm.js +56 -27
  3. package/dist-lib/hooks/usePickConfig.d.ts +11 -11
  4. package/dist-lib/hooks/usePickConfig.d.ts.map +1 -1
  5. package/dist-lib/hooks/usePickQueue.d.ts +5 -3
  6. package/dist-lib/hooks/usePickQueue.d.ts.map +1 -1
  7. package/dist-lib/hooks/usePickQueue.js +17 -4
  8. package/dist-lib/hooks/usePickReferenceData.d.ts +1 -1
  9. package/dist-lib/hooks/usePickReferenceData.d.ts.map +1 -1
  10. package/dist-lib/integrations/supabase/auth-middleware.d.ts +4754 -230
  11. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  12. package/dist-lib/integrations/supabase/client.d.ts +4754 -230
  13. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  14. package/dist-lib/integrations/supabase/client.js +1 -1
  15. package/dist-lib/integrations/supabase/client.server.d.ts +4754 -230
  16. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  17. package/dist-lib/integrations/supabase/client.server.js +1 -1
  18. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +1 -1
  19. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
  20. package/dist-lib/integrations/supabase/previewAuthStorage.js +8 -1
  21. package/dist-lib/integrations/supabase/types.d.ts +4795 -203
  22. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  23. package/dist-lib/lib/__tests__/pickRobustness.test.d.ts +2 -0
  24. package/dist-lib/lib/__tests__/pickRobustness.test.d.ts.map +1 -0
  25. package/dist-lib/lib/__tests__/pickRobustness.test.js +68 -0
  26. package/dist-lib/lib/pickApi.d.ts +25 -1
  27. package/dist-lib/lib/pickApi.d.ts.map +1 -1
  28. package/dist-lib/lib/pickApi.js +56 -3
  29. package/dist-lib/lib/pickRetry.d.ts +13 -0
  30. package/dist-lib/lib/pickRetry.d.ts.map +1 -0
  31. package/dist-lib/lib/pickRetry.js +52 -0
  32. package/dist-lib/lib/pickUiText.d.ts.map +1 -1
  33. package/dist-lib/lib/pickUiText.js +5 -3
  34. package/dist-lib/lib/pickVerify.d.ts +15 -0
  35. package/dist-lib/lib/pickVerify.d.ts.map +1 -0
  36. package/dist-lib/lib/pickVerify.js +32 -0
  37. package/package.json +5 -4
  38. package/dist-lib/lib/layoutApi.d.ts +0 -23
  39. package/dist-lib/lib/layoutApi.d.ts.map +0 -1
  40. package/dist-lib/lib/layoutApi.js +0 -94
  41. package/dist-lib/lib/layoutMaker/documentProfiles.d.ts +0 -50
  42. package/dist-lib/lib/layoutMaker/documentProfiles.d.ts.map +0 -1
  43. package/dist-lib/lib/layoutMaker/documentProfiles.js +0 -458
  44. package/dist-lib/lib/layoutMaker/documentTypes.d.ts +0 -123
  45. package/dist-lib/lib/layoutMaker/documentTypes.d.ts.map +0 -1
  46. package/dist-lib/lib/layoutMaker/documentTypes.js +0 -74
  47. package/dist-lib/lib/layoutMaker/logoLibrary.d.ts +0 -13
  48. package/dist-lib/lib/layoutMaker/logoLibrary.d.ts.map +0 -1
  49. package/dist-lib/lib/layoutMaker/logoLibrary.js +0 -54
  50. package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts +0 -196
  51. package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts.map +0 -1
  52. package/dist-lib/lib/layoutMaker/pakbonBuilder.js +0 -813
  53. package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts +0 -48
  54. package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts.map +0 -1
  55. package/dist-lib/lib/layoutMaker/pakbonHtml.js +0 -703
  56. package/dist-lib/lib/layoutRenderer.d.ts +0 -7
  57. package/dist-lib/lib/layoutRenderer.d.ts.map +0 -1
  58. package/dist-lib/lib/layoutRenderer.js +0 -233
  59. package/dist-lib/lib/layoutTypes.d.ts +0 -84
  60. package/dist-lib/lib/layoutTypes.d.ts.map +0 -1
  61. package/dist-lib/lib/layoutTypes.js +0 -25
  62. package/dist-lib/lib/orderContext.d.ts +0 -50
  63. package/dist-lib/lib/orderContext.d.ts.map +0 -1
  64. package/dist-lib/lib/orderContext.js +0 -162
  65. package/dist-lib/lib/pakbonOrderInput.d.ts +0 -8
  66. package/dist-lib/lib/pakbonOrderInput.d.ts.map +0 -1
  67. package/dist-lib/lib/pakbonOrderInput.js +0 -150
@@ -1 +1 @@
1
- {"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AAqCA,OAAO,EAUL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AA0B7B,UAAU,KAAK;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAeD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,+BAgrDpD"}
1
+ {"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AAqCA,OAAO,EAUL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AA2B7B,UAAU,KAAK;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAeD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,+BAotDpD"}
@@ -11,6 +11,7 @@ import { getSessionId, pickApi } from "../../lib/pickApi";
11
11
  import { sendLogisticsEvent } from "../../lib/logisticsApi";
12
12
  import { completeLogisticsTaskForItem } from "../../lib/pickPrint";
13
13
  import { isPdfOnlyFailure, pickReadiness, printedCartIdsOf, pdfSaveWarning, unitRefOf, unitTitleOf, } from "../../lib/pickTypes";
14
+ import { rowFingerprint, rowsToVerify } from "../../lib/pickVerify";
14
15
  import { getPickTranslator } from "../../lib/pickI18n";
15
16
  import { friendlyPickError, getPickUiTexts } from "../../lib/pickUiText";
16
17
  import { getPrintJobTexts, printJobStatusLabel } from "../../lib/pickPrintJobText";
@@ -139,12 +140,20 @@ export function PickScherm({ station, onBack }) {
139
140
  return () => clearTimeout(timer);
140
141
  }, [searchInput]);
141
142
  const effectiveFilters = useMemo(() => ({ ...filters, country: null, sortRules: [] }), [filters]);
142
- const { items, total, loading, lockedIds, refresh, pendingCount, printedCount, urgentCount, realtimeOk, pickDay, rebuiltAt, } = usePickQueue({
143
+ const { items, total, loading, lockedIds, refresh, pendingCount, printedCount, urgentCount, realtimeOk, pickDay, rebuiltAt, syncError, } = usePickQueue({
143
144
  stationId: station.id,
144
145
  filters: effectiveFilters,
145
146
  enabled: lang !== null,
146
147
  pickDayOverride: chosenDay,
147
148
  });
149
+ // Eén toast per nieuwe syncfout; de rode balk blijft staan tot hij is opgelost.
150
+ const lastSyncError = useRef(null);
151
+ useEffect(() => {
152
+ if (syncError && syncError !== lastSyncError.current) {
153
+ toast.error(`Pickwachtrij kan niet worden bijgewerkt: ${syncError}`);
154
+ }
155
+ lastSyncError.current = syncError;
156
+ }, [syncError]);
148
157
  const { data: pickDays } = usePickDays(lang !== null);
149
158
  const safePickDays = Array.isArray(pickDays) ? pickDays : [];
150
159
  const dayLabel = useCallback((day) => new Date(`${day}T00:00:00`).toLocaleDateString(t.lang === "en" ? "en-GB" : "nl-NL", {
@@ -252,37 +261,57 @@ export function PickScherm({ station, onBack }) {
252
261
  const visibleIdsKey = useMemo(() => (Array.isArray(items) ? items.map((item) => item.id).join(",") : ""), [items]);
253
262
  const itemsRef = useRef([]);
254
263
  itemsRef.current = Array.isArray(items) ? items : [];
264
+ const verifyMemo = useRef(new Map());
255
265
  useEffect(() => {
256
266
  let cancelled = false;
267
+ let running = false;
257
268
  const verifyVisibleRows = async () => {
269
+ if (running)
270
+ return;
258
271
  const visibleItems = itemsRef.current;
259
- setCheckProgress({ done: 0, total: visibleItems.length });
260
- if (visibleItems.length === 0)
272
+ const todo = rowsToVerify(visibleItems, verifyMemo.current, Date.now());
273
+ if (todo.length === 0)
261
274
  return;
262
- let done = 0;
263
- await Promise.all(visibleItems.map(async (item) => {
264
- let entry = {
265
- checking: false,
266
- ready: false,
267
- reason: "De bron kon de pakbon nog niet bevestigen.",
268
- };
269
- try {
270
- const [plan, status] = await Promise.all([
271
- pickApi.queueCartPlan(item.id),
272
- pickApi.cartPlanStatus(unitRefOf(item)),
273
- ]);
274
- const state = pickReadiness(plan, status, item);
275
- entry = { checking: false, ready: state.ready, reason: state.reason };
276
- }
277
- catch {
278
- // fail closed: de regel blijft "Pakbon ophalen"
275
+ // Laadbalk alleen voor regels die nog nooit gecontroleerd zijn.
276
+ const fresh = todo.filter((item) => !verifyMemo.current.has(item.id)).length;
277
+ if (fresh > 0)
278
+ setCheckProgress({ done: 0, total: fresh });
279
+ running = true;
280
+ const next = {};
281
+ try {
282
+ const results = await pickApi.verifyRows(todo.map((item) => ({ id: item.id, ref: unitRefOf(item) || null })));
283
+ const byId = new Map(results.map((r) => [r.id, r]));
284
+ const now = Date.now();
285
+ for (const item of todo) {
286
+ const r = byId.get(item.id);
287
+ let entry = {
288
+ checking: false,
289
+ ready: false,
290
+ reason: "De bron kon de pakbon nog niet bevestigen.",
291
+ };
292
+ if (r && !r.error) {
293
+ const state = pickReadiness(r.plan, r.status, item);
294
+ entry = { checking: false, ready: state.ready, reason: state.reason };
295
+ }
296
+ next[item.id] = entry;
297
+ verifyMemo.current.set(item.id, {
298
+ fingerprint: rowFingerprint(item),
299
+ ready: entry.ready,
300
+ checkedAt: now,
301
+ });
279
302
  }
280
- if (cancelled)
281
- return;
282
- done += 1;
283
- setReadinessById((prev) => ({ ...prev, [item.id]: entry }));
284
- setCheckProgress({ done, total: visibleItems.length });
285
- }));
303
+ }
304
+ catch {
305
+ // fail closed: bestaande uitkomst blijft staan; nooit bevestigde regels blijven "Pakbon ophalen"
306
+ }
307
+ finally {
308
+ running = false;
309
+ }
310
+ if (cancelled)
311
+ return;
312
+ if (Object.keys(next).length > 0)
313
+ setReadinessById((prev) => ({ ...prev, ...next }));
314
+ setCheckProgress({ done: 0, total: 0 });
286
315
  };
287
316
  void verifyVisibleRows();
288
317
  const timer = window.setInterval(() => void verifyVisibleRows(), 15000);
@@ -1001,7 +1030,7 @@ export function PickScherm({ station, onBack }) {
1001
1030
  : Math.round((checkDone / checkTotal) * 100);
1002
1031
  return (_jsxs("div", { className: "space-y-4 pb-24 md:pb-0", children: [busyLoading && (_jsxs("div", { className: "space-y-1", role: "status", "aria-live": "polite", "aria-label": "Gegevens worden geladen", children: [_jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [_jsx("span", { children: loading || loadingDay
1003
1032
  ? "Wachtrij wordt geladen…"
1004
- : `Pakbonnen controleren bij de bron (${checkDone} van ${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")] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "lg", className: "h-12 px-3", onClick: () => 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: () => 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, 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" })), "Print eerstvolgende ", cartsPerPrint, " karren"] })), _jsxs(Button, { size: "lg", className: "hidden h-14 px-8 text-lg md:inline-flex", onClick: () => (pending ? confirmPending() : fetchNext()), disabled: busyId !== null || fetchingData, children: [busyId !== null || 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"), pending?.document_number ? ` · ${pending.document_number}` : ""] })] })] }), !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." })] })), _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, children: t("cancel") }), _jsxs(Button, { size: "lg", className: "h-14 w-full px-8 text-lg sm:w-auto", onClick: confirmPending, disabled: busyId !== null || 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
1033
+ : `Pakbonnen controleren bij de bron (${checkDone} van ${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")] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "lg", className: "h-12 px-3", onClick: () => 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: () => 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, 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" })), "Print eerstvolgende ", cartsPerPrint, " karren"] })), _jsxs(Button, { size: "lg", className: "hidden h-14 px-8 text-lg md:inline-flex", onClick: () => (pending ? confirmPending() : fetchNext()), disabled: busyId !== null || fetchingData, children: [busyId !== null || 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"), pending?.document_number ? ` · ${pending.document_number}` : ""] })] })] }), 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: ["Pickwachtrij kan niet worden bijgewerkt: ", 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." })] })), _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, children: t("cancel") }), _jsxs(Button, { size: "lg", className: "h-14 w-full px-8 text-lg sm:w-auto", onClick: confirmPending, disabled: busyId !== null || 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
1005
1034
  ? "De pakbon wordt bij de bron opgevraagd. Zodra alles compleet is, verschijnt de printknop weer."
1006
1035
  : planReason
1007
1036
  ? `${planReason} Klik op "Pakbon ophalen" om hem bij de bron op te vragen.`
@@ -1,15 +1,15 @@
1
- export declare function usePickCountries(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickCountry[]>, Error>;
2
- export declare function usePickStatuses(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickStatus[]>, Error>;
3
- export declare function usePickPrinters(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickPrinter[]>, Error>;
4
- export declare function usePickDocumentTypes(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickDocumentType[]>, Error>;
5
- export declare function usePickStationTypes(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickStationType[]>, Error>;
6
- export declare function usePickTasks(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickTask[]>, Error>;
7
- export declare function usePickStations(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickStation[]>, Error>;
1
+ export declare function usePickCountries(): import("@tanstack/react-query").UseQueryResult<import("..").PickCountry[], Error>;
2
+ export declare function usePickStatuses(): import("@tanstack/react-query").UseQueryResult<import("..").PickStatus[], Error>;
3
+ export declare function usePickPrinters(): import("@tanstack/react-query").UseQueryResult<import("..").PickPrinter[], Error>;
4
+ export declare function usePickDocumentTypes(): import("@tanstack/react-query").UseQueryResult<import("..").PickDocumentType[], Error>;
5
+ export declare function usePickStationTypes(): import("@tanstack/react-query").UseQueryResult<import("..").PickStationType[], Error>;
6
+ export declare function usePickTasks(): import("@tanstack/react-query").UseQueryResult<import("..").PickTask[], Error>;
7
+ export declare function usePickStations(): import("@tanstack/react-query").UseQueryResult<import("..").PickStation[], Error>;
8
8
  /** Actieve printplekken uit de Layout maker. */
9
- export declare function usePickPrintPlekken(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickPrintPlek[]>, Error>;
9
+ export declare function usePickPrintPlekken(): import("@tanstack/react-query").UseQueryResult<import("..").PickPrintPlek[], Error>;
10
10
  /** Koppelingen pickstation → printplek (beheerpagina). */
11
- export declare function useStationPrintPlekken(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickStationPrintPlekRow[]>, Error>;
11
+ export declare function useStationPrintPlekken(): import("@tanstack/react-query").UseQueryResult<import("..").PickStationPrintPlekRow[], Error>;
12
12
  /** De printplek van één pickstation (ook in openbare pickschermen). */
13
- export declare function useStationPrintPlek(stationId?: string): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickStationPrintPlek | null>, Error>;
14
- export declare function usePickScreens(stationId?: string): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickScreen[]>, Error>;
13
+ export declare function useStationPrintPlek(stationId?: string): import("@tanstack/react-query").UseQueryResult<import("..").PickStationPrintPlek | null, Error>;
14
+ export declare function usePickScreens(stationId?: string): import("@tanstack/react-query").UseQueryResult<import("..").PickScreen[], Error>;
15
15
  //# sourceMappingURL=usePickConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"usePickConfig.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickConfig.ts"],"names":[],"mappings":"AAGA,wBAAgB,gBAAgB,+FAE/B;AACD,wBAAgB,eAAe,8FAE9B;AACD,wBAAgB,eAAe,+FAE9B;AACD,wBAAgB,oBAAoB,oGAEnC;AACD,wBAAgB,mBAAmB,mGAElC;AACD,wBAAgB,YAAY,4FAE3B;AACD,wBAAgB,eAAe,+FAE9B;AACD,gDAAgD;AAChD,wBAAgB,mBAAmB,iGAElC;AACD,0DAA0D;AAC1D,wBAAgB,sBAAsB,2GAKrC;AACD,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,4GAMrD;AAED,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,6FAKhD"}
1
+ {"version":3,"file":"usePickConfig.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickConfig.ts"],"names":[],"mappings":"AAGA,wBAAgB,gBAAgB,sFAE/B;AACD,wBAAgB,eAAe,qFAE9B;AACD,wBAAgB,eAAe,sFAE9B;AACD,wBAAgB,oBAAoB,2FAEnC;AACD,wBAAgB,mBAAmB,0FAElC;AACD,wBAAgB,YAAY,mFAE3B;AACD,wBAAgB,eAAe,sFAE9B;AACD,gDAAgD;AAChD,wBAAgB,mBAAmB,wFAElC;AACD,0DAA0D;AAC1D,wBAAgB,sBAAsB,kGAKrC;AACD,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,mGAMrD;AAED,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,oFAKhD"}
@@ -33,6 +33,8 @@ export declare function usePickQueue(args: {
33
33
  error: string | null;
34
34
  lockedIds: Set<string>;
35
35
  realtimeOk: boolean;
36
+ /** Letterlijke fout uit de wachtrij-synchronisatie, of null. */
37
+ syncError: string | null;
36
38
  /** Tijdstip van de laatste heropbouw na een buffer-seintje van de Engine. */
37
39
  rebuiltAt: number | null;
38
40
  refresh: () => void;
@@ -44,10 +46,10 @@ export declare function usePickHeartbeat(stationId?: string, screenId?: string |
44
46
  export declare function usePickCountryCounts(args: {
45
47
  stationId?: string;
46
48
  screenId?: string;
47
- }): import("@tanstack/react-query").UseQueryResult<NoInfer<Record<string, number>>, Error>;
49
+ }): import("@tanstack/react-query").UseQueryResult<Record<string, number>, Error>;
48
50
  /** Pickdagen waarop nog orders klaarstaan (vandaag en later). */
49
- export declare function usePickDays(enabled?: boolean): import("@tanstack/react-query").UseQueryResult<NoInfer<{
51
+ export declare function usePickDays(enabled?: boolean): import("@tanstack/react-query").UseQueryResult<{
50
52
  day: string;
51
53
  orders: number;
52
- }[]>, Error>;
54
+ }[], Error>;
53
55
  //# sourceMappingURL=usePickQueue.d.ts.map
@@ -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;AAG9E,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;;;;;;;;;;;IAgLG,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,0FAOnF;AACD,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,OAAO,UAAO;;;aAQzC"}
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;AAG9E,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;;;;;;;;;;;IA0LG,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"}
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
- import { useQuery, useQueryClient } from "@tanstack/react-query";
2
+ import { keepPreviousData, useQuery, useQueryClient } from "@tanstack/react-query";
3
3
  import { pickApi, pickDb } from "../lib/pickApi";
4
4
  import { safeArray } from "../lib/pickTypes";
5
5
  export const defaultFilters = {
@@ -24,7 +24,15 @@ export function usePickQueue(args) {
24
24
  queryKey: ["pick", "sync"],
25
25
  enabled,
26
26
  queryFn: async () => {
27
- await pickApi.syncQueue();
27
+ // Syncfout wordt als waarde teruggegeven zodat de wachtrij blijft laden
28
+ // maar de fout zichtbaar in beeld komt.
29
+ let syncError = null;
30
+ try {
31
+ await pickApi.syncQueue();
32
+ }
33
+ catch (e) {
34
+ syncError = e instanceof Error ? e.message : String(e);
35
+ }
28
36
  // Bewaking: orders zonder karplan meteen bij de Engine melden. Mislukt
29
37
  // dit, dan mag de wachtrij daar niet op stuklopen.
30
38
  try {
@@ -33,7 +41,7 @@ export function usePickQueue(args) {
33
41
  catch {
34
42
  /* bewaking is aanvullend, nooit blokkerend */
35
43
  }
36
- return Date.now();
44
+ return { at: Date.now(), syncError };
37
45
  },
38
46
  staleTime: 60000,
39
47
  refetchInterval: 60000,
@@ -75,7 +83,8 @@ export function usePickQueue(args) {
75
83
  useEffect(() => {
76
84
  if (rebuildCount <= 0)
77
85
  return;
78
- queryClient.removeQueries({ queryKey: ["pick", "queue"] });
86
+ // Verouderd markeren en vers ophalen; de oude lijst blijft staan tot de nieuwe binnen is.
87
+ queryClient.invalidateQueries({ queryKey: ["pick", "queue"], refetchType: "all" });
79
88
  queryClient.invalidateQueries({ queryKey: ["pick", "pickDay"] });
80
89
  queryClient.invalidateQueries({ queryKey: ["pick", "pickDays"] });
81
90
  queryClient.invalidateQueries({ queryKey: ["pick", "dayCounts"] });
@@ -99,11 +108,13 @@ export function usePickQueue(args) {
99
108
  page: filters.page,
100
109
  pageSize: filters.pageSize,
101
110
  }),
111
+ placeholderData: keepPreviousData,
102
112
  });
103
113
  const countsQuery = useQuery({
104
114
  queryKey: ["pick", "dayCounts", stationId ?? "-", screenId ?? "-", pickDay ?? "-"],
105
115
  enabled: enabled && !pickDayQuery.isLoading,
106
116
  queryFn: () => pickApi.dayCounts({ stationId, screenId, pickDay }),
117
+ placeholderData: keepPreviousData,
107
118
  });
108
119
  // Locks komen primair via realtime binnen; deze poll is alleen terugval.
109
120
  const locksQuery = useQuery({
@@ -170,6 +181,8 @@ export function usePickQueue(args) {
170
181
  error: queueQuery.error instanceof Error ? queueQuery.error.message : null,
171
182
  lockedIds,
172
183
  realtimeOk,
184
+ /** Letterlijke fout uit de wachtrij-synchronisatie, of null. */
185
+ syncError: syncQuery.data?.syncError ?? null,
173
186
  /** Tijdstip van de laatste heropbouw na een buffer-seintje van de Engine. */
174
187
  rebuiltAt,
175
188
  refresh: invalidateNow,
@@ -1,4 +1,4 @@
1
1
  export declare const PICK_REFERENCE_QUERY_KEY: readonly ["pick", "referenceData"];
2
2
  /** Eén bron voor de instellingenkaart en de waarschuwingsbanner. */
3
- export declare function usePickReferenceData(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickReferenceStatus>, Error>;
3
+ export declare function usePickReferenceData(): import("@tanstack/react-query").UseQueryResult<import("..").PickReferenceStatus, Error>;
4
4
  //# sourceMappingURL=usePickReferenceData.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"usePickReferenceData.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickReferenceData.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,oCAAqC,CAAC;AAE3E,oEAAoE;AACpE,wBAAgB,oBAAoB,qGAKnC"}
1
+ {"version":3,"file":"usePickReferenceData.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickReferenceData.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,oCAAqC,CAAC;AAE3E,oEAAoE;AACpE,wBAAgB,oBAAoB,4FAKnC"}