@flowselections/pick-schermen-kwekers 1.0.32 → 1.0.33

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.
@@ -1 +1 @@
1
- {"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AAqCA,OAAO,EAWL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AA2C7B,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,+BA80DpD"}
1
+ {"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AAqCA,OAAO,EAWL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAsD7B,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,+BAw7DpD"}
@@ -20,6 +20,7 @@ import { defaultFilters, usePickDays, usePickHeartbeat, usePickQueue, } from "..
20
20
  import { usePickDocumentTypes, usePickStatuses, useStationPrintPlek, } from "../../hooks/usePickConfig";
21
21
  import { usePrintBatch, usePrintJob } from "../../hooks/usePrintJob";
22
22
  import { useShippingNoteStatus } from "../../hooks/useShippingNoteStatus";
23
+ import { firstVisibleTarget, isJobFinished, isRowGoneError, NO_ROW_IN_FILTER_MESSAGE, RELEASE_PENDING_MESSAGE, ROW_GONE_MESSAGE, stuckMessage, stuckMinutesOf, } from "../../lib/pickRowState";
23
24
  import { CartItemRows, PlanWarnings } from "./CartItemRows";
24
25
  import { isWaitingShippingNote, shippingNoteMessage, shippingNoteSourceLabel, } from "../../lib/shippingNoteStatus";
25
26
  const LANG_STORAGE_KEY = "pick.language";
@@ -55,6 +56,11 @@ export function PickScherm({ station, onBack }) {
55
56
  const [planStatus, setPlanStatus] = useState(null);
56
57
  const [fetchingData, setFetchingData] = useState(false);
57
58
  const [readinessById, setReadinessById] = useState({});
59
+ /** De vastgehouden rij is door de Engine vervangen of bestaat niet meer. */
60
+ const [rowGone, setRowGone] = useState(false);
61
+ /** Moment waarop dit scherm een printopdracht verstuurde (voor "wacht al X minuten"). */
62
+ const sentAtRef = useRef(new Map());
63
+ const [nowTick, setNowTick] = useState(() => Date.now());
58
64
  /** Voortgang van de pakboncontrole: hoeveel van de zichtbare regels zijn gecontroleerd. */
59
65
  const [checkProgress, setCheckProgress] = useState({
60
66
  done: 0,
@@ -239,6 +245,48 @@ export function PickScherm({ station, onBack }) {
239
245
  * Er wordt niets verzonnen: is het plan er niet, of is het nog niet
240
246
  * vrijgegeven, dan blijft de regel "wacht op gegevens".
241
247
  */
248
+ /** Vervangen rij: loslaten, claim vrijgeven, wachtrij verversen, één melding. */
249
+ const handleRowGone = useCallback(async (item) => {
250
+ setRowGone(true);
251
+ setPending(null);
252
+ setCartPlan(null);
253
+ setActiveCartId(null);
254
+ toast.error(ROW_GONE_MESSAGE, { id: "pick-row-gone" });
255
+ if (item)
256
+ await releaseQuietly(item.id);
257
+ refresh();
258
+ }, [refresh]);
259
+ /**
260
+ * Printopdrachten die dit scherm volgt: verzendmoment onthouden en, zolang er
261
+ * één niet klaar is, elke 30 s de klok verzetten voor "wacht al X minuten".
262
+ */
263
+ const openJobIds = useMemo(() => {
264
+ const ids = [];
265
+ if (tracked && !isJobFinished(tracked.job))
266
+ ids.push(tracked.jobId);
267
+ for (const entry of batch?.jobs ?? [])
268
+ if (!isJobFinished(entry.job))
269
+ ids.push(entry.jobId);
270
+ return ids;
271
+ }, [tracked, batch]);
272
+ useEffect(() => {
273
+ const now = Date.now();
274
+ for (const id of openJobIds)
275
+ if (!sentAtRef.current.has(id))
276
+ sentAtRef.current.set(id, now);
277
+ if (openJobIds.length === 0)
278
+ return;
279
+ const timer = window.setInterval(() => setNowTick(Date.now()), 30000);
280
+ return () => window.clearInterval(timer);
281
+ }, [openJobIds]);
282
+ const waitingQueueIds = useMemo(() => {
283
+ const ids = new Set();
284
+ if (tracked && !isJobFinished(tracked.job))
285
+ ids.add(tracked.queueItemId);
286
+ if (batch && batch.jobs.some((entry) => !isJobFinished(entry.job)))
287
+ ids.add(batch.queueItemId);
288
+ return ids;
289
+ }, [tracked, batch]);
242
290
  const loadCartPlan = useCallback(async (item) => {
243
291
  const plan = await pickApi.queueCartPlan(item.id);
244
292
  const ref = statusRefOf(item, plan);
@@ -304,6 +352,9 @@ export function PickScherm({ station, onBack }) {
304
352
  const state = pickReadiness(r.plan, r.status, item);
305
353
  entry = { checking: false, ready: state.ready, reason: state.reason };
306
354
  }
355
+ else if (r?.error && isRowGoneError(r.error)) {
356
+ entry = { checking: false, ready: false, reason: String(r.error), replaced: true };
357
+ }
307
358
  next[item.id] = entry;
308
359
  verifyMemo.current.set(item.id, {
309
360
  fingerprint: rowFingerprint(item),
@@ -461,10 +512,14 @@ export function PickScherm({ station, onBack }) {
461
512
  * verlopen was — dan kan het scherm zelf opnieuw ophalen.
462
513
  */
463
514
  const showPrintError = useCallback((e) => {
515
+ if (isRowGoneError(e)) {
516
+ void handleRowGone(null);
517
+ return false;
518
+ }
464
519
  const { message, detail, expiredClaim } = friendlyPickError(e, t.lang);
465
520
  toast.error(message, detail && detail !== message ? { description: detail } : undefined);
466
521
  return expiredClaim;
467
- }, [t]);
522
+ }, [t, handleRowGone]);
468
523
  const handlePick = useCallback(async (item) => {
469
524
  setBusyId(item.id);
470
525
  try {
@@ -756,14 +811,31 @@ export function PickScherm({ station, onBack }) {
756
811
  setBusyId("next");
757
812
  let claimed = null;
758
813
  try {
759
- claimed = await pickApi.claimNext({
760
- stationId: station.id,
761
- screenId: null,
762
- country: null,
763
- sessionId,
764
- timeout: station.lock_timeout_seconds ?? 120,
765
- pickDay: chosenDay ?? pickDay ?? null,
766
- });
814
+ const target = firstVisibleTarget(itemsRef.current, lockedIds);
815
+ const filtered = !!filters.search.trim() || !!filters.documentTypeId || filters.urgentOnly || !!filters.country;
816
+ if (target) {
817
+ // De rij die in beeld staat (ook met zoekfilter), niet de bovenste van de hele wachtrij.
818
+ claimed =
819
+ (await pickApi.claim({
820
+ itemId: target.id,
821
+ stationId: station.id,
822
+ screenId: null,
823
+ sessionId,
824
+ timeout: station.lock_timeout_seconds ?? 120,
825
+ })) ?? target;
826
+ }
827
+ else if (filtered) {
828
+ throw new Error(NO_ROW_IN_FILTER_MESSAGE);
829
+ }
830
+ else
831
+ claimed = await pickApi.claimNext({
832
+ stationId: station.id,
833
+ screenId: null,
834
+ country: null,
835
+ sessionId,
836
+ timeout: station.lock_timeout_seconds ?? 120,
837
+ pickDay: chosenDay ?? pickDay ?? null,
838
+ });
767
839
  if (!claimed)
768
840
  throw new Error(t("noDocument"));
769
841
  if (requestedDayVersion !== daySelectionVersion.current) {
@@ -790,7 +862,15 @@ export function PickScherm({ station, onBack }) {
790
862
  // lock verloopt automatisch
791
863
  }
792
864
  }
793
- const { message } = friendlyPickError(e, t.lang);
865
+ if (isRowGoneError(e)) {
866
+ await handleRowGone(null);
867
+ return null;
868
+ }
869
+ let { message } = friendlyPickError(e, t.lang);
870
+ if (e instanceof Error && e.message === NO_ROW_IN_FILTER_MESSAGE)
871
+ message = NO_ROW_IN_FILTER_MESSAGE;
872
+ else if (claimed && (await pickApi.orderReleased(claimed.order_number)) === false)
873
+ message = RELEASE_PENDING_MESSAGE;
794
874
  if (silent)
795
875
  setEmptyNotice(message);
796
876
  else
@@ -805,7 +885,7 @@ export function PickScherm({ station, onBack }) {
805
885
  finally {
806
886
  setBusyId(null);
807
887
  }
808
- }, [station.id, station.lock_timeout_seconds, sessionId, refresh, t, loadCartPlan, chosenDay, pickDay]);
888
+ }, [station.id, station.lock_timeout_seconds, sessionId, refresh, t, loadCartPlan, chosenDay, pickDay, lockedIds, filters, handleRowGone]);
809
889
  const fetchNextLocked = useMemo(() => withActionLock(() => fetchNext()), [withActionLock, fetchNext]);
810
890
  /**
811
891
  * Print alle nog niet geprinte karren (pakbonnen) van deze order in één keer
@@ -865,6 +945,10 @@ export function PickScherm({ station, onBack }) {
865
945
  refresh();
866
946
  return;
867
947
  }
948
+ if (isRowGoneError(e)) {
949
+ await handleRowGone(item);
950
+ return;
951
+ }
868
952
  showCartResults(resultsFromBatchError(todo, e, already));
869
953
  const { expiredClaim: expired } = friendlyPickError(e, t.lang);
870
954
  try {
@@ -892,7 +976,7 @@ export function PickScherm({ station, onBack }) {
892
976
  if (!keepBusy)
893
977
  setBusyId(null);
894
978
  }
895
- }, [pending, cartPlan, readiness, requestData, sessionId, startBatchTracking, showCartResults, t, fetchNext, refresh]);
979
+ }, [pending, cartPlan, readiness, requestData, sessionId, startBatchTracking, showCartResults, t, fetchNext, refresh, handleRowGone]);
896
980
  const confirmPending = useMemo(() => withActionLock(confirmPendingInner), [withActionLock, confirmPendingInner]);
897
981
  /** Rond de order pas af wanneer alle batchopdrachten een eindstatus hebben. */
898
982
  useEffect(() => {
@@ -1083,21 +1167,7 @@ export function PickScherm({ station, onBack }) {
1083
1167
  // De lock verloopt automatisch.
1084
1168
  });
1085
1169
  }, [pending, selectedDay]);
1086
- /** Zet automatisch de volgende opdracht klaar, zodat één klik op printen volstaat. */
1087
- useEffect(() => {
1088
- if (lang === null || loading)
1089
- return;
1090
- if (pending !== null || (busyId !== null || actionBusy))
1091
- return;
1092
- if (autoFetched.current)
1093
- return;
1094
- if (!selectedDay)
1095
- return;
1096
- if (pendingCount === 0)
1097
- return;
1098
- autoFetched.current = true;
1099
- void fetchNext(true);
1100
- }, [lang, loading, pending, busyId, pendingCount, fetchNext, selectedDay]);
1170
+ // Geen automatisch claimen bij openen: een rij wordt pas geclaimd als de picker hem kiest.
1101
1171
  /** Pas opnieuw proberen zodra er echt weer iets te printen staat. */
1102
1172
  useEffect(() => {
1103
1173
  if (pendingCount === 0)
@@ -1127,8 +1197,9 @@ export function PickScherm({ station, onBack }) {
1127
1197
  : Math.round((checkDone / checkTotal) * 100);
1128
1198
  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
1129
1199
  ? "Wachtrij wordt geladen…"
1130
- : `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 || 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" })), "Print eerstvolgende ", 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"), 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." })] })), cartMissing && (_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" }), CART_MISSING_MESSAGE] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => {
1200
+ : `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"), 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: () => 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 || 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" })), "Print eerstvolgende ", 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"), 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." })] })), (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: () => {
1131
1201
  setCartMissing(false);
1202
+ setRowGone(false);
1132
1203
  setPending(null);
1133
1204
  setCartPlan(null);
1134
1205
  setActiveCartId(null);
@@ -1156,7 +1227,21 @@ export function PickScherm({ station, onBack }) {
1156
1227
  if (!activeCart)
1157
1228
  return null;
1158
1229
  return (_jsxs("div", { className: "rounded-md border bg-muted/20 p-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("p", { className: "text-lg font-bold text-foreground", children: activeCart.cartLabel }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [activeCart.isFullCart ? "Volle kar" : "Halve kar (deel van de order)", activeCart.isShared ? " · gedeeld" : ""] })] }), activeCart.barcode && _jsx(Badge, { variant: "outline", children: activeCart.barcode })] }), _jsx("div", { className: "mt-4 divide-y rounded-md border bg-background", children: _jsx(CartItemRows, { items: activeCart.items, cartId: activeCart.cartId }) })] }));
1159
- })()] })] }))] })), batch && (_jsx(Card, { className: batchFailed > 0 ? "border-2 border-destructive" : "border-2 border-primary/40", children: _jsxs(CardContent, { className: "flex items-center gap-3 p-4", children: [batchCompleted + batchFailed === batch.jobs.length ? (batchFailed > 0 ? _jsx(AlertTriangle, { className: "h-6 w-6 shrink-0 text-destructive" }) : _jsx(CheckCircle2, { className: "h-6 w-6 shrink-0 text-primary" })) : (_jsx(Loader2, { className: "h-6 w-6 shrink-0 animate-spin text-muted-foreground" })), _jsxs("div", { className: "min-w-0", children: [_jsxs("p", { className: "truncate text-sm text-muted-foreground", children: [jobTexts.jobTitle, batch.documentNumber ? ` · ${batch.documentNumber}` : ""] }), _jsxs("p", { className: "font-semibold text-foreground", children: [batchCompleted, " van ", batch.jobs.length, " pakbonnen voltooid", batchFailed > 0 ? ` · ${batchFailed} mislukt` : ""] })] })] }) })), tracked && (_jsx(Card, { className: jobFailed ? "border-2 border-destructive" : "border-2 border-primary/40", children: _jsxs(CardContent, { className: "flex flex-col gap-4 p-4 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between", children: [_jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [jobFailed ? (_jsx(AlertTriangle, { className: "h-6 w-6 shrink-0 text-destructive" })) : jobStatus === "voltooid" ? (_jsx(CheckCircle2, { className: "h-6 w-6 shrink-0 text-primary" })) : (_jsx(Loader2, { className: "h-6 w-6 shrink-0 animate-spin text-muted-foreground" })), _jsxs("div", { className: "min-w-0", children: [_jsxs("p", { className: "truncate text-sm font-medium text-muted-foreground", children: [jobTexts.jobTitle, " ", tracked.documentNumber ? `· ${tracked.documentNumber}` : "", tracked.cartLabel ? ` · ${tracked.cartLabel}` : ""] }), _jsx("p", { className: "text-lg font-semibold text-foreground", children: printJobStatusLabel(jobStatus, t.lang) }), tracked.job?.printer_naam && (_jsxs("p", { className: "truncate text-sm text-muted-foreground", children: [jobTexts.printerLabel, ": ", tracked.job.printer_naam] })), jobFailed && (_jsxs("p", { className: "text-sm text-destructive", children: [tracked.job?.foutmelding ?? jobTexts.unknown, " \u00B7 ", jobTexts.requeued] })), !jobFailed && pdfSaveWarning(tracked.job) && (_jsx("p", { className: "text-sm font-medium text-destructive", children: pdfSaveWarning(tracked.job) }))] })] }), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [jobFailed && lastPrinted && (_jsxs(Button, { size: "lg", className: "h-12 w-full sm:w-auto", onClick: () => {
1230
+ })()] })] }))] })), batch && (_jsx(Card, { className: batchFailed > 0 ? "border-2 border-destructive" : "border-2 border-primary/40", children: _jsxs(CardContent, { className: "flex items-center gap-3 p-4", children: [batchCompleted + batchFailed === batch.jobs.length ? (batchFailed > 0 ? _jsx(AlertTriangle, { className: "h-6 w-6 shrink-0 text-destructive" }) : _jsx(CheckCircle2, { className: "h-6 w-6 shrink-0 text-primary" })) : (_jsx(Loader2, { className: "h-6 w-6 shrink-0 animate-spin text-muted-foreground" })), _jsxs("div", { className: "min-w-0", children: [_jsxs("p", { className: "truncate text-sm text-muted-foreground", children: [jobTexts.jobTitle, batch.documentNumber ? ` · ${batch.documentNumber}` : ""] }), _jsxs("p", { className: "font-semibold text-foreground", children: [batchCompleted, " van ", batch.jobs.length, " pakbonnen voltooid", batchFailed > 0 ? ` · ${batchFailed} mislukt` : ""] }), batch.jobs.map((entry) => {
1231
+ const minutes = stuckMinutesOf(entry.job, sentAtRef.current.get(entry.jobId) ?? null, nowTick);
1232
+ if (minutes === null)
1233
+ return null;
1234
+ const cart = cartPlan?.carts.find((c) => c.cartId === entry.cartId) ?? null;
1235
+ const item = lastPrinted ?? pending;
1236
+ return (_jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-sm font-medium text-destructive", children: [_jsxs("span", { children: [entry.cartLabel ? `${entry.cartLabel}: ` : "", stuckMessage(minutes), entry.job?.printer_naam ? ` (${entry.job.printer_naam})` : ""] }), cart && item && (_jsx(Button, { size: "sm", variant: "outline", disabled: busyId !== null || actionBusy, onClick: () => void reprintCart(item, cart), children: "Opnieuw proberen" }))] }, entry.jobId));
1237
+ })] })] }) })), tracked && (_jsx(Card, { className: jobFailed ? "border-2 border-destructive" : "border-2 border-primary/40", children: _jsxs(CardContent, { className: "flex flex-col gap-4 p-4 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between", children: [_jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [jobFailed ? (_jsx(AlertTriangle, { className: "h-6 w-6 shrink-0 text-destructive" })) : jobStatus === "voltooid" ? (_jsx(CheckCircle2, { className: "h-6 w-6 shrink-0 text-primary" })) : (_jsx(Loader2, { className: "h-6 w-6 shrink-0 animate-spin text-muted-foreground" })), _jsxs("div", { className: "min-w-0", children: [_jsxs("p", { className: "truncate text-sm font-medium text-muted-foreground", children: [jobTexts.jobTitle, " ", tracked.documentNumber ? `· ${tracked.documentNumber}` : "", tracked.cartLabel ? ` · ${tracked.cartLabel}` : ""] }), _jsx("p", { className: "text-lg font-semibold text-foreground", children: printJobStatusLabel(jobStatus, t.lang) }), tracked.job?.printer_naam && (_jsxs("p", { className: "truncate text-sm text-muted-foreground", children: [jobTexts.printerLabel, ": ", tracked.job.printer_naam] })), (() => {
1238
+ const minutes = stuckMinutesOf(tracked.job, sentAtRef.current.get(tracked.jobId) ?? null, nowTick);
1239
+ if (minutes === null)
1240
+ return null;
1241
+ const cart = cartPlan?.carts.find((c) => c.cartId === tracked.cartId) ?? null;
1242
+ const item = lastPrinted ?? pending;
1243
+ return (_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm font-medium text-destructive", children: [_jsxs("span", { children: [stuckMessage(minutes), tracked.job?.printer_naam ? ` (${tracked.job.printer_naam})` : ""] }), cart && item && (_jsx(Button, { size: "sm", variant: "outline", disabled: busyId !== null || actionBusy, onClick: () => void reprintCart(item, cart), children: "Opnieuw proberen" }))] }));
1244
+ })(), jobFailed && (_jsxs("p", { className: "text-sm text-destructive", children: [tracked.job?.foutmelding ?? jobTexts.unknown, " \u00B7 ", jobTexts.requeued] })), !jobFailed && pdfSaveWarning(tracked.job) && (_jsx("p", { className: "text-sm font-medium text-destructive", children: pdfSaveWarning(tracked.job) }))] })] }), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [jobFailed && lastPrinted && (_jsxs(Button, { size: "lg", className: "h-12 w-full sm:w-auto", onClick: () => {
1160
1245
  clearJob();
1161
1246
  void confirmPending();
1162
1247
  }, disabled: (busyId !== null || actionBusy) || !pending, children: [_jsx(Printer, { className: "mr-2 h-5 w-5" }), " ", jobTexts.retry] })), _jsx(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:w-auto", onClick: () => {
@@ -1172,5 +1257,5 @@ export function PickScherm({ station, onBack }) {
1172
1257
  return (_jsxs("div", { className: "flex items-start gap-3", children: [failed ? (_jsx(AlertTriangle, { className: "mt-0.5 h-5 w-5 shrink-0 text-destructive" })) : note.state.status === "geprint" ? (_jsx(CheckCircle2, { className: "mt-0.5 h-5 w-5 shrink-0 text-primary" })) : (_jsx(Loader2, { className: "mt-0.5 h-5 w-5 shrink-0 animate-spin text-muted-foreground" })), _jsxs("div", { className: "min-w-0", children: [(note.cartLabel || typeLabel) && (_jsx("p", { className: "truncate text-sm text-muted-foreground", children: [note.cartLabel, typeLabel].filter(Boolean).join(" · ") })), _jsx("p", { className: failed ? "text-sm font-medium text-destructive" : "text-sm text-foreground", children: 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
1173
1258
  ? `Volgende poging: ${new Date(note.state.nextAttemptAt).toLocaleTimeString("nl-NL", { hour: "2-digit", minute: "2-digit" })}`
1174
1259
  : ""] }))] })] }, note.jobId));
1175
- })] }) })), _jsx(Card, { 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, { 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" })), "Print eerstvolgende ", 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")] })) : (_jsx(QueueTable, { items: items, lockedIds: lockedIds, statuses: Array.isArray(statuses) ? statuses : [], documentTypes: Array.isArray(documentTypes) ? documentTypes : [], busyId: busyId, readinessById: readinessById, 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) })] }));
1260
+ })] }) })), _jsx(Card, { 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, { 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" })), "Print eerstvolgende ", 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")] })) : (_jsx(QueueTable, { items: items, lockedIds: lockedIds, statuses: Array.isArray(statuses) ? statuses : [], documentTypes: Array.isArray(documentTypes) ? documentTypes : [], busyId: busyId, readinessById: readinessById, 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) })] }));
1176
1261
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PreviewDialog.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PreviewDialog.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,UAAU,KAAK;IACb,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,KAAK,+BAqGlE"}
1
+ {"version":3,"file":"PreviewDialog.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PreviewDialog.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,UAAU,KAAK;IACb,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,KAAK,+BAkHlE"}
@@ -3,6 +3,8 @@ import { useEffect, useState } from "react";
3
3
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@flowselections/core";
4
4
  import { AlertTriangle, Loader2 } from "lucide-react";
5
5
  import { fetchPickPreview, PickPreviewError } from "../../lib/pickPreview";
6
+ import { pickApi } from "../../lib/pickApi";
7
+ import { isRowGoneError, RELEASE_PENDING_MESSAGE, ROW_GONE_MESSAGE } from "../../lib/pickRowState";
6
8
  /**
7
9
  * Toont het PDF-voorbeeld zoals de printketen het opbouwt. Bewust zonder
8
10
  * printknop: printen loopt uitsluitend via de wachtrijknoppen.
@@ -40,9 +42,23 @@ export function PreviewDialog({ item, stationSlug, onClose }) {
40
42
  setHtml(result.html);
41
43
  setBron(result.bron);
42
44
  })
43
- .catch((err) => {
45
+ .catch(async (err) => {
44
46
  if (controller.signal.aborted)
45
47
  return;
48
+ if (isRowGoneError(err)) {
49
+ setError(ROW_GONE_MESSAGE);
50
+ return;
51
+ }
52
+ // Geen inhoud: eerst bij de Engine nagaan of het pickvenster al begonnen is.
53
+ if (err instanceof PickPreviewError && err.code === "layout_ontbreekt") {
54
+ const released = await pickApi.orderReleased(item.order_number);
55
+ if (controller.signal.aborted)
56
+ return;
57
+ if (released === false) {
58
+ setError(RELEASE_PENDING_MESSAGE);
59
+ return;
60
+ }
61
+ }
46
62
  setError(err instanceof PickPreviewError
47
63
  ? err.message
48
64
  : "Het voorbeeld kon niet worden opgehaald.");
@@ -10,7 +10,10 @@ interface Props {
10
10
  checking: boolean;
11
11
  ready: boolean;
12
12
  reason: string | null;
13
+ replaced?: boolean;
13
14
  }>;
15
+ /** Rijen met een printopdracht die nog niet voltooid is. */
16
+ waitingIds?: Set<string>;
14
17
  onPick: (item: PickQueueItem) => void;
15
18
  onReprint?: (item: PickQueueItem) => void;
16
19
  onPrintAll?: (item: PickQueueItem) => void;
@@ -20,6 +23,6 @@ interface Props {
20
23
  readOnly?: boolean;
21
24
  t?: PickTranslator;
22
25
  }
23
- export declare function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, }: Props): import("react").JSX.Element;
26
+ export declare function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, waitingIds, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, }: Props): import("react").JSX.Element;
24
27
  export {};
25
28
  //# sourceMappingURL=QueueTable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"QueueTable.d.ts","sourceRoot":"","sources":["../../../src/components/pick/QueueTable.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGvF,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,CAAA;KAAE,CAAC,CAAC;IAC5F,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;AAqBD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,QAAQ,EACR,aAAa,EACb,MAAM,EACN,aAAa,EACb,MAAM,EACN,SAAS,EACT,UAAU,EACV,eAAe,EACf,aAAa,EACb,SAAS,EAGT,QAAQ,EACR,CAAC,EAAE,UAAU,GACd,EAAE,KAAK,+BA4aP"}
1
+ {"version":3,"file":"QueueTable.d.ts","sourceRoot":"","sources":["../../../src/components/pick/QueueTable.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAIvF,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,CAAA;KAAE,CAAC,CAAC;IAChH,4DAA4D;IAC5D,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,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;AAqBD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,QAAQ,EACR,aAAa,EACb,MAAM,EACN,aAAa,EACb,UAAU,EACV,MAAM,EACN,SAAS,EACT,UAAU,EACV,eAAe,EACf,aAAa,EACb,SAAS,EAGT,QAAQ,EACR,CAAC,EAAE,UAAU,GACd,EAAE,KAAK,+BA0cP"}
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { Badge, Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@flowselections/core";
3
3
  import { AlertTriangle, Check, Eye, Loader2, Lock, Printer, RefreshCw, RotateCcw } from "lucide-react";
4
4
  import { bufferOrdersOf, cartColumnInfo, comparePickQueue, dedupeByUnit, displayCartCount, displayPageCount, sinceLabel, unitTitleOf } from "../../lib/pickTypes";
5
+ import { duplicateNameTag } from "../../lib/pickRowState";
5
6
  import { getPickTranslator } from "../../lib/pickI18n";
6
7
  /**
7
8
  * Uit hoeveel pakbonnen een order bestaat, is pas bekend nadat er geprint is.
@@ -25,7 +26,7 @@ function priorityTone(priority, urgent) {
25
26
  return "bg-secondary text-secondary-foreground";
26
27
  return "bg-muted text-muted-foreground";
27
28
  }
28
- export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, }) {
29
+ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, waitingIds, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, }) {
29
30
  const t = translator ?? getPickTranslator("nl");
30
31
  // Volgorde identiek aan de keuze van "volgende uitprinten" (zie
31
32
  // comparePickQueue): niet-geprinte regels bovenaan, en bij gelijke stand op
@@ -41,6 +42,9 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
41
42
  const readiness = readinessById[item.id];
42
43
  const checking = !readiness || readiness.checking;
43
44
  const ready = readiness?.ready === true;
45
+ const replaced = readiness?.replaced === true;
46
+ const dupTag = duplicateNameTag(safeItems, item);
47
+ const waiting = waitingIds?.has(item.id) === true;
44
48
  const locked = !printed && lockedIds.has(item.id);
45
49
  const doc = item.document_type_id ? docById.get(item.document_type_id) : undefined;
46
50
  const warnings = Array.isArray(item.warnings) ? item.warnings : [];
@@ -53,7 +57,7 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
53
57
  event.preventDefault();
54
58
  onSelectPrinted?.(item);
55
59
  }
56
- }, children: [_jsxs(TableCell, { className: "font-medium", children: [_jsxs("div", { className: "flex items-center gap-2", children: [unitTitleOf(item), 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: bufferOrdersOf(item).length > 0 ? "" : item.order_number }), _jsx(TableCell, { children: item.customer_name }), _jsx(TableCell, { className: "text-right", children: item.line_count }), _jsx(TableCell, { className: "text-right", children: (() => {
60
+ }, 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" })), 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: bufferOrdersOf(item).length > 0 ? "" : item.order_number }), _jsx(TableCell, { children: item.customer_name }), _jsx(TableCell, { className: "text-right", children: item.line_count }), _jsx(TableCell, { className: "text-right", children: (() => {
57
61
  const info = cartColumnInfo(item);
58
62
  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 }))] }));
59
63
  })() }), _jsx(TableCell, { className: "text-right", children: printedSlipCount(item) ?? "—" }), _jsx(TableCell, { className: "text-right", children: displayPageCount(item.line_count) }), _jsxs(TableCell, { children: [_jsx(Badge, { variant: printed ? "secondary" : "default", children: printed ? t("statusPrinted") : t("statusToPrint") }), printed && (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: new Date(item.printed_at).toLocaleTimeString([], {
@@ -69,18 +73,21 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
69
73
  }, children: _jsx(Eye, { className: "h-5 w-5" }) })), !printed && onMarkPrinted && (_jsx("button", { type: "button", "aria-label": "Markeer " + item.document_number + " als geprint", title: "Markeer als geprint (zonder opnieuw printen)", disabled: readOnly || busyId === item.id, className: "inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50", onClick: (e) => {
70
74
  e.stopPropagation();
71
75
  onMarkPrinted(item);
72
- }, children: _jsx(Check, { className: "h-5 w-5" }) })), printed ? (_jsxs(Button, { size: "sm", variant: "ghost", disabled: readOnly || busyId === item.id || checking, onClick: (e) => {
76
+ }, children: _jsx(Check, { className: "h-5 w-5" }) })), printed ? (_jsxs(Button, { size: "sm", variant: "ghost", disabled: readOnly || busyId === item.id || checking || replaced, onClick: (e) => {
73
77
  e.stopPropagation();
74
78
  (onPrintAll ?? onReprint ?? onPick)(item);
75
- }, 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" })), 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, onClick: (e) => {
79
+ }, 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) => {
76
80
  e.stopPropagation();
77
81
  (onPrintAll ?? onPick)(item);
78
- }, 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" })), checking ? "Pakbon controleren" : ready ? t("print") : "Pakbon ophalen"] }))] }) })] }, item.id));
82
+ }, 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));
79
83
  }), safeItems.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 11, className: "py-10 text-center text-muted-foreground", children: t("emptyQueue") }) }))] })] }) }), _jsxs("div", { className: "space-y-3 md:hidden", children: [safeItems.map((item) => {
80
84
  const printed = !!item.printed_at;
81
85
  const readiness = readinessById[item.id];
82
86
  const checking = !readiness || readiness.checking;
83
87
  const ready = readiness?.ready === true;
88
+ const replaced = readiness?.replaced === true;
89
+ const dupTag = duplicateNameTag(safeItems, item);
90
+ const waiting = waitingIds?.has(item.id) === true;
84
91
  const locked = !printed && lockedIds.has(item.id);
85
92
  const doc = item.document_type_id ? docById.get(item.document_type_id) : undefined;
86
93
  const warnings = Array.isArray(item.warnings) ? item.warnings : [];
@@ -93,7 +100,7 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
93
100
  event.preventDefault();
94
101
  onSelectPrinted?.(item);
95
102
  }
96
- }, 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: [_jsx("span", { className: "truncate text-lg font-bold text-foreground", children: unitTitleOf(item) }), 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) => {
103
+ }, 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) => {
97
104
  e.stopPropagation();
98
105
  onPreview(item);
99
106
  }, children: _jsx(Eye, { className: "h-5 w-5" }) })), _jsxs("div", { className: "flex shrink-0 flex-col items-end gap-1", children: [_jsx(Badge, { variant: printed ? "secondary" : "default", children: printed ? t("statusPrinted") : t("statusToPrint") }), printed && (_jsx("span", { className: "text-xs text-muted-foreground", children: new Date(item.printed_at).toLocaleTimeString([], {
@@ -106,13 +113,13 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
106
113
  })(), _jsxs("span", { children: ["Pakbonnen: ", printedSlipCount(item) ?? "—"] }), _jsxs("span", { children: [t("page"), ": ", displayPageCount(item.line_count)] }), _jsxs("span", { children: [t("announced"), ":", " ", new Date(item.announced_at).toLocaleTimeString(t.locale, {
107
114
  hour: "2-digit",
108
115
  minute: "2-digit",
109
- })] }), _jsxs("span", { children: [t("waiting"), ": ", sinceLabel(item.announced_at)] })] }), _jsxs("div", { className: "mt-3", children: [printed ? (_jsxs(Button, { size: "lg", variant: "outline", className: "h-12 w-full", disabled: readOnly || busyId === item.id || checking, onClick: (e) => {
116
+ })] }), _jsxs("span", { children: [t("waiting"), ": ", sinceLabel(item.announced_at)] })] }), _jsxs("div", { className: "mt-3", children: [printed ? (_jsxs(Button, { size: "lg", variant: "outline", className: "h-12 w-full", disabled: readOnly || busyId === item.id || checking || replaced, onClick: (e) => {
110
117
  e.stopPropagation();
111
118
  (onPrintAll ?? onReprint ?? onPick)(item);
112
- }, 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" })), 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, onClick: (e) => {
119
+ }, 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) => {
113
120
  e.stopPropagation();
114
121
  (onPrintAll ?? onPick)(item);
115
- }, 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" })), checking ? "Pakbon controleren" : ready ? t("print") : "Pakbon ophalen"] })), !printed && onMarkPrinted && (_jsxs(Button, { size: "sm", variant: "ghost", className: "mt-2 w-full", disabled: readOnly || busyId === item.id, onClick: (e) => {
122
+ }, 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(Button, { size: "sm", variant: "ghost", className: "mt-2 w-full", disabled: readOnly || busyId === item.id, onClick: (e) => {
116
123
  e.stopPropagation();
117
124
  onMarkPrinted(item);
118
125
  }, children: [_jsx(Check, { className: "mr-2 h-4 w-4" }), "Markeer als geprint"] }))] })] }, item.id));
@@ -3059,6 +3059,27 @@ export type Database = {
3059
3059
  }
3060
3060
  ];
3061
3061
  };
3062
+ dashboard_funnel_indelingen: {
3063
+ Row: {
3064
+ created_at: string;
3065
+ posities: Json;
3066
+ updated_at: string;
3067
+ user_id: string;
3068
+ };
3069
+ Insert: {
3070
+ created_at?: string;
3071
+ posities?: Json;
3072
+ updated_at?: string;
3073
+ user_id?: string;
3074
+ };
3075
+ Update: {
3076
+ created_at?: string;
3077
+ posities?: Json;
3078
+ updated_at?: string;
3079
+ user_id?: string;
3080
+ };
3081
+ Relationships: [];
3082
+ };
3062
3083
  dashboard_pages: {
3063
3084
  Row: {
3064
3085
  created_at: string;
@@ -12551,6 +12572,32 @@ export type Database = {
12551
12572
  };
12552
12573
  Relationships: [];
12553
12574
  };
12575
+ logistics_order_plan_exclusion: {
12576
+ Row: {
12577
+ created_at: string;
12578
+ order_id: string;
12579
+ reason: string;
12580
+ };
12581
+ Insert: {
12582
+ created_at?: string;
12583
+ order_id: string;
12584
+ reason: string;
12585
+ };
12586
+ Update: {
12587
+ created_at?: string;
12588
+ order_id?: string;
12589
+ reason?: string;
12590
+ };
12591
+ Relationships: [
12592
+ {
12593
+ foreignKeyName: "logistics_order_plan_exclusion_order_id_fkey";
12594
+ columns: ["order_id"];
12595
+ isOneToOne: true;
12596
+ referencedRelation: "orders";
12597
+ referencedColumns: ["id"];
12598
+ }
12599
+ ];
12600
+ };
12554
12601
  logistics_packing_deviations: {
12555
12602
  Row: {
12556
12603
  auto_fixed_at: string | null;
@@ -30891,6 +30938,12 @@ export type Database = {
30891
30938
  };
30892
30939
  Returns: Json;
30893
30940
  };
30941
+ logistics_order_buffer_excluded: {
30942
+ Args: {
30943
+ p_order_id: string;
30944
+ };
30945
+ Returns: boolean;
30946
+ };
30894
30947
  logistics_order_cart_approval: {
30895
30948
  Args: {
30896
30949
  _order_ref: string;
@@ -35150,6 +35203,23 @@ export type Database = {
35150
35203
  Args: never;
35151
35204
  Returns: Json;
35152
35205
  };
35206
+ voorraad_hook_base_url: {
35207
+ Args: never;
35208
+ Returns: string;
35209
+ };
35210
+ voorraad_hook_on: {
35211
+ Args: {
35212
+ p_name: string;
35213
+ };
35214
+ Returns: boolean;
35215
+ };
35216
+ voorraad_hook_post: {
35217
+ Args: {
35218
+ p_path: string;
35219
+ p_timeout?: number;
35220
+ };
35221
+ Returns: undefined;
35222
+ };
35153
35223
  voorraad_production_enabled: {
35154
35224
  Args: never;
35155
35225
  Returns: boolean;