@flowselections/pick-schermen-kwekers 1.0.19 → 1.0.21
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/README.md +24 -24
- package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
- package/dist-lib/components/pick/PickScherm.js +322 -69
- package/dist-lib/components/pick/QueueTable.d.ts +6 -1
- package/dist-lib/components/pick/QueueTable.d.ts.map +1 -1
- package/dist-lib/components/pick/QueueTable.js +30 -22
- package/dist-lib/hooks/useShippingNoteStatus.d.ts +27 -0
- package/dist-lib/hooks/useShippingNoteStatus.d.ts.map +1 -0
- package/dist-lib/hooks/useShippingNoteStatus.js +132 -0
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +1 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +740 -1
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +740 -1
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +740 -1
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +743 -2
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/layoutMaker/pakbonHtml.js +49 -49
- package/dist-lib/lib/layoutRenderer.js +17 -17
- package/dist-lib/lib/pickApi.d.ts +10 -0
- package/dist-lib/lib/pickApi.d.ts.map +1 -1
- package/dist-lib/lib/pickApi.js +21 -0
- package/dist-lib/lib/pickTypes.d.ts +59 -2
- package/dist-lib/lib/pickTypes.d.ts.map +1 -1
- package/dist-lib/lib/pickTypes.js +149 -24
- package/dist-lib/lib/shippingNoteStatus.d.ts +35 -0
- package/dist-lib/lib/shippingNoteStatus.d.ts.map +1 -0
- package/dist-lib/lib/shippingNoteStatus.js +118 -0
- package/package.json +2 -2
- package/dist-lib/components/TemplateModulePage.d.ts +0 -2
- package/dist-lib/components/TemplateModulePage.d.ts.map +0 -1
- package/dist-lib/components/TemplateModulePage.js +0 -44
|
@@ -6,6 +6,11 @@ interface Props {
|
|
|
6
6
|
statuses: PickStatus[];
|
|
7
7
|
documentTypes: PickDocumentType[];
|
|
8
8
|
busyId: string | null;
|
|
9
|
+
readinessById: Record<string, {
|
|
10
|
+
checking: boolean;
|
|
11
|
+
ready: boolean;
|
|
12
|
+
reason: string | null;
|
|
13
|
+
}>;
|
|
9
14
|
onPick: (item: PickQueueItem) => void;
|
|
10
15
|
onReprint?: (item: PickQueueItem) => void;
|
|
11
16
|
onPrintAll?: (item: PickQueueItem) => void;
|
|
@@ -15,6 +20,6 @@ interface Props {
|
|
|
15
20
|
readOnly?: boolean;
|
|
16
21
|
t?: PickTranslator;
|
|
17
22
|
}
|
|
18
|
-
export declare function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, }: Props): import("react").JSX.Element;
|
|
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;
|
|
19
24
|
export {};
|
|
20
25
|
//# 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;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,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Badge, Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@flowselections/core";
|
|
3
|
-
import { AlertTriangle, Check, Eye, Lock, Printer, RotateCcw } from "lucide-react";
|
|
4
|
-
import { bufferOrdersOf,
|
|
3
|
+
import { AlertTriangle, Check, Eye, Loader2, Lock, Printer, RefreshCw, RotateCcw } from "lucide-react";
|
|
4
|
+
import { bufferOrdersOf, cartColumnInfo, comparePickQueue, dedupeByUnit, displayCartCount, displayPageCount, sinceLabel, unitTitleOf } from "../../lib/pickTypes";
|
|
5
5
|
import { getPickTranslator } from "../../lib/pickI18n";
|
|
6
6
|
/**
|
|
7
7
|
* Uit hoeveel pakbonnen een order bestaat, is pas bekend nadat er geprint is.
|
|
@@ -25,23 +25,22 @@ function priorityTone(priority, urgent) {
|
|
|
25
25
|
return "bg-secondary text-secondary-foreground";
|
|
26
26
|
return "bg-muted text-muted-foreground";
|
|
27
27
|
}
|
|
28
|
-
export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, }) {
|
|
28
|
+
export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, readinessById, onPick, onReprint, onPrintAll, onSelectPrinted, onMarkPrinted, onPreview, readOnly, t: translator, }) {
|
|
29
29
|
const t = translator ?? getPickTranslator("nl");
|
|
30
|
-
//
|
|
31
|
-
//
|
|
30
|
+
// Volgorde identiek aan de keuze van "volgende uitprinten" (zie
|
|
31
|
+
// comparePickQueue): niet-geprinte regels bovenaan, en bij gelijke stand op
|
|
32
|
+
// kar-nummer, zodat K1 boven K2 boven K3 staat en het printen van boven naar
|
|
33
|
+
// beneden loopt. Eén regel per eenheid: een bufferorder verschijnt nooit als
|
|
34
|
+
// losse orders.
|
|
32
35
|
const safeItems = dedupeByUnit(Array.isArray(items) ? items : [])
|
|
33
|
-
.
|
|
34
|
-
.sort(
|
|
35
|
-
const aPrinted = a.item.printed_at ? 1 : 0;
|
|
36
|
-
const bPrinted = b.item.printed_at ? 1 : 0;
|
|
37
|
-
if (aPrinted !== bPrinted)
|
|
38
|
-
return aPrinted - bPrinted;
|
|
39
|
-
return a.index - b.index;
|
|
40
|
-
})
|
|
41
|
-
.map((entry) => entry.item);
|
|
36
|
+
.slice()
|
|
37
|
+
.sort(comparePickQueue);
|
|
42
38
|
const docById = new Map((Array.isArray(documentTypes) ? documentTypes : []).map((d) => [d.id, d]));
|
|
43
39
|
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "hidden overflow-x-auto rounded-lg border md:block", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: t("document") }), _jsx(TableHead, { children: t("order") }), _jsx(TableHead, { children: t("customer") }), _jsx(TableHead, { className: "text-right", children: t("lines") }), _jsx(TableHead, { className: "text-right", children: "Karren" }), _jsx(TableHead, { className: "text-right", children: "Pakbonnen" }), _jsx(TableHead, { className: "text-right", children: t("page") }), _jsx(TableHead, { children: t("status") }), _jsx(TableHead, { children: t("priority") }), _jsx(TableHead, { children: t("announced") }), _jsx(TableHead, { children: t("waiting") }), _jsx(TableHead, { className: "text-right", children: t("action") })] }) }), _jsxs(TableBody, { children: [safeItems.map((item) => {
|
|
44
40
|
const printed = !!item.printed_at;
|
|
41
|
+
const readiness = readinessById[item.id];
|
|
42
|
+
const checking = !readiness || readiness.checking;
|
|
43
|
+
const ready = readiness?.ready === true;
|
|
45
44
|
const locked = !printed && lockedIds.has(item.id);
|
|
46
45
|
const doc = item.document_type_id ? docById.get(item.document_type_id) : undefined;
|
|
47
46
|
const warnings = Array.isArray(item.warnings) ? item.warnings : [];
|
|
@@ -54,7 +53,10 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
|
|
|
54
53
|
event.preventDefault();
|
|
55
54
|
onSelectPrinted?.(item);
|
|
56
55
|
}
|
|
57
|
-
}, 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:
|
|
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: (() => {
|
|
57
|
+
const info = cartColumnInfo(item);
|
|
58
|
+
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
|
+
})() }), _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([], {
|
|
58
60
|
hour: "2-digit",
|
|
59
61
|
minute: "2-digit",
|
|
60
62
|
}) }))] }), _jsx(TableCell, { children: _jsx("span", { className: "rounded px-2 py-1 text-xs font-semibold " +
|
|
@@ -67,15 +69,18 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
|
|
|
67
69
|
}, 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) => {
|
|
68
70
|
e.stopPropagation();
|
|
69
71
|
onMarkPrinted(item);
|
|
70
|
-
}, children: _jsx(Check, { className: "h-5 w-5" }) })), printed ? (_jsxs(Button, { size: "sm", variant: "ghost", disabled: readOnly || busyId === item.id, onClick: (e) => {
|
|
72
|
+
}, children: _jsx(Check, { className: "h-5 w-5" }) })), printed ? (_jsxs(Button, { size: "sm", variant: "ghost", disabled: readOnly || busyId === item.id || checking, onClick: (e) => {
|
|
71
73
|
e.stopPropagation();
|
|
72
74
|
(onPrintAll ?? onReprint ?? onPick)(item);
|
|
73
|
-
}, children: [_jsx(RotateCcw, { className: "mr-1 h-4 w-4" }), t("print")] })) : 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, onClick: (e) => {
|
|
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) => {
|
|
74
76
|
e.stopPropagation();
|
|
75
77
|
(onPrintAll ?? onPick)(item);
|
|
76
|
-
}, children: [_jsx(Printer, { className: "mr-1 h-4 w-4" }), t("print")] }))] }) })] }, item.id));
|
|
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));
|
|
77
79
|
}), 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) => {
|
|
78
80
|
const printed = !!item.printed_at;
|
|
81
|
+
const readiness = readinessById[item.id];
|
|
82
|
+
const checking = !readiness || readiness.checking;
|
|
83
|
+
const ready = readiness?.ready === true;
|
|
79
84
|
const locked = !printed && lockedIds.has(item.id);
|
|
80
85
|
const doc = item.document_type_id ? docById.get(item.document_type_id) : undefined;
|
|
81
86
|
const warnings = Array.isArray(item.warnings) ? item.warnings : [];
|
|
@@ -95,16 +100,19 @@ export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId,
|
|
|
95
100
|
hour: "2-digit",
|
|
96
101
|
minute: "2-digit",
|
|
97
102
|
}) })), _jsx("span", { className: "rounded px-2 py-0.5 text-xs font-semibold " +
|
|
98
|
-
priorityTone(item.priority, item.is_urgent), children: item.is_urgent ? t("urgent") : item.priority })] })] })] }), _jsxs("div", { className: "mt-2 min-w-0 space-y-0.5 text-sm", children: [bufferOrdersOf(item).length > 0 ? null : (_jsx("p", { className: "truncate text-foreground", children: item.order_number })), _jsx("p", { className: "truncate text-muted-foreground", children: item.customer_name })] }), _jsxs("div", { className: "mt-2 flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [_jsxs("span", { children: [t("lines"), ": ", item.line_count] }),
|
|
103
|
+
priorityTone(item.priority, item.is_urgent), children: item.is_urgent ? t("urgent") : item.priority })] })] })] }), _jsxs("div", { className: "mt-2 min-w-0 space-y-0.5 text-sm", children: [bufferOrdersOf(item).length > 0 ? null : (_jsx("p", { className: "truncate text-foreground", children: item.order_number })), _jsx("p", { className: "truncate text-muted-foreground", children: item.customer_name })] }), _jsxs("div", { className: "mt-2 flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [_jsxs("span", { children: [t("lines"), ": ", item.line_count] }), (() => {
|
|
104
|
+
const info = cartColumnInfo(item);
|
|
105
|
+
return (_jsxs("span", { children: ["Karren: ", info.carts, info.cartLabel ? ` · ${info.cartLabel}` : "", info.reason ? ` · ${info.reason}` : ""] }));
|
|
106
|
+
})(), _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, {
|
|
99
107
|
hour: "2-digit",
|
|
100
108
|
minute: "2-digit",
|
|
101
|
-
})] }), _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, onClick: (e) => {
|
|
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) => {
|
|
102
110
|
e.stopPropagation();
|
|
103
111
|
(onPrintAll ?? onReprint ?? onPick)(item);
|
|
104
|
-
}, children: [_jsx(RotateCcw, { className: "mr-2 h-4 w-4" }), t("print")] })) : 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, onClick: (e) => {
|
|
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) => {
|
|
105
113
|
e.stopPropagation();
|
|
106
114
|
(onPrintAll ?? onPick)(item);
|
|
107
|
-
}, children: [_jsx(Printer, { className: "mr-2 h-4 w-4" }), t("print")] })), !printed && onMarkPrinted && (_jsxs(Button, { size: "sm", variant: "ghost", className: "mt-2 w-full", disabled: readOnly || busyId === item.id, onClick: (e) => {
|
|
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) => {
|
|
108
116
|
e.stopPropagation();
|
|
109
117
|
onMarkPrinted(item);
|
|
110
118
|
}, children: [_jsx(Check, { className: "mr-2 h-4 w-4" }), "Markeer als geprint"] }))] })] }, item.id));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ShippingNoteStatus } from "../lib/shippingNoteStatus";
|
|
2
|
+
export interface WatchedShippingNote {
|
|
3
|
+
/** Het print_job-id van de pakbon; leidend bij het opvragen van de status. */
|
|
4
|
+
jobId: string;
|
|
5
|
+
cartId: string | null;
|
|
6
|
+
cartLabel: string | null;
|
|
7
|
+
state: ShippingNoteStatus;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Volgt per geprinte kar of de verzendbrief wordt klaargezet, op Floriday
|
|
11
|
+
* wacht, geprint is of is mislukt. Uitsluitend lezen: er wordt nooit een nieuwe
|
|
12
|
+
* aanvraag of printopdracht gemaakt.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useShippingNoteStatus(): {
|
|
15
|
+
shippingNotes: WatchedShippingNote[];
|
|
16
|
+
watchShippingNotes: (entries: {
|
|
17
|
+
jobId: string;
|
|
18
|
+
cartId?: string | null;
|
|
19
|
+
cartLabel?: string | null;
|
|
20
|
+
}[]) => void;
|
|
21
|
+
clearShippingNotes: () => void;
|
|
22
|
+
refreshShippingNotesNow: () => Promise<{
|
|
23
|
+
ok: boolean;
|
|
24
|
+
message: string | null;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=useShippingNoteStatus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useShippingNoteStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/useShippingNoteStatus.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,mBAAmB;IAClC,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,kBAAkB,CAAC;CAC3B;AAMD;;;;GAIG;AACH,wBAAgB,qBAAqB;;kCAYvB;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE;;mCA4C5B,OAAO,CAAC;QAC5D,EAAE,EAAE,OAAO,CAAC;QACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;KACxB,CAAC;EAuFH"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { isWaitingShippingNote, readShippingNoteStatus, requestShippingNoteNow, } from "../lib/shippingNoteStatus";
|
|
3
|
+
/** Ververs elke 3 seconden, maximaal 15 minuten. */
|
|
4
|
+
const INTERVAL_MS = 3000;
|
|
5
|
+
const MAX_MS = 15 * 60 * 1000;
|
|
6
|
+
/**
|
|
7
|
+
* Volgt per geprinte kar of de verzendbrief wordt klaargezet, op Floriday
|
|
8
|
+
* wacht, geprint is of is mislukt. Uitsluitend lezen: er wordt nooit een nieuwe
|
|
9
|
+
* aanvraag of printopdracht gemaakt.
|
|
10
|
+
*/
|
|
11
|
+
export function useShippingNoteStatus() {
|
|
12
|
+
const [notes, setNotes] = useState([]);
|
|
13
|
+
const notesRef = useRef([]);
|
|
14
|
+
const startedAt = useRef({});
|
|
15
|
+
const apply = useCallback((next) => {
|
|
16
|
+
notesRef.current = next;
|
|
17
|
+
setNotes(next);
|
|
18
|
+
}, []);
|
|
19
|
+
/** Start (of hergebruik) de statuscontrole voor de geprinte karren. */
|
|
20
|
+
const watchShippingNotes = useCallback((entries) => {
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
const existing = new Map(notesRef.current.map((note) => [note.jobId, note]));
|
|
23
|
+
const next = [];
|
|
24
|
+
let hasNew = false;
|
|
25
|
+
for (const entry of Array.isArray(entries) ? entries : []) {
|
|
26
|
+
if (!entry?.jobId)
|
|
27
|
+
continue;
|
|
28
|
+
const prev = existing.get(entry.jobId);
|
|
29
|
+
if (!startedAt.current[entry.jobId]) {
|
|
30
|
+
startedAt.current[entry.jobId] = now;
|
|
31
|
+
hasNew = true;
|
|
32
|
+
}
|
|
33
|
+
next.push(prev ?? {
|
|
34
|
+
jobId: entry.jobId,
|
|
35
|
+
cartId: entry.cartId ?? null,
|
|
36
|
+
cartLabel: entry.cartLabel ?? null,
|
|
37
|
+
state: {
|
|
38
|
+
status: null,
|
|
39
|
+
message: null,
|
|
40
|
+
attempts: null,
|
|
41
|
+
nextAttemptAt: null,
|
|
42
|
+
source: null,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
apply(next);
|
|
47
|
+
// Eén directe aanvraag per printactie, niet per kar en niet bij verversen.
|
|
48
|
+
if (hasNew)
|
|
49
|
+
void requestShippingNoteNow();
|
|
50
|
+
}, [apply]);
|
|
51
|
+
const clearShippingNotes = useCallback(() => {
|
|
52
|
+
startedAt.current = {};
|
|
53
|
+
apply([]);
|
|
54
|
+
}, [apply]);
|
|
55
|
+
/**
|
|
56
|
+
* Handmatig: vraagt de shell één keer om nu alle openstaande verzendbrieven op
|
|
57
|
+
* te halen en leest daarna de status van de karren die in beeld staan. Blijft
|
|
58
|
+
* alleen-lezen richting Floriday en maakt nooit een tweede aanvraag.
|
|
59
|
+
*/
|
|
60
|
+
const refreshShippingNotesNow = useCallback(async () => {
|
|
61
|
+
const result = await requestShippingNoteNow();
|
|
62
|
+
const current = notesRef.current;
|
|
63
|
+
if (current.length > 0) {
|
|
64
|
+
const results = await Promise.all(current.map(async (note) => {
|
|
65
|
+
try {
|
|
66
|
+
return { jobId: note.jobId, state: await readShippingNoteStatus(note.jobId, note.cartId) };
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}));
|
|
72
|
+
const byJob = new Map(results
|
|
73
|
+
.filter((r) => r !== null)
|
|
74
|
+
.map((r) => [r.jobId, r.state]));
|
|
75
|
+
if (byJob.size > 0) {
|
|
76
|
+
apply(notesRef.current.map((note) => byJob.has(note.jobId) ? { ...note, state: byJob.get(note.jobId) } : note));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}, [apply]);
|
|
81
|
+
const key = notes.map((note) => note.jobId).join(",");
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (!key)
|
|
84
|
+
return;
|
|
85
|
+
let stopped = false;
|
|
86
|
+
let timer = null;
|
|
87
|
+
const stop = () => {
|
|
88
|
+
if (timer !== null) {
|
|
89
|
+
window.clearInterval(timer);
|
|
90
|
+
timer = null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const read = async () => {
|
|
94
|
+
const current = notesRef.current;
|
|
95
|
+
const pending = current.filter((note) => {
|
|
96
|
+
if (note.state.status && !isWaitingShippingNote(note.state.status))
|
|
97
|
+
return false;
|
|
98
|
+
const since = startedAt.current[note.jobId] ?? Date.now();
|
|
99
|
+
return Date.now() - since < MAX_MS;
|
|
100
|
+
});
|
|
101
|
+
if (pending.length === 0) {
|
|
102
|
+
stop();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const results = await Promise.all(pending.map(async (note) => {
|
|
106
|
+
try {
|
|
107
|
+
return { jobId: note.jobId, state: await readShippingNoteStatus(note.jobId, note.cartId) };
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Status tijdelijk niet leesbaar; volgende ronde volgt.
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
if (stopped)
|
|
115
|
+
return;
|
|
116
|
+
const byJob = new Map(results.filter((r) => r !== null)
|
|
117
|
+
.map((r) => [r.jobId, r.state]));
|
|
118
|
+
if (byJob.size === 0)
|
|
119
|
+
return;
|
|
120
|
+
const updated = notesRef.current.map((note) => byJob.has(note.jobId) ? { ...note, state: byJob.get(note.jobId) } : note);
|
|
121
|
+
notesRef.current = updated;
|
|
122
|
+
setNotes(updated);
|
|
123
|
+
};
|
|
124
|
+
void read();
|
|
125
|
+
timer = window.setInterval(() => void read(), INTERVAL_MS);
|
|
126
|
+
return () => {
|
|
127
|
+
stopped = true;
|
|
128
|
+
stop();
|
|
129
|
+
};
|
|
130
|
+
}, [key]);
|
|
131
|
+
return { shippingNotes: notes, watchShippingNotes, clearShippingNotes, refreshShippingNotesNow };
|
|
132
|
+
}
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './lib/pickI18n';
|
|
|
14
14
|
export { QueueTable } from './components/pick/QueueTable';
|
|
15
15
|
export { ShippingNoteScan } from './components/pick/ShippingNoteScan';
|
|
16
16
|
export * from './lib/shippingNote';
|
|
17
|
+
export * from './lib/shippingNoteStatus';
|
|
17
18
|
export { PickScherm } from './components/pick/PickScherm';
|
|
18
19
|
export { PickstationsPage } from './components/PickstationsPage';
|
|
19
20
|
export { PickPublicPage } from './components/PickPublicPage';
|
package/dist-lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAErE,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC9F,OAAO,EAAE,gCAAgC,EAAE,MAAM,wDAAwD,CAAC;AAC1G,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAE9E,eAAO,MAAM,kBAAkB,EAAE,UAYhC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAErE,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC9F,OAAO,EAAE,gCAAgC,EAAE,MAAM,wDAAwD,CAAC;AAC1G,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAE9E,eAAO,MAAM,kBAAkB,EAAE,UAYhC,CAAC"}
|
package/dist-lib/index.js
CHANGED
|
@@ -30,6 +30,7 @@ export * from './lib/pickI18n';
|
|
|
30
30
|
export { QueueTable } from './components/pick/QueueTable';
|
|
31
31
|
export { ShippingNoteScan } from './components/pick/ShippingNoteScan';
|
|
32
32
|
export * from './lib/shippingNote';
|
|
33
|
+
export * from './lib/shippingNoteStatus';
|
|
33
34
|
export { PickScherm } from './components/pick/PickScherm';
|
|
34
35
|
export { PickstationsPage } from './components/PickstationsPage';
|
|
35
36
|
export { PickPublicPage } from './components/PickPublicPage';
|