@flowselections/pick-schermen-kwekers 1.0.32 → 1.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
- package/dist-lib/components/pick/PickScherm.js +115 -30
- package/dist-lib/components/pick/PreviewDialog.d.ts.map +1 -1
- package/dist-lib/components/pick/PreviewDialog.js +17 -1
- package/dist-lib/components/pick/QueueTable.d.ts +4 -1
- package/dist-lib/components/pick/QueueTable.d.ts.map +1 -1
- package/dist-lib/components/pick/QueueTable.js +16 -9
- package/dist-lib/integrations/supabase/types.d.ts +70 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/__tests__/pickRowState.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/pickRowState.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/pickRowState.test.js +47 -0
- package/dist-lib/lib/pickApi.d.ts +2 -0
- package/dist-lib/lib/pickApi.d.ts.map +1 -1
- package/dist-lib/lib/pickApi.js +9 -0
- package/dist-lib/lib/pickRowState.d.ts +23 -0
- package/dist-lib/lib/pickRowState.d.ts.map +1 -0
- package/dist-lib/lib/pickRowState.js +68 -0
- package/package.json +1 -1
|
@@ -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;
|
|
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
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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` : ""] })
|
|
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;
|
|
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;
|
|
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: [
|
|
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;
|