@flowselections/pick-schermen-kwekers 1.0.18 → 1.0.19

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 CHANGED
@@ -1,24 +1,24 @@
1
- # pick schermen kwekers
2
-
3
- blank project start
4
-
5
- This project was built with [Lovable](https://lovable.dev).
6
-
7
- ## Build with Lovable
8
-
9
- Continue developing this project in the [Lovable editor](https://lovable.dev/projects/f7462658-1d60-42f1-8e22-dbefe36f44ef).
10
-
11
- - **Ship faster**: describe what you want to build and Lovable handles the code.
12
- - **Stay in sync**: every change made in Lovable is committed straight to this repository.
13
- - **Full ownership**: this code is yours. Push to `main` on GitHub and your changes sync back into Lovable, ready for your next prompt.
14
-
15
- ## Development
16
-
17
- Prefer working locally? You need Node.js and npm — [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
18
-
19
- ```sh
20
- git clone <this-repository-url>
21
- cd <repository-name>
22
- npm i
23
- npm run dev
24
- ```
1
+ # pick schermen kwekers
2
+
3
+ blank project start
4
+
5
+ This project was built with [Lovable](https://lovable.dev).
6
+
7
+ ## Build with Lovable
8
+
9
+ Continue developing this project in the [Lovable editor](https://lovable.dev/projects/f7462658-1d60-42f1-8e22-dbefe36f44ef).
10
+
11
+ - **Ship faster**: describe what you want to build and Lovable handles the code.
12
+ - **Stay in sync**: every change made in Lovable is committed straight to this repository.
13
+ - **Full ownership**: this code is yours. Push to `main` on GitHub and your changes sync back into Lovable, ready for your next prompt.
14
+
15
+ ## Development
16
+
17
+ Prefer working locally? You need Node.js and npm — [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
18
+
19
+ ```sh
20
+ git clone <this-repository-url>
21
+ cd <repository-name>
22
+ npm i
23
+ npm run dev
24
+ ```
@@ -0,0 +1,2 @@
1
+ export declare function TemplateModulePage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=TemplateModulePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateModulePage.d.ts","sourceRoot":"","sources":["../../src/components/TemplateModulePage.tsx"],"names":[],"mappings":"AAsBA,wBAAgB,kBAAkB,gCAmFjC"}
@@ -0,0 +1,44 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/TemplateModulePage.tsx — EXAMPLE PAGE COMPONENT
4
+ // ============================================================================
5
+ // Pagina-componenten horen in src/components/, NIET alleen in src/routes/.
6
+ // src/routes/ wordt NIET naar npm gepubliceerd (zie tsconfig.build.json exclude).
7
+ //
8
+ // GEEN <Header /> hier — die zit in _authenticated.tsx via staticData.title
9
+ // ============================================================================
10
+ import { useState, useEffect } from "react";
11
+ import { useAuth, supabase, Button, Card, CardContent, CardHeader, CardTitle, toast, } from "@flowselections/core";
12
+ import { TemplateModuleLogo } from './TemplateModuleLogo';
13
+ export function TemplateModulePage() {
14
+ // Auth is guaranteed — this user is already logged in
15
+ const { user, isAdmin } = useAuth();
16
+ // Example state — replace with your own
17
+ const [items, setItems] = useState([]);
18
+ const [loading, setLoading] = useState(true);
19
+ useEffect(() => {
20
+ loadData();
21
+ }, []);
22
+ const loadData = async () => {
23
+ setLoading(true);
24
+ try {
25
+ // Example query — replace "products" with your table
26
+ const { data, error } = await supabase
27
+ .from("products")
28
+ .select("*")
29
+ .limit(10);
30
+ if (error)
31
+ throw error;
32
+ // ✅ Altijd Array.isArray bewaken op server-function data
33
+ // const safeItems = Array.isArray(data?.items) ? data.items : [];
34
+ setItems(Array.isArray(data) ? data : []);
35
+ }
36
+ catch {
37
+ toast.error("Fout bij het laden van gegevens");
38
+ }
39
+ finally {
40
+ setLoading(false);
41
+ }
42
+ };
43
+ return (_jsxs("main", { className: "p-6 space-y-6", children: [isAdmin && (_jsxs("div", { className: "text-sm text-muted-foreground", children: ["Ingelogd als admin: ", user?.email] })), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: "Overzicht" }) }), _jsxs(CardContent, { children: [loading ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Laden..." })) : items.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen gegevens gevonden." })) : (_jsxs("p", { className: "text-sm", children: [items.length, " items geladen."] })), _jsx(Button, { onClick: loadData, className: "mt-4", disabled: loading, children: "Vernieuwen" })] })] }), _jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(TemplateModuleLogo, { className: "w-6 h-6 text-primary" }), _jsx("span", { children: "SVG-component (voorkeur voor vector-logo's)" })] })] }));
44
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AAkCA,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAmB7B,UAAU,KAAK;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAcD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,+BA4uCpD"}
1
+ {"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AAkCA,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAmB7B,UAAU,KAAK;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAcD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,+BAwwCpD"}
@@ -35,6 +35,7 @@ export function PickScherm({ station, onBack }) {
35
35
  const [busyId, setBusyId] = useState(null);
36
36
  const [pending, setPending] = useState(null);
37
37
  const [cartPlan, setCartPlan] = useState(null);
38
+ const [planReason, setPlanReason] = useState(null);
38
39
  const [activeCartId, setActiveCartId] = useState(null);
39
40
  const [lastPrinted, setLastPrinted] = useState(null);
40
41
  const [previewItem, setPreviewItem] = useState(null);
@@ -73,7 +74,7 @@ export function PickScherm({ station, onBack }) {
73
74
  return () => clearTimeout(timer);
74
75
  }, [searchInput]);
75
76
  const effectiveFilters = useMemo(() => ({ ...filters, country: null, sortRules: [] }), [filters]);
76
- const { items, total, loading, lockedIds, refresh, pendingCount, printedCount, urgentCount, realtimeOk, pickDay, } = usePickQueue({
77
+ const { items, total, loading, lockedIds, refresh, pendingCount, printedCount, urgentCount, realtimeOk, pickDay, rebuiltAt, } = usePickQueue({
77
78
  stationId: station.id,
78
79
  filters: effectiveFilters,
79
80
  enabled: lang !== null,
@@ -86,6 +87,21 @@ export function PickScherm({ station, onBack }) {
86
87
  day: "numeric",
87
88
  month: "short",
88
89
  }), [t.lang]);
90
+ /**
91
+ * De Engine heeft gemeld dat een buffer is gesloten of dat een order is
92
+ * losgekoppeld. De regels zijn opnieuw opgebouwd; de openstaande selectie en
93
+ * het oude karplan gaan weg zodat nooit een verouderde groepering blijft
94
+ * staan. Kar-id's, karnummers en barcodes van geprinte karren wijzigen niet.
95
+ */
96
+ useEffect(() => {
97
+ if (rebuiltAt === null)
98
+ return;
99
+ daySelectionVersion.current += 1;
100
+ setPending(null);
101
+ setCartPlan(null);
102
+ setActiveCartId(null);
103
+ autoFetched.current = false;
104
+ }, [rebuiltAt]);
89
105
  /** Kiest een andere pickdag en laat de Engine die dag alvast klaarzetten. */
90
106
  const chooseDay = useCallback(async (value) => {
91
107
  const day = value === "current" ? null : value;
@@ -155,8 +171,18 @@ export function PickScherm({ station, onBack }) {
155
171
  if (!plan || plan.carts.length === 0) {
156
172
  setCartPlan(null);
157
173
  setActiveCartId(null);
174
+ // De reden komt letterlijk uit de Engine; deze module bedenkt niets.
175
+ try {
176
+ const ref = item.order_number ?? item.document_number;
177
+ const status = ref ? await pickApi.cartPlanStatus(ref) : null;
178
+ setPlanReason(status && (!status.ready || !status.released) ? status.reason ?? null : null);
179
+ }
180
+ catch {
181
+ setPlanReason(null);
182
+ }
158
183
  return null;
159
184
  }
185
+ setPlanReason(null);
160
186
  setCartPlan(plan);
161
187
  const printed = new Set(printedCartIdsOf(item));
162
188
  setActiveCartId(plan.carts.find((cart) => !printed.has(cart.cartId))?.cartId ?? plan.carts[0].cartId);
@@ -737,7 +763,9 @@ export function PickScherm({ station, onBack }) {
737
763
  const jobFailed = jobStatus === "mislukt" || jobStatus === "geannuleerd";
738
764
  const batchCompleted = batch?.jobs.filter((entry) => entry.job?.status === "voltooid").length ?? 0;
739
765
  const batchFailed = batch?.jobs.filter((entry) => entry.job?.status === "mislukt" || entry.job?.status === "geannuleerd").length ?? 0;
740
- return (_jsxs("div", { className: "space-y-4 pb-24 md:pb-0", children: [_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, { size: "lg", className: "hidden h-14 px-8 text-lg md:inline-flex", onClick: () => (pending ? confirmPending() : fetchNext()), disabled: busyId !== null, children: [busyId !== null ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), t("printNext"), pending?.document_number ? ` · ${pending.document_number}` : ""] })] })] }), !plekLoading && !printPlek && (_jsxs("div", { className: "flex items-start gap-2 rounded-md border-2 border-destructive/50 bg-destructive/5 p-3 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: "Nog geen printplek gekoppeld \u2014 de opdracht blijft in de wachtrij staan." })] })), _jsx(ShippingNoteScan, { stationId: station.id }), !pending && emptyNotice && (_jsx("p", { className: "text-sm text-muted-foreground", children: emptyNotice })), pending && (_jsxs(Card, { className: "border-2 border-primary", children: [_jsxs(CardContent, { className: "flex flex-col gap-4 p-4 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between sm:p-5", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("confirmPrintTitle") }), _jsx("p", { className: "truncate text-xl font-bold text-foreground sm:text-2xl", children: pending.document_number ?? t("document") }), _jsx("p", { className: "truncate text-sm text-muted-foreground", children: [pending.order_number, pending.customer_name].filter(Boolean).join(" · ") })] }), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [_jsx(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:w-auto", onClick: cancelPending, disabled: busyId !== null, children: t("cancel") }), _jsxs(Button, { size: "lg", className: "h-14 w-full px-8 text-lg sm:w-auto", onClick: confirmPending, disabled: busyId !== null, children: [busyId === "confirm" ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), t("print")] })] })] }), !cartPlan && (_jsx(CardContent, { className: "border-t p-4 sm:p-5", children: _jsxs("div", { className: "flex items-start gap-2 rounded-md border bg-muted/30 p-3 text-sm text-muted-foreground", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: "De karplanning voor deze order is nog niet klaar \u2014 de logistiek is automatisch op de hoogte gebracht. Zolang die ontbreekt, wordt de pakbon als \u00E9\u00E9n document geprint." })] }) })), cartPlan && (_jsx(CardContent, { className: "border-t p-4 sm:p-5", children: _jsxs("div", { className: "grid gap-3 lg:grid-cols-[minmax(0,0.8fr)_minmax(0,1.2fr)]", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-semibold text-foreground", children: "Karren van deze order" }), _jsx("div", { className: "max-h-72 space-y-2 overflow-y-auto rounded-md border p-2", children: cartPlan.carts.map((cart) => {
766
+ return (_jsxs("div", { className: "space-y-4 pb-24 md:pb-0", children: [_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, { size: "lg", className: "hidden h-14 px-8 text-lg md:inline-flex", onClick: () => (pending ? confirmPending() : fetchNext()), disabled: busyId !== null, children: [busyId !== null ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), t("printNext"), pending?.document_number ? ` · ${pending.document_number}` : ""] })] })] }), !plekLoading && !printPlek && (_jsxs("div", { className: "flex items-start gap-2 rounded-md border-2 border-destructive/50 bg-destructive/5 p-3 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: "Nog geen printplek gekoppeld \u2014 de opdracht blijft in de wachtrij staan." })] })), _jsx(ShippingNoteScan, { stationId: station.id }), !pending && emptyNotice && (_jsx("p", { className: "text-sm text-muted-foreground", children: emptyNotice })), pending && (_jsxs(Card, { className: "border-2 border-primary", children: [_jsxs(CardContent, { className: "flex flex-col gap-4 p-4 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between sm:p-5", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("confirmPrintTitle") }), _jsx("p", { className: "truncate text-xl font-bold text-foreground sm:text-2xl", children: pending.document_number ?? t("document") }), _jsx("p", { className: "truncate text-sm text-muted-foreground", children: [pending.order_number, pending.customer_name].filter(Boolean).join(" · ") })] }), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [_jsx(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:w-auto", onClick: cancelPending, disabled: busyId !== null, children: t("cancel") }), _jsxs(Button, { size: "lg", className: "h-14 w-full px-8 text-lg sm:w-auto", onClick: confirmPending, disabled: busyId !== null, children: [busyId === "confirm" ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), t("print")] })] })] }), !cartPlan && (_jsx(CardContent, { className: "border-t p-4 sm:p-5", children: _jsxs("div", { className: "flex items-start gap-2 rounded-md border bg-muted/30 p-3 text-sm text-muted-foreground", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: planReason
767
+ ? `${planReason} De logistiek is automatisch op de hoogte gebracht.`
768
+ : "De karplanning voor deze order is nog niet klaar — de logistiek is automatisch op de hoogte gebracht. Zolang die ontbreekt, wordt de pakbon als één document geprint." })] }) })), cartPlan && (_jsx(CardContent, { className: "border-t p-4 sm:p-5", children: _jsxs("div", { className: "grid gap-3 lg:grid-cols-[minmax(0,0.8fr)_minmax(0,1.2fr)]", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-semibold text-foreground", children: "Karren van deze order" }), _jsx("div", { className: "max-h-72 space-y-2 overflow-y-auto rounded-md border p-2", children: cartPlan.carts.map((cart) => {
741
769
  const done = printedCartIdsOf(pending).includes(cart.cartId);
742
770
  const active = cart.cartId === activeCartId;
743
771
  return (_jsxs("div", { role: "button", tabIndex: 0, onClick: () => setActiveCartId(cart.cartId), onKeyDown: (event) => {
@@ -33,6 +33,8 @@ export declare function usePickQueue(args: {
33
33
  error: string | null;
34
34
  lockedIds: Set<string>;
35
35
  realtimeOk: boolean;
36
+ /** Tijdstip van de laatste heropbouw na een buffer-seintje van de Engine. */
37
+ rebuiltAt: number | null;
36
38
  refresh: () => void;
37
39
  };
38
40
  /** Houdt bij dat dit scherm online is en ruimt verlopen locks op. */
@@ -1 +1 @@
1
- {"version":3,"file":"usePickQueue.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickQueue.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAY,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG9E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,EAAE,YAS5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;;;;;;;;;;;;EAoJA;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM;;EAuBhG;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,0FAOnF;AACD,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,OAAO,UAAO;;;aAQzC"}
1
+ {"version":3,"file":"usePickQueue.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickQueue.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAY,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG9E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,EAAE,YAS5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;;;;;;;;;;;IAgLG,6EAA6E;;;EAIhF;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM;;EAuBhG;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,0FAOnF;AACD,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,OAAO,UAAO;;;aAQzC"}
@@ -39,6 +39,20 @@ export function usePickQueue(args) {
39
39
  refetchInterval: 60000,
40
40
  retry: false,
41
41
  });
42
+ /**
43
+ * Seintjes van de Engine: een gesloten buffer of een losgekoppelde order.
44
+ * Zodra er zo'n seintje is, worden de regels opnieuw opgebouwd vanuit de
45
+ * Engine — de oude groepering per eenheid wordt niet meer getoond.
46
+ */
47
+ const bufferEventsQuery = useQuery({
48
+ queryKey: ["pick", "bufferEvents"],
49
+ enabled,
50
+ queryFn: () => pickApi.applyBufferEvents(),
51
+ refetchInterval: 15000,
52
+ retry: false,
53
+ });
54
+ const rebuildCount = bufferEventsQuery.data?.events ?? 0;
55
+ const [rebuiltAt, setRebuiltAt] = useState(null);
42
56
  const pickDayQuery = useQuery({
43
57
  queryKey: ["pick", "pickDay"],
44
58
  enabled: enabled && !syncQuery.isLoading,
@@ -54,6 +68,20 @@ export function usePickQueue(args) {
54
68
  queryClient.invalidateQueries({ queryKey: ["pick", "queue"] });
55
69
  queryClient.invalidateQueries({ queryKey: ["pick", "dayCounts"] });
56
70
  }, [syncQuery.data, queryClient]);
71
+ /**
72
+ * Na een buffer-seintje: de oude regels uit het geheugen gooien en alles
73
+ * opnieuw ophalen bij de Engine. Niets uit cache tonen.
74
+ */
75
+ useEffect(() => {
76
+ if (rebuildCount <= 0)
77
+ return;
78
+ queryClient.removeQueries({ queryKey: ["pick", "queue"] });
79
+ queryClient.invalidateQueries({ queryKey: ["pick", "pickDay"] });
80
+ queryClient.invalidateQueries({ queryKey: ["pick", "pickDays"] });
81
+ queryClient.invalidateQueries({ queryKey: ["pick", "dayCounts"] });
82
+ queryClient.invalidateQueries({ queryKey: ["pick", "countryCounts"] });
83
+ setRebuiltAt(Date.now());
84
+ }, [rebuildCount, bufferEventsQuery.dataUpdatedAt, queryClient]);
57
85
  const key = useMemo(() => ["pick", "queue", stationId ?? "-", screenId ?? "-", pickDay ?? "-", filters], [stationId, screenId, pickDay, filters]);
58
86
  const queueQuery = useQuery({
59
87
  queryKey: key,
@@ -142,6 +170,8 @@ export function usePickQueue(args) {
142
170
  error: queueQuery.error instanceof Error ? queueQuery.error.message : null,
143
171
  lockedIds,
144
172
  realtimeOk,
173
+ /** Tijdstip van de laatste heropbouw na een buffer-seintje van de Engine. */
174
+ rebuiltAt,
145
175
  refresh: invalidateNow,
146
176
  };
147
177
  }
@@ -2155,6 +2155,8 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
2155
2155
  created_at: string;
2156
2156
  currency: string;
2157
2157
  distribute_over: string | null;
2158
+ external_id: string | null;
2159
+ external_synced_at: string | null;
2158
2160
  group_type: string;
2159
2161
  handling_fee: number | null;
2160
2162
  id: string;
@@ -2167,6 +2169,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
2167
2169
  rounding: string;
2168
2170
  rounding_step: number;
2169
2171
  sort_order: number;
2172
+ source: string;
2170
2173
  unit: string;
2171
2174
  updated_at: string;
2172
2175
  };
@@ -2177,6 +2180,8 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
2177
2180
  created_at?: string;
2178
2181
  currency?: string;
2179
2182
  distribute_over?: string | null;
2183
+ external_id?: string | null;
2184
+ external_synced_at?: string | null;
2180
2185
  group_type?: string;
2181
2186
  handling_fee?: number | null;
2182
2187
  id?: string;
@@ -2189,6 +2194,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
2189
2194
  rounding?: string;
2190
2195
  rounding_step?: number;
2191
2196
  sort_order?: number;
2197
+ source?: string;
2192
2198
  unit?: string;
2193
2199
  updated_at?: string;
2194
2200
  };
@@ -2199,6 +2205,8 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
2199
2205
  created_at?: string;
2200
2206
  currency?: string;
2201
2207
  distribute_over?: string | null;
2208
+ external_id?: string | null;
2209
+ external_synced_at?: string | null;
2202
2210
  group_type?: string;
2203
2211
  handling_fee?: number | null;
2204
2212
  id?: string;
@@ -2211,6 +2219,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
2211
2219
  rounding?: string;
2212
2220
  rounding_step?: number;
2213
2221
  sort_order?: number;
2222
+ source?: string;
2214
2223
  unit?: string;
2215
2224
  updated_at?: string;
2216
2225
  };
@@ -9074,6 +9083,30 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
9074
9083
  referencedColumns: ["id"];
9075
9084
  }];
9076
9085
  };
9086
+ job_locks: {
9087
+ Row: {
9088
+ created_at: string;
9089
+ lock_key: string;
9090
+ locked_until: string;
9091
+ owner: string | null;
9092
+ updated_at: string;
9093
+ };
9094
+ Insert: {
9095
+ created_at?: string;
9096
+ lock_key: string;
9097
+ locked_until: string;
9098
+ owner?: string | null;
9099
+ updated_at?: string;
9100
+ };
9101
+ Update: {
9102
+ created_at?: string;
9103
+ lock_key?: string;
9104
+ locked_until?: string;
9105
+ owner?: string | null;
9106
+ updated_at?: string;
9107
+ };
9108
+ Relationships: [];
9109
+ };
9077
9110
  layout_logos: {
9078
9111
  Row: {
9079
9112
  bestand_url: string;
@@ -10236,6 +10269,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
10236
10269
  next_attempt_at: string;
10237
10270
  order_id: string;
10238
10271
  reason: string;
10272
+ reason_code: string | null;
10239
10273
  status: string;
10240
10274
  updated_at: string;
10241
10275
  };
@@ -10248,6 +10282,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
10248
10282
  next_attempt_at?: string;
10249
10283
  order_id: string;
10250
10284
  reason?: string;
10285
+ reason_code?: string | null;
10251
10286
  status?: string;
10252
10287
  updated_at?: string;
10253
10288
  };
@@ -10260,6 +10295,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
10260
10295
  next_attempt_at?: string;
10261
10296
  order_id?: string;
10262
10297
  reason?: string;
10298
+ reason_code?: string | null;
10263
10299
  status?: string;
10264
10300
  updated_at?: string;
10265
10301
  };
@@ -10964,6 +11000,21 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
10964
11000
  referencedColumns: ["id"];
10965
11001
  }];
10966
11002
  };
11003
+ logistics_tick_heartbeat: {
11004
+ Row: {
11005
+ id: boolean;
11006
+ last_tick_at: string;
11007
+ };
11008
+ Insert: {
11009
+ id?: boolean;
11010
+ last_tick_at?: string;
11011
+ };
11012
+ Update: {
11013
+ id?: boolean;
11014
+ last_tick_at?: string;
11015
+ };
11016
+ Relationships: [];
11017
+ };
10967
11018
  logistics_variables: {
10968
11019
  Row: {
10969
11020
  created_at: string;
@@ -13601,6 +13652,27 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
13601
13652
  };
13602
13653
  Relationships: [];
13603
13654
  };
13655
+ pick_buffer_event_cursor: {
13656
+ Row: {
13657
+ created_at: string;
13658
+ id: boolean;
13659
+ last_event_at: string;
13660
+ updated_at: string;
13661
+ };
13662
+ Insert: {
13663
+ created_at?: string;
13664
+ id?: boolean;
13665
+ last_event_at?: string;
13666
+ updated_at?: string;
13667
+ };
13668
+ Update: {
13669
+ created_at?: string;
13670
+ id?: boolean;
13671
+ last_event_at?: string;
13672
+ updated_at?: string;
13673
+ };
13674
+ Relationships: [];
13675
+ };
13604
13676
  pick_countries: {
13605
13677
  Row: {
13606
13678
  active: boolean;
@@ -22846,6 +22918,30 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
22846
22918
  };
22847
22919
  Returns: import("./types").Json;
22848
22920
  };
22921
+ logistics_block_reason_code: {
22922
+ Args: {
22923
+ p_details?: import("./types").Json;
22924
+ p_reason: string;
22925
+ };
22926
+ Returns: string;
22927
+ };
22928
+ logistics_blocked_orders: {
22929
+ Args: never;
22930
+ Returns: {
22931
+ attempts: number;
22932
+ blocked_since: string;
22933
+ delivery_date: string;
22934
+ order_id: string;
22935
+ order_ref: string;
22936
+ queue_id: string;
22937
+ reason: string;
22938
+ reason_code: string;
22939
+ }[];
22940
+ };
22941
+ logistics_blocked_overview: {
22942
+ Args: never;
22943
+ Returns: import("./types").Json;
22944
+ };
22849
22945
  logistics_buffer_criteria: {
22850
22946
  Args: {
22851
22947
  p_settings: import("./types").Json;
@@ -22860,6 +22956,39 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
22860
22956
  };
22861
22957
  Returns: import("./types").Json;
22862
22958
  };
22959
+ logistics_buffer_detach_late_orders: {
22960
+ Args: {
22961
+ p_buffer?: string;
22962
+ };
22963
+ Returns: import("./types").Json;
22964
+ };
22965
+ logistics_buffer_frozen_order: {
22966
+ Args: {
22967
+ p_order_id: string;
22968
+ };
22969
+ Returns: boolean;
22970
+ };
22971
+ logistics_buffer_handled: {
22972
+ Args: {
22973
+ p_buffer: string;
22974
+ };
22975
+ Returns: boolean;
22976
+ };
22977
+ logistics_buffer_notify: {
22978
+ Args: {
22979
+ p_event_type: string;
22980
+ p_idempotency_key: string;
22981
+ p_order_ref: string;
22982
+ p_payload: import("./types").Json;
22983
+ };
22984
+ Returns: string;
22985
+ };
22986
+ logistics_buffer_open_key: {
22987
+ Args: {
22988
+ p_base_key: string;
22989
+ };
22990
+ Returns: string;
22991
+ };
22863
22992
  logistics_buffer_simulate: {
22864
22993
  Args: {
22865
22994
  p_orders?: import("./types").Json;
@@ -22949,6 +23078,25 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
22949
23078
  Args: never;
22950
23079
  Returns: import("./types").Json;
22951
23080
  };
23081
+ logistics_cart_plan_overview: {
23082
+ Args: {
23083
+ p_days?: number;
23084
+ };
23085
+ Returns: {
23086
+ cart_total: number;
23087
+ delivery_date: string;
23088
+ order_ref: string;
23089
+ plan_ready: boolean;
23090
+ reason: string;
23091
+ released: boolean;
23092
+ }[];
23093
+ };
23094
+ logistics_cart_plan_status: {
23095
+ Args: {
23096
+ p_ref: string;
23097
+ };
23098
+ Returns: import("./types").Json;
23099
+ };
22952
23100
  logistics_cart_seq: {
22953
23101
  Args: {
22954
23102
  p_order_uuid?: string;
@@ -23482,6 +23630,12 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
23482
23630
  };
23483
23631
  Returns: boolean;
23484
23632
  };
23633
+ logistics_link_order_items: {
23634
+ Args: {
23635
+ p_order?: string;
23636
+ };
23637
+ Returns: import("./types").Json;
23638
+ };
23485
23639
  logistics_live_carriers: {
23486
23640
  Args: {
23487
23641
  p_order_ref: string;
@@ -23508,6 +23662,12 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
23508
23662
  };
23509
23663
  Returns: string;
23510
23664
  };
23665
+ logistics_normalize_product_label: {
23666
+ Args: {
23667
+ p_label: string;
23668
+ };
23669
+ Returns: string;
23670
+ };
23511
23671
  logistics_not_past: {
23512
23672
  Args: {
23513
23673
  p_ts: string;
@@ -23696,6 +23856,12 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
23696
23856
  Args: never;
23697
23857
  Returns: number;
23698
23858
  };
23859
+ logistics_plan_retry: {
23860
+ Args: {
23861
+ p_order_ids: string[];
23862
+ };
23863
+ Returns: number;
23864
+ };
23699
23865
  logistics_plan_setting: {
23700
23866
  Args: {
23701
23867
  p_default: number;
@@ -23802,6 +23968,12 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
23802
23968
  };
23803
23969
  Returns: import("./types").Json;
23804
23970
  };
23971
+ logistics_resolve_product_id: {
23972
+ Args: {
23973
+ p_label: string;
23974
+ };
23975
+ Returns: string;
23976
+ };
23805
23977
  logistics_resolve_settings: {
23806
23978
  Args: {
23807
23979
  p_config_id: string;
@@ -23931,6 +24103,10 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
23931
24103
  };
23932
24104
  Returns: number;
23933
24105
  };
24106
+ logistics_tick_ping: {
24107
+ Args: never;
24108
+ Returns: string;
24109
+ };
23934
24110
  logistics_upsert_task: {
23935
24111
  Args: {
23936
24112
  p_buffer_ref: string;
@@ -24115,6 +24291,10 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
24115
24291
  online: boolean;
24116
24292
  }[];
24117
24293
  };
24294
+ pick_apply_buffer_events: {
24295
+ Args: never;
24296
+ Returns: import("./types").Json;
24297
+ };
24118
24298
  pick_available_pick_days: {
24119
24299
  Args: {
24120
24300
  _max_days?: number;
@@ -25042,6 +25222,12 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
25042
25222
  };
25043
25223
  Returns: boolean;
25044
25224
  };
25225
+ release_job_lock: {
25226
+ Args: {
25227
+ _key: string;
25228
+ };
25229
+ Returns: undefined;
25230
+ };
25045
25231
  release_local_pdf_job: {
25046
25232
  Args: {
25047
25233
  _job_id: string;
@@ -25730,6 +25916,14 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
25730
25916
  row_count: number;
25731
25917
  }[];
25732
25918
  };
25919
+ try_acquire_job_lock: {
25920
+ Args: {
25921
+ _key: string;
25922
+ _owner?: string;
25923
+ _seconds?: number;
25924
+ };
25925
+ Returns: boolean;
25926
+ };
25733
25927
  try_debtor_lock: {
25734
25928
  Args: {
25735
25929
  _group_key: string;