@flowselections/pick-schermen-kwekers 1.0.58 → 1.0.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist-lib/components/PickPublicPage.d.ts.map +1 -1
  2. package/dist-lib/components/PickPublicPage.js +33 -2
  3. package/dist-lib/components/PickstationsPage.d.ts.map +1 -1
  4. package/dist-lib/components/PickstationsPage.js +2 -1
  5. package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
  6. package/dist-lib/components/pick/PickScherm.js +11 -4
  7. package/dist-lib/components/pick/ShippingNoteScan.d.ts.map +1 -1
  8. package/dist-lib/components/pick/ShippingNoteScan.js +52 -13
  9. package/dist-lib/components/pick/StationDevices.d.ts +6 -0
  10. package/dist-lib/components/pick/StationDevices.d.ts.map +1 -0
  11. package/dist-lib/components/pick/StationDevices.js +55 -0
  12. package/dist-lib/components/pick/StationPairing.d.ts +7 -0
  13. package/dist-lib/components/pick/StationPairing.d.ts.map +1 -0
  14. package/dist-lib/components/pick/StationPairing.js +25 -0
  15. package/dist-lib/components/pick/StickerState.d.ts +4 -0
  16. package/dist-lib/components/pick/StickerState.d.ts.map +1 -1
  17. package/dist-lib/components/pick/StickerState.js +30 -4
  18. package/dist-lib/hooks/usePickQueue.d.ts.map +1 -1
  19. package/dist-lib/hooks/usePickQueue.js +4 -0
  20. package/dist-lib/index.d.ts +1 -0
  21. package/dist-lib/index.d.ts.map +1 -1
  22. package/dist-lib/index.js +1 -0
  23. package/dist-lib/integrations/supabase/types.d.ts +3828 -90
  24. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  25. package/dist-lib/lib/__tests__/pick159.test.d.ts +2 -0
  26. package/dist-lib/lib/__tests__/pick159.test.d.ts.map +1 -0
  27. package/dist-lib/lib/__tests__/pick159.test.js +36 -0
  28. package/dist-lib/lib/__tests__/pick161.test.d.ts +2 -0
  29. package/dist-lib/lib/__tests__/pick161.test.d.ts.map +1 -0
  30. package/dist-lib/lib/__tests__/pick161.test.js +29 -0
  31. package/dist-lib/lib/__tests__/pickUitwijk.test.d.ts +2 -0
  32. package/dist-lib/lib/__tests__/pickUitwijk.test.d.ts.map +1 -0
  33. package/dist-lib/lib/__tests__/pickUitwijk.test.js +36 -0
  34. package/dist-lib/lib/pick150.d.ts.map +1 -1
  35. package/dist-lib/lib/pick150.js +2 -1
  36. package/dist-lib/lib/pick152.d.ts.map +1 -1
  37. package/dist-lib/lib/pick152.js +2 -1
  38. package/dist-lib/lib/pick156.d.ts.map +1 -1
  39. package/dist-lib/lib/pick156.js +2 -1
  40. package/dist-lib/lib/pick159.d.ts +56 -0
  41. package/dist-lib/lib/pick159.d.ts.map +1 -0
  42. package/dist-lib/lib/pick159.js +125 -0
  43. package/dist-lib/lib/pick161.d.ts +27 -0
  44. package/dist-lib/lib/pick161.d.ts.map +1 -0
  45. package/dist-lib/lib/pick161.js +86 -0
  46. package/dist-lib/lib/pickApi.d.ts.map +1 -1
  47. package/dist-lib/lib/pickApi.js +35 -81
  48. package/dist-lib/lib/pickPreview.d.ts.map +1 -1
  49. package/dist-lib/lib/pickPreview.js +5 -5
  50. package/dist-lib/lib/pickStickers.d.ts +5 -0
  51. package/dist-lib/lib/pickStickers.d.ts.map +1 -1
  52. package/dist-lib/lib/pickStickers.js +5 -1
  53. package/dist-lib/lib/pickUitwijk.d.ts +25 -0
  54. package/dist-lib/lib/pickUitwijk.d.ts.map +1 -0
  55. package/dist-lib/lib/pickUitwijk.js +93 -0
  56. package/dist-lib/lib/shippingNote.d.ts +2 -0
  57. package/dist-lib/lib/shippingNote.d.ts.map +1 -1
  58. package/dist-lib/lib/shippingNote.js +2 -1
  59. package/package.json +4 -2
@@ -1 +1 @@
1
- {"version":3,"file":"PickPublicPage.d.ts","sourceRoot":"","sources":["../../src/components/PickPublicPage.tsx"],"names":[],"mappings":"AAKA,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,+BA2B7C"}
1
+ {"version":3,"file":"PickPublicPage.d.ts","sourceRoot":"","sources":["../../src/components/PickPublicPage.tsx"],"names":[],"mappings":"AAQA,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,+BAiE7C"}
@@ -1,17 +1,48 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
2
3
  import { useQuery } from "@tanstack/react-query";
3
4
  import { Loader2 } from "lucide-react";
4
5
  import { pickApi } from "../lib/pickApi.js";
6
+ import { fetchDeviceStatus, mustPair, readDeviceKey, setActiveDeviceKey } from "../lib/pick159.js";
5
7
  import { PickScherm } from "./pick/PickScherm.js";
8
+ import { StationPairing } from "./pick/StationPairing.js";
6
9
  /** Openbaar pickscherm, bereikbaar via /pickstation/<slug>. */
7
10
  export function PickPublicPage({ slug }) {
11
+ const [deviceKey, setDeviceKey] = useState(null);
12
+ const [keyRead, setKeyRead] = useState(false);
13
+ const [qrCode, setQrCode] = useState(undefined);
14
+ useEffect(() => {
15
+ setActiveDeviceKey(deviceKey);
16
+ return () => setActiveDeviceKey(null);
17
+ }, [deviceKey]);
18
+ useEffect(() => {
19
+ setDeviceKey(readDeviceKey(slug));
20
+ const c = new URLSearchParams(window.location.search).get("koppelcode");
21
+ if (c)
22
+ setQrCode(c);
23
+ setKeyRead(true);
24
+ }, [slug]);
25
+ const { data: deviceStatus, isLoading: statusLoading, refetch } = useQuery({
26
+ queryKey: ["pick", "device-status", slug, deviceKey],
27
+ queryFn: () => fetchDeviceStatus(slug, deviceKey),
28
+ enabled: keyRead,
29
+ });
8
30
  const { data: station, isLoading } = useQuery({
9
- queryKey: ["pick", "station", slug],
31
+ queryKey: ["pick", "station", slug, deviceKey],
10
32
  queryFn: () => pickApi.stationBySlug(slug),
33
+ enabled: keyRead,
11
34
  });
12
- if (isLoading) {
35
+ if (isLoading || !keyRead || statusLoading) {
13
36
  return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-background", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin text-primary" }) }));
14
37
  }
38
+ if (mustPair(deviceStatus ?? null) || (qrCode && !deviceStatus?.gekoppeld)) {
39
+ return (_jsx(StationPairing, { slug: slug, initialCode: qrCode, onPaired: () => {
40
+ setQrCode(undefined);
41
+ window.history.replaceState(null, "", window.location.pathname);
42
+ setDeviceKey(readDeviceKey(slug));
43
+ void refetch();
44
+ } }));
45
+ }
15
46
  if (!station) {
16
47
  return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-background", children: _jsx("p", { className: "text-muted-foreground", children: "Pickstation niet gevonden of niet actief." }) }));
17
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PickstationsPage.d.ts","sourceRoot":"","sources":["../../src/components/PickstationsPage.tsx"],"names":[],"mappings":"AAkGA,wBAAgB,gBAAgB,gCA4L/B"}
1
+ {"version":3,"file":"PickstationsPage.d.ts","sourceRoot":"","sources":["../../src/components/PickstationsPage.tsx"],"names":[],"mappings":"AAmGA,wBAAgB,gBAAgB,gCA6L/B"}
@@ -8,6 +8,7 @@ import { usePickStations } from "../hooks/usePickConfig.js";
8
8
  import { useKoppelingVoorBron } from "../hooks/useKoppelingVoorBron.js";
9
9
  import { ReferentiedataBanner } from "./pick/ReferentiedataBanner.js";
10
10
  import { DOCUMENT_AUTO_TEXT } from "../lib/pick156.js";
11
+ import { StationDevices } from "./pick/StationDevices.js";
11
12
  const emptyDraft = { name: "", description: "", active: true };
12
13
  function publicUrl(slug) {
13
14
  const origin = typeof window !== "undefined" ? window.location.origin : "";
@@ -61,7 +62,7 @@ export function PickstationsPage() {
61
62
  return (_jsxs("main", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-foreground", children: "Pickstations" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Beheer je pickstations en de link die je met de medewerkers deelt." })] }), _jsxs(Button, { onClick: () => setDraft({ ...emptyDraft }), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Nieuw pickstation"] })] }), _jsx(ReferentiedataBanner, {}), isLoading ? (_jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Laden..."] })) : safeStations.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen pickstations." })) : (_jsx("div", { className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3", children: safeStations.map((station) => (_jsx(Card, { className: "border-2", children: _jsxs(CardContent, { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: station.name }), _jsx("p", { className: "text-sm text-muted-foreground", children: station.description })] }), _jsx("span", { className: "rounded-full px-2 py-1 text-xs font-medium " +
62
63
  (station.active
63
64
  ? "bg-primary/10 text-primary"
64
- : "bg-muted text-muted-foreground"), children: station.active ? "Actief" : "Inactief" })] }), _jsx("code", { className: "block truncate rounded bg-muted px-2 py-1 text-xs text-muted-foreground", children: publicUrl(station.slug) }), _jsx(StationPrintplek, { station: station }), _jsx("p", { className: "text-sm text-muted-foreground", children: DOCUMENT_AUTO_TEXT }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { className: "flex-1", asChild: true, children: _jsxs("a", { href: publicUrl(station.slug), target: "_blank", rel: "noreferrer", children: [_jsx(ExternalLink, { className: "mr-2 h-4 w-4" }), " Open pickstation"] }) }), _jsxs(Button, { variant: "outline", onClick: () => copyLink(station), children: [_jsx(Copy, { className: "mr-2 h-4 w-4" }), " Link kopi\u00EBren"] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setDraft({
65
+ : "bg-muted text-muted-foreground"), children: station.active ? "Actief" : "Inactief" })] }), _jsx("code", { className: "block truncate rounded bg-muted px-2 py-1 text-xs text-muted-foreground", children: publicUrl(station.slug) }), _jsx(StationPrintplek, { station: station }), _jsx("p", { className: "text-sm text-muted-foreground", children: DOCUMENT_AUTO_TEXT }), _jsx(StationDevices, { stationId: station.id, slug: station.slug ?? null }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { className: "flex-1", asChild: true, children: _jsxs("a", { href: publicUrl(station.slug), target: "_blank", rel: "noreferrer", children: [_jsx(ExternalLink, { className: "mr-2 h-4 w-4" }), " Open pickstation"] }) }), _jsxs(Button, { variant: "outline", onClick: () => copyLink(station), children: [_jsx(Copy, { className: "mr-2 h-4 w-4" }), " Link kopi\u00EBren"] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setDraft({
65
66
  id: station.id,
66
67
  name: station.name,
67
68
  description: station.description ?? "",
@@ -1 +1 @@
1
- {"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AA0DA,OAAO,EAaL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AA2D7B,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,+BAkqEpD"}
1
+ {"version":3,"file":"PickScherm.d.ts","sourceRoot":"","sources":["../../../src/components/pick/PickScherm.tsx"],"names":[],"mappings":"AA0DA,OAAO,EAaL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AA2D7B,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,+BAyqEpD"}
@@ -26,7 +26,7 @@ import { usePrintBatch, usePrintJob } from "../../hooks/usePrintJob.js";
26
26
  import { useShippingNoteStatus } from "../../hooks/useShippingNoteStatus.js";
27
27
  import { firstVisibleTarget, isJobFinished, isRowGoneError, NO_ROW_IN_FILTER_MESSAGE, RELEASE_PENDING_MESSAGE, ROW_GONE_MESSAGE, stuckMessage, stuckMinutesOf, } from "../../lib/pickRowState.js";
28
28
  import { CartItemRows, PlanWarnings } from "./CartItemRows.js";
29
- import { CartStickerState, OrderStickerMeldingen, StickerFitMeldingen } from "./StickerState.js";
29
+ import { CartStickerState, OrderStickerMeldingen, StickerFitMeldingen, VroegeStickerWaarschuwing } from "./StickerState.js";
30
30
  import { StickerReprintButton } from "./StickerReprintButton.js";
31
31
  import { isJobFailed } from "../../lib/pick142.js";
32
32
  import { isPrintBlocked } from "../../lib/pick156.js";
@@ -144,15 +144,22 @@ export function PickScherm({ station, onBack }) {
144
144
  if (fetchingNotes)
145
145
  return;
146
146
  setFetchingNotes(true);
147
+ const id = toast.loading("Verzendbrieven ophalen…");
147
148
  try {
148
149
  const result = await refreshShippingNotesNow();
149
150
  if (result.ok) {
150
- toast.success(result.message ?? "Verzendbrieven worden opgehaald.");
151
+ toast.success(result.message ?? "Verzendbrieven worden opgehaald.", { id });
151
152
  }
152
153
  else {
153
- toast.info("De verzendbrieven worden zo vanzelf opgehaald. Je hoeft niets te doen.");
154
+ toast.info("De verzendbrieven worden zo vanzelf opgehaald. Je hoeft niets te doen.", { id });
154
155
  }
155
156
  }
157
+ catch (e) {
158
+ toast.error("Verzendbrieven ophalen lukte niet. Probeer het over een minuut opnieuw.", {
159
+ id,
160
+ description: e instanceof Error ? `Details voor beheer: ${e.message}` : undefined,
161
+ });
162
+ }
156
163
  finally {
157
164
  setFetchingNotes(false);
158
165
  }
@@ -1371,7 +1378,7 @@ export function PickScherm({ station, onBack }) {
1371
1378
  const cart = plannedCart ?? { cartId: r.cartId, cartLabel: r.cartLabel ?? r.cartId };
1372
1379
  setLastCartResults((prev) => prev.filter((x) => x.cartId !== r.cartId));
1373
1380
  void reprintCart(lastPrinted, cart);
1374
- }, children: "Opnieuw printen" })] }, r.cartId))) }) })), lastCartResults.length > 1 && (_jsxs("div", { className: "rounded-md border p-3 text-sm", "aria-label": "Resultaat per kar", children: [_jsx("p", { className: "mb-1 font-semibold text-foreground", children: "Resultaat per kar" }), _jsx("ul", { className: "space-y-0.5 text-muted-foreground", children: lastCartResults.map((r) => (_jsx("li", { className: r.outcome === "created" ? "text-foreground" : r.outcome === "error" ? "text-destructive" : "", children: cartResultLine(r) }, r.cartId))) })] })), _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 || actionBusy), children: t("cancel") }), _jsxs(Button, { size: "lg", className: "h-14 w-full px-8 text-lg sm:w-auto", onClick: confirmPending, disabled: (busyId !== null || actionBusy) || fetchingData, variant: readiness.ready ? "default" : "secondary", children: [busyId === "confirm" || fetchingData ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : readiness.ready ? (_jsx(Printer, { className: "mr-2 h-5 w-5" })) : (_jsx(RefreshCw, { className: "mr-2 h-5 w-5" })), readiness.ready ? t("print") : "Pakbon ophalen"] })] })] }), !readiness.ready && (_jsx(CardContent, { className: "border-t p-4 sm:p-5", children: _jsxs("div", { className: "flex items-start gap-2 rounded-md border bg-muted/30 p-3 text-sm text-muted-foreground", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: fetchingData
1381
+ }, children: "Opnieuw printen" })] }, r.cartId))) }) })), lastCartResults.length > 1 && (_jsxs("div", { className: "rounded-md border p-3 text-sm", "aria-label": "Resultaat per kar", children: [_jsx("p", { className: "mb-1 font-semibold text-foreground", children: "Resultaat per kar" }), _jsx("ul", { className: "space-y-0.5 text-muted-foreground", children: lastCartResults.map((r) => (_jsx("li", { className: r.outcome === "created" ? "text-foreground" : r.outcome === "error" ? "text-destructive" : "", children: cartResultLine(r) }, r.cartId))) })] })), _jsx(VroegeStickerWaarschuwing, { stationId: station.id }), _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 || actionBusy), children: t("cancel") }), _jsxs(Button, { size: "lg", className: "h-14 w-full px-8 text-lg sm:w-auto", onClick: confirmPending, disabled: (busyId !== null || actionBusy) || fetchingData, variant: readiness.ready ? "default" : "secondary", children: [busyId === "confirm" || fetchingData ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : readiness.ready ? (_jsx(Printer, { className: "mr-2 h-5 w-5" })) : (_jsx(RefreshCw, { className: "mr-2 h-5 w-5" })), readiness.ready ? t("print") : "Pakbon ophalen"] })] })] }), !readiness.ready && (_jsx(CardContent, { className: "border-t p-4 sm:p-5", children: _jsxs("div", { className: "flex items-start gap-2 rounded-md border bg-muted/30 p-3 text-sm text-muted-foreground", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: fetchingData
1375
1382
  ? "De pakbon wordt opgevraagd. Zodra alles compleet is, verschijnt de printknop weer."
1376
1383
  : planReason
1377
1384
  ? `${planReason} Klik op "Pakbon ophalen" om hem op te vragen.`
@@ -1 +1 @@
1
- {"version":3,"file":"ShippingNoteScan.d.ts","sourceRoot":"","sources":["../../../src/components/pick/ShippingNoteScan.tsx"],"names":[],"mappings":"AASA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yEAAyE;IACzE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;CACxE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,KAAK,+BA0LlE"}
1
+ {"version":3,"file":"ShippingNoteScan.d.ts","sourceRoot":"","sources":["../../../src/components/pick/ShippingNoteScan.tsx"],"names":[],"mappings":"AAkBA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yEAAyE;IACzE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;CACxE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,KAAK,+BA0NlE"}
@@ -3,6 +3,16 @@ import { useCallback, useState } from "react";
3
3
  import { Badge, Button, Card, CardContent, Input, toast } from "@flowselections/core";
4
4
  import { AlertTriangle, CheckCircle2, Loader2, ScanLine } from "lucide-react";
5
5
  import { createShippingNote, lookupBarcode, } from "../../lib/shippingNote.js";
6
+ import { friendlyEngineMessage, isPakbonNumber, quantityText, SCAN_UNKNOWN, slipVariantText } from "../../lib/pick161.js";
7
+ import { pickDb } from "../../lib/pickApi.js";
8
+ async function toCartBarcode(code) {
9
+ if (!isPakbonNumber(code))
10
+ return code;
11
+ const { data, error } = await pickDb.rpc("pick_resolve_scan_code", { p_code: code });
12
+ if (error)
13
+ throw new Error(error.message);
14
+ return typeof data === "string" && data ? data : null;
15
+ }
6
16
  /**
7
17
  * Pakbon scannen -> verzendbrief. De module zoekt eerst op (leest alleen) en
8
18
  * maakt pas na een expliciete bevestiging een verzendbrief aan via de Engine.
@@ -11,7 +21,19 @@ export function ShippingNoteScan({ stationId, onJobCreated }) {
11
21
  const [code, setCode] = useState("");
12
22
  const [busy, setBusy] = useState(false);
13
23
  const [found, setFound] = useState(null);
14
- const [notice, setNotice] = useState(null);
24
+ const [notice, setNoticeRaw] = useState(null);
25
+ const [detail, setDetail] = useState(null);
26
+ const [status, setStatus] = useState(null);
27
+ const setNotice = useCallback((raw, fallback = SCAN_UNKNOWN) => {
28
+ if (raw == null) {
29
+ setNoticeRaw(null);
30
+ setDetail(null);
31
+ return;
32
+ }
33
+ const f = friendlyEngineMessage(raw, fallback);
34
+ setNoticeRaw(f.message);
35
+ setDetail(f.detail);
36
+ }, []);
15
37
  const [reprintNotice, setReprintNotice] = useState(null);
16
38
  const [warning, setWarning] = useState(null);
17
39
  const reset = useCallback(() => {
@@ -23,31 +45,43 @@ export function ShippingNoteScan({ stationId, onJobCreated }) {
23
45
  const barcode = raw.trim();
24
46
  if (!barcode)
25
47
  return;
48
+ let found_barcode = barcode;
26
49
  setBusy(true);
27
50
  reset();
28
51
  setNotice(null);
52
+ setStatus("Pakbon opzoeken…");
29
53
  try {
30
- const lookup = await lookupBarcode(barcode);
54
+ const cartBarcode = await toCartBarcode(barcode);
55
+ if (!cartBarcode) {
56
+ setNotice(null);
57
+ setNoticeRaw(SCAN_UNKNOWN);
58
+ return;
59
+ }
60
+ const lookup = await lookupBarcode(cartBarcode);
31
61
  if (!lookup.ok) {
32
- // De RPC levert een kant-en-klare melding; die tonen we letterlijk.
33
- setNotice(lookup.error ?? "De barcode kon niet worden opgezocht.");
62
+ setNoticeRaw(SCAN_UNKNOWN);
63
+ setDetail(lookup.error);
34
64
  return;
35
65
  }
36
- setFound({ barcode, lookup });
66
+ found_barcode = cartBarcode;
67
+ setFound({ barcode: found_barcode, lookup });
37
68
  setCode("");
38
69
  }
39
70
  catch (e) {
40
- setNotice(e instanceof Error ? e.message : "De barcode kon niet worden opgezocht.");
71
+ setNoticeRaw("De pakbon kon niet worden opgezocht. Probeer het opnieuw.");
72
+ setDetail(e instanceof Error ? e.message : null);
41
73
  }
42
74
  finally {
43
75
  setBusy(false);
76
+ setStatus(null);
44
77
  }
45
- }, [reset]);
78
+ }, [reset, setNotice]);
46
79
  const handleConfirm = useCallback(async (allowReprint) => {
47
80
  if (!found)
48
81
  return;
49
82
  setBusy(true);
50
83
  setWarning(null);
84
+ setStatus("Verzendbrief klaarzetten…");
51
85
  try {
52
86
  const result = await createShippingNote({
53
87
  barcode: found.barcode,
@@ -56,10 +90,12 @@ export function ShippingNoteScan({ stationId, onJobCreated }) {
56
90
  });
57
91
  if (!result.ok) {
58
92
  if (result.errorCode === "al_geprint") {
59
- setReprintNotice(result.error ?? "Er is al een verzendbrief voor deze kar gemaakt.");
93
+ setReprintNotice("Er is al een verzendbrief voor deze kar gemaakt.");
60
94
  return;
61
95
  }
62
- setNotice(result.error ?? "De verzendbrief kon niet worden klaargezet.");
96
+ setNotice(result.error ?? result.errorCode ?? null, "De verzendbrief kon niet worden klaargezet. Meld dit bij kantoor.");
97
+ if (!result.error && !result.errorCode)
98
+ setNoticeRaw("De verzendbrief kon niet worden klaargezet. Meld dit bij kantoor.");
63
99
  reset();
64
100
  return;
65
101
  }
@@ -73,17 +109,20 @@ export function ShippingNoteScan({ stationId, onJobCreated }) {
73
109
  setReprintNotice(null);
74
110
  }
75
111
  catch (e) {
76
- setNotice(e instanceof Error ? e.message : "De verzendbrief kon niet worden klaargezet.");
112
+ setNotice(e instanceof Error ? e.message : null, "De verzendbrief kon niet worden klaargezet. Probeer het opnieuw.");
113
+ if (!(e instanceof Error))
114
+ setNoticeRaw("De verzendbrief kon niet worden klaargezet. Probeer het opnieuw.");
77
115
  }
78
116
  finally {
79
117
  setBusy(false);
118
+ setStatus(null);
80
119
  }
81
- }, [found, stationId, onJobCreated, reset]);
120
+ }, [found, stationId, onJobCreated, reset, setNotice]);
82
121
  const cart = found?.lookup.cart ?? null;
83
- return (_jsx(Card, { children: _jsxs(CardContent, { className: "space-y-3 p-3 sm:p-4", children: [_jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [_jsx("p", { className: "text-sm font-semibold text-foreground", children: "Pakbon scannen" }), _jsxs("div", { className: "relative w-full min-w-0 sm:w-72", children: [_jsx(ScanLine, { 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: "Barcode van de pakbon", value: code, disabled: busy, onChange: (e) => setCode(e.target.value), onKeyDown: (e) => {
122
+ return (_jsx(Card, { children: _jsxs(CardContent, { className: "space-y-3 p-3 sm:p-4", children: [_jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [_jsx("p", { className: "text-sm font-semibold text-foreground", children: "Pakbon scannen" }), _jsxs("div", { className: "relative w-full min-w-0 sm:w-72", children: [_jsx(ScanLine, { 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: "Pakbonnummer of barcode onderaan de pakbon", value: code, disabled: busy, onChange: (e) => setCode(e.target.value), onKeyDown: (e) => {
84
123
  if (e.key !== "Enter")
85
124
  return;
86
125
  e.preventDefault();
87
126
  void handleLookup(code);
88
- } })] })] }), notice && (_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: notice })] })), warning && (_jsxs("div", { className: "flex items-start gap-2 rounded-md border p-3 text-sm text-muted-foreground", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: warning })] })), found && (_jsxs("div", { className: "rounded-md border-2 border-primary/40 bg-muted/20 p-3 sm:p-4", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "truncate text-lg font-bold text-foreground", children: found.lookup.orderNumber ?? "Order" }), _jsx("p", { className: "truncate text-sm text-muted-foreground", children: [found.lookup.customerName, cart?.cartLabel].filter(Boolean).join(" · ") })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [cart?.slipVariant && _jsx(Badge, { variant: "outline", children: cart.slipVariant }), cart?.barcode && _jsx(Badge, { variant: "outline", children: cart.barcode }), found.lookup.alreadyPrinted && (_jsxs(Badge, { className: "bg-destructive text-destructive-foreground", children: ["Al geprint (", found.lookup.printCount, ")"] }))] })] }), _jsx("div", { className: "mt-3 divide-y rounded-md border bg-background", children: cart && cart.items.length > 0 ? (cart.items.map((item, index) => (_jsxs("div", { className: "flex items-center justify-between gap-3 p-3", children: [_jsx("span", { className: "min-w-0 truncate text-sm text-foreground", children: item.productName }), _jsx("span", { className: "shrink-0 text-sm font-semibold text-foreground", children: item.quantity ?? 0 })] }, `${item.productName}-${index}`)))) : (_jsx("p", { className: "p-3 text-sm text-muted-foreground", children: "Geen regels bij deze kar." })) }), reprintNotice && (_jsxs("div", { className: "mt-3 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: reprintNotice })] })), _jsxs("div", { className: "mt-3 flex flex-col gap-2 sm:flex-row sm:justify-end", children: [_jsx(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:w-auto", onClick: reset, disabled: busy, children: "Annuleren" }), _jsxs(Button, { size: "lg", className: "h-12 w-full sm:w-auto", onClick: () => void handleConfirm(reprintNotice !== null), disabled: busy, children: [busy ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(CheckCircle2, { className: "mr-2 h-5 w-5" })), reprintNotice ? "Toch opnieuw printen" : "Verzendbrief klaarzetten"] })] })] }))] }) }));
127
+ } })] })] }), notice && (_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: notice })] })), status && (_jsxs("p", { role: "status", className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " ", status] })), detail && notice && (_jsxs("details", { className: "text-xs text-muted-foreground", children: [_jsx("summary", { className: "cursor-pointer", children: "Details voor beheer" }), _jsx("p", { children: detail })] })), warning && (_jsxs("div", { className: "flex items-start gap-2 rounded-md border p-3 text-sm text-muted-foreground", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: warning })] })), found && (_jsxs("div", { className: "rounded-md border-2 border-primary/40 bg-muted/20 p-3 sm:p-4", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "truncate text-lg font-bold text-foreground", children: found.lookup.orderNumber ?? "Order" }), _jsx("p", { className: "truncate text-sm text-muted-foreground", children: [found.lookup.customerName, cart?.cartLabel].filter(Boolean).join(" · ") })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [slipVariantText(cart?.slipVariant) && _jsx(Badge, { variant: "outline", children: slipVariantText(cart?.slipVariant) }), cart?.barcode && _jsx(Badge, { variant: "outline", children: cart.barcode }), found.lookup.alreadyPrinted && (_jsxs(Badge, { className: "bg-destructive text-destructive-foreground", children: ["Al geprint (", found.lookup.printCount, ")"] }))] })] }), _jsx("div", { className: "mt-3 divide-y rounded-md border bg-background", children: cart && cart.items.length > 0 ? (cart.items.map((item, index) => (_jsxs("div", { className: "flex items-center justify-between gap-3 p-3", children: [_jsx("span", { className: "min-w-0 truncate text-sm text-foreground", children: item.productName }), _jsx("span", { className: "shrink-0 text-sm font-semibold text-foreground", children: quantityText(item.quantity, item.crates) })] }, `${item.productName}-${index}`)))) : (_jsx("p", { className: "p-3 text-sm text-muted-foreground", children: "Geen regels bij deze kar." })) }), reprintNotice && (_jsxs("div", { className: "mt-3 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: reprintNotice })] })), _jsxs("div", { className: "mt-3 flex flex-col gap-2 sm:flex-row sm:justify-end", children: [_jsx(Button, { variant: "outline", size: "lg", className: "h-12 w-full sm:w-auto", onClick: reset, disabled: busy, children: "Annuleren" }), _jsxs(Button, { size: "lg", className: "h-12 w-full sm:w-auto", onClick: () => void handleConfirm(reprintNotice !== null), disabled: busy, children: [busy ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(CheckCircle2, { className: "mr-2 h-5 w-5" })), reprintNotice ? "Toch opnieuw printen" : "Verzendbrief klaarzetten"] })] })] }))] }) }));
89
128
  }
@@ -0,0 +1,6 @@
1
+ /** Beheer: apparaat koppelen (code + QR-link) en apparaten intrekken. */
2
+ export declare function StationDevices({ stationId, slug }: {
3
+ stationId: string;
4
+ slug: string | null;
5
+ }): import("react").JSX.Element;
6
+ //# sourceMappingURL=StationDevices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StationDevices.d.ts","sourceRoot":"","sources":["../../../src/components/pick/StationDevices.tsx"],"names":[],"mappings":"AAOA,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,+BAyE7F"}
@@ -0,0 +1,55 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ import QRCode from "qrcode";
4
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
5
+ import { Button, toast } from "@flowselections/core";
6
+ import { Loader2, Smartphone } from "lucide-react";
7
+ import { createPairCode, listDevices, revokeDevice } from "../../lib/pick159.js";
8
+ /** Beheer: apparaat koppelen (code + QR-link) en apparaten intrekken. */
9
+ export function StationDevices({ stationId, slug }) {
10
+ const qc = useQueryClient();
11
+ const [code, setCode] = useState(null);
12
+ const [bezig, setBezig] = useState(false);
13
+ const { data: devices = [], isLoading } = useQuery({
14
+ queryKey: ["pick", "devices", stationId],
15
+ queryFn: () => listDevices(stationId),
16
+ });
17
+ const actief = (Array.isArray(devices) ? devices : []).filter((d) => !d.ingetrokken_op);
18
+ const origin = typeof window !== "undefined" ? window.location.origin : "";
19
+ const link = code && slug ? `${origin}/pickstation/${slug}?koppelcode=${code.code}` : null;
20
+ const [qr, setQr] = useState(null);
21
+ useEffect(() => {
22
+ // QR wordt in de browser zelf getekend; er gaat niets naar een dienst van buiten.
23
+ if (!link)
24
+ return setQr(null);
25
+ let actief = true;
26
+ QRCode.toDataURL(link, { margin: 1, width: 220 }).then((u) => actief && setQr(u)).catch(() => actief && setQr(null));
27
+ return () => {
28
+ actief = false;
29
+ };
30
+ }, [link]);
31
+ async function nieuweCode() {
32
+ setBezig(true);
33
+ try {
34
+ setCode(await createPairCode(stationId));
35
+ }
36
+ catch {
37
+ toast.error("Er kon geen koppelcode worden gemaakt.");
38
+ }
39
+ finally {
40
+ setBezig(false);
41
+ }
42
+ }
43
+ async function intrekken(id) {
44
+ if (!window.confirm("Dit apparaat intrekken? Het kan daarna niet meer printen."))
45
+ return;
46
+ try {
47
+ await revokeDevice(id);
48
+ void qc.invalidateQueries({ queryKey: ["pick", "devices", stationId] });
49
+ }
50
+ catch {
51
+ toast.error("Intrekken lukte niet.");
52
+ }
53
+ }
54
+ return (_jsxs("div", { className: "space-y-2", children: [_jsxs("p", { className: "text-sm font-medium text-foreground", children: ["Apparaten ", isLoading ? "" : actief.length === 0 ? "– nog niet gekoppeld" : `– ${actief.length} gekoppeld`] }), actief.map((d) => (_jsxs("div", { className: "flex items-center justify-between gap-2 text-sm", children: [_jsxs("span", { className: "flex items-center gap-2 text-muted-foreground", children: [_jsx(Smartphone, { className: "h-4 w-4" }), d.naam ?? "Apparaat", d.laatst_gezien ? ` · laatst gezien ${new Date(d.laatst_gezien).toLocaleString("nl-NL")}` : ""] }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => void intrekken(d.id), children: "Intrekken" })] }, d.id))), _jsxs(Button, { size: "sm", variant: "secondary", disabled: bezig, onClick: () => void nieuweCode(), children: [bezig ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null, "Apparaat koppelen"] }), code ? (_jsxs("div", { className: "rounded-md border border-border p-3 text-sm", children: [_jsxs("p", { children: ["Koppelcode: ", _jsx("span", { className: "font-mono text-lg font-bold tracking-widest", children: code.code })] }), _jsx("p", { className: "text-muted-foreground", children: "10 minuten geldig, maximaal 5 pogingen." }), qr ? _jsx("img", { src: qr, alt: "QR-code om dit apparaat te koppelen", className: "mt-2 h-44 w-44 rounded bg-background" }) : null, link ? _jsxs("p", { className: "mt-2 break-all text-muted-foreground", children: ["Of open op het apparaat: ", link] }) : null] })) : null] }));
55
+ }
@@ -0,0 +1,7 @@
1
+ /** Volledig scherm voor een apparaat zonder geldige sleutel. */
2
+ export declare function StationPairing({ slug, initialCode, onPaired }: {
3
+ slug: string;
4
+ initialCode?: string;
5
+ onPaired: () => void;
6
+ }): import("react").JSX.Element;
7
+ //# sourceMappingURL=StationPairing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StationPairing.d.ts","sourceRoot":"","sources":["../../../src/components/pick/StationPairing.tsx"],"names":[],"mappings":"AAKA,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAAE,+BAuC3H"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Button, Card, CardContent, Input, Label } from "@flowselections/core";
4
+ import { Loader2 } from "lucide-react";
5
+ import { NOT_PAIRED_TEXT, pairDevice, saveDeviceKey } from "../../lib/pick159.js";
6
+ /** Volledig scherm voor een apparaat zonder geldige sleutel. */
7
+ export function StationPairing({ slug, initialCode, onPaired }) {
8
+ const [code, setCode] = useState(initialCode ?? "");
9
+ const [naam, setNaam] = useState("");
10
+ const [bezig, setBezig] = useState(false);
11
+ const [fout, setFout] = useState(null);
12
+ async function koppel() {
13
+ setBezig(true);
14
+ setFout(null);
15
+ const r = await pairDevice(slug, code.trim().toUpperCase(), naam.trim() || null);
16
+ setBezig(false);
17
+ if (r.ok) {
18
+ saveDeviceKey(slug, r.key);
19
+ onPaired();
20
+ }
21
+ else
22
+ setFout(r.tekst);
23
+ }
24
+ return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-background p-4", children: _jsx(Card, { className: "w-full max-w-md", children: _jsxs(CardContent, { className: "space-y-4 p-6", children: [_jsx("p", { className: "text-lg font-semibold text-foreground", children: NOT_PAIRED_TEXT }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "pair-code", children: "Koppelcode" }), _jsx(Input, { id: "pair-code", value: code, maxLength: 6, autoComplete: "off", onChange: (e) => setCode(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "pair-naam", children: "Naam van dit apparaat (mag leeg)" }), _jsx(Input, { id: "pair-naam", value: naam, maxLength: 80, onChange: (e) => setNaam(e.target.value) })] }), fout ? _jsx("p", { className: "text-sm text-destructive", children: fout }) : null, _jsxs(Button, { className: "w-full", disabled: bezig || code.trim().length !== 6, onClick: () => void koppel(), children: [bezig ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null, "Koppelen"] })] }) }) }));
25
+ }
@@ -13,4 +13,8 @@ export declare function CartStickerState({ cartId, slug }: {
13
13
  cartId: string;
14
14
  slug: string | null;
15
15
  }): import("react").JSX.Element | null;
16
+ /** Bovenaan het pickstation: stickers die vandaag/morgen via A4 of verkleind gaan. Niets als Layouts het nog niet levert. */
17
+ export declare function VroegeStickerWaarschuwing({ stationId }: {
18
+ stationId: string | null;
19
+ }): import("react").JSX.Element | null;
16
20
  //# sourceMappingURL=StickerState.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StickerState.d.ts","sourceRoot":"","sources":["../../../src/components/pick/StickerState.tsx"],"names":[],"mappings":"AAaA,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAuC5F;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAoBvG;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAqCzF"}
1
+ {"version":3,"file":"StickerState.d.ts","sourceRoot":"","sources":["../../../src/components/pick/StickerState.tsx"],"names":[],"mappings":"AAcA,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAuC5F;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAoBvG;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCA8CzF;AAED,6HAA6H;AAC7H,wBAAgB,yBAAyB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAiBpF"}
@@ -1,6 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useQuery } from "@tanstack/react-query";
3
- import { fetchCartStickerState, fetchOrderStickerMeldingen, STICKER_UNKNOWN, stickerStatusLabel, stickerSummary, } from "../../lib/pickStickers.js";
3
+ import { fetchCartStickerState, fetchOrderStickerMeldingen, STICKER_UNKNOWN, stickerStatusLabel, } from "../../lib/pickStickers.js";
4
+ import { stickerLine } from "../../lib/pick161.js";
5
+ import { fetchUitwijk, fetchVroegeWaarschuwing, vroegeWaarschuwingText } from "../../lib/pickUitwijk.js";
4
6
  import { fetchStickerFit, STICKER_FIT_UNKNOWN, stickerFitTone } from "../../lib/pick150.js";
5
7
  const POLL = 15000;
6
8
  /** Controle vooraf of de klantstickers van de kar passen; vóór het printen. */
@@ -59,15 +61,39 @@ export function CartStickerState({ cartId, slug }) {
59
61
  placeholderData: (prev) => prev,
60
62
  retry: 1,
61
63
  });
64
+ const jobIds = Array.isArray(q.data?.regels) ? q.data.regels.map((r) => r.printJobId).filter((x) => !!x).sort() : [];
65
+ const u = useQuery({
66
+ queryKey: ["pick", "uitwijk", jobIds.join(",")],
67
+ queryFn: () => fetchUitwijk(jobIds),
68
+ enabled: jobIds.length > 0,
69
+ refetchInterval: POLL,
70
+ placeholderData: (prev) => prev,
71
+ retry: 1,
72
+ });
62
73
  if (q.isLoading)
63
74
  return null;
64
75
  if (q.isError || !q.data) {
65
76
  return _jsx("p", { className: "mt-3 text-xs text-muted-foreground", children: STICKER_UNKNOWN });
66
77
  }
67
78
  const s = q.data;
79
+ const line = stickerLine(s, u.data);
68
80
  const regels = Array.isArray(s.regels) ? s.regels : [];
69
- const summary = stickerSummary(s);
70
81
  if (s.totaal === 0)
71
- return _jsx("p", { className: "mt-3 text-xs text-muted-foreground", children: summary });
72
- return (_jsxs("details", { className: "mt-3 rounded-md border bg-background p-3 text-sm", children: [_jsxs("summary", { className: "cursor-pointer font-medium text-foreground", children: ["Stickers: ", s.totaal ?? regels.length, " \u00B7 in de printwachtrij ", s.inPrintwachtrij ?? "—", " \u00B7 wachtend ", s.wachtend ?? "—", " \u00B7 geblokkeerd ", s.geblokkeerd ?? "—"] }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "In de printwachtrij betekent nog niet fysiek geprint." }), _jsx("ul", { className: "mt-2 divide-y", children: regels.map((r, i) => (_jsxs("li", { className: "flex flex-wrap justify-between gap-2 py-1.5 text-xs", children: [_jsxs("span", { className: "text-foreground", children: [r.soort ?? "sticker", " \u00B7 ", r.kopieen ?? "—", "x", r.breedteMm && r.hoogteMm ? ` · ${r.breedteMm}x${r.hoogteMm} mm` : ""] }), _jsxs("span", { className: "text-muted-foreground", children: [stickerStatusLabel(r.status), r.reden ? ` — ${r.reden}` : ""] })] }, r.stickerId ?? i))) })] }));
82
+ return _jsx("p", { className: "mt-3 text-sm text-muted-foreground", children: line });
83
+ return (_jsxs("details", { className: "mt-3 rounded-md border bg-background p-3 text-sm", children: [_jsxs("summary", { className: "cursor-pointer font-medium text-foreground", children: ["Stickers: ", line] }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "In de printwachtrij betekent nog niet fysiek geprint." }), _jsx("ul", { className: "mt-2 divide-y", children: regels.map((r, i) => (_jsxs("li", { className: "flex flex-wrap justify-between gap-2 py-1.5 text-xs", children: [_jsxs("span", { className: "text-foreground", children: [r.soort ?? "sticker", " \u00B7 ", r.kopieen ?? "—", "x", r.breedteMm && r.hoogteMm ? ` · ${r.breedteMm}x${r.hoogteMm} mm` : ""] }), _jsxs("span", { className: "text-muted-foreground", children: [stickerStatusLabel(r.status), r.reden ? ` — ${r.reden}` : ""] })] }, r.stickerId ?? i))) })] }));
84
+ }
85
+ /** Bovenaan het pickstation: stickers die vandaag/morgen via A4 of verkleind gaan. Niets als Layouts het nog niet levert. */
86
+ export function VroegeStickerWaarschuwing({ stationId }) {
87
+ const q = useQuery({
88
+ queryKey: ["pick", "vroege-sticker", stationId],
89
+ queryFn: () => fetchVroegeWaarschuwing(stationId),
90
+ refetchInterval: 5 * 60000,
91
+ placeholderData: (prev) => prev,
92
+ retry: 1,
93
+ });
94
+ const list = Array.isArray(q.data) ? q.data : [];
95
+ if (list.length === 0)
96
+ return null;
97
+ const today = new Date().toLocaleDateString("sv-SE");
98
+ return (_jsxs("div", { role: "status", className: "mb-3 space-y-1 rounded-md border-2 border-primary/40 bg-primary/5 p-3 text-sm text-foreground", children: [_jsx("p", { className: "font-medium", children: "Let op: stickers passen niet op het gewone etiket" }), list.map((w, i) => _jsx("p", { children: vroegeWaarschuwingText(w, today) }, i))] }));
73
99
  }
@@ -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;;;;;;;;;;;IA4LG,gEAAgE;;IAEhE,6EAA6E;;;EAIhF;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM;;EAuBhG;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,iFAOnF;AACD,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,OAAO,UAAO;;;YAQzC;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAEpF"}
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;;;;;;;;;;;IAoMG,gEAAgE;;IAEhE,6EAA6E;;;EAIhF;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM;;EAuBhG;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,iFAOnF;AACD,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,OAAO,UAAO;;;YAQzC;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAEpF"}
@@ -164,6 +164,10 @@ export function usePickQueue(args) {
164
164
  .channel(`pick-queue-${stationId ?? "all"}`)
165
165
  .on("postgres_changes", queueFilter, invalidate)
166
166
  .on("postgres_changes", lockFilter, invalidate)
167
+ // 1.0.59: alleen een seintje per station; de gegevens komen via functies met sleutel.
168
+ .on("postgres_changes", stationId
169
+ ? { event: "UPDATE", schema: "public", table: "pick_station_signals", filter: `station_id=eq.${stationId}` }
170
+ : { event: "UPDATE", schema: "public", table: "pick_station_signals" }, invalidate)
167
171
  .subscribe((status) => {
168
172
  setRealtimeOk(status === "SUBSCRIBED");
169
173
  });
@@ -31,5 +31,6 @@ export * from "./lib/pick145.js";
31
31
  export * from "./lib/pick150.js";
32
32
  export * from "./lib/pick152.js";
33
33
  export * from "./lib/pick156.js";
34
+ export * from "./lib/pick159.js";
34
35
  export { DocumentChoiceMelding, useDocumentChoice } from "./components/pick/DocumentChoiceMelding.js";
35
36
  //# sourceMappingURL=index.d.ts.map
@@ -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,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;AAEF,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACzF,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,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;AAEF,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACzF,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC"}
package/dist-lib/index.js CHANGED
@@ -56,4 +56,5 @@ export * from "./lib/pick145.js";
56
56
  export * from "./lib/pick150.js";
57
57
  export * from "./lib/pick152.js";
58
58
  export * from "./lib/pick156.js";
59
+ export * from "./lib/pick159.js";
59
60
  export { DocumentChoiceMelding, useDocumentChoice } from "./components/pick/DocumentChoiceMelding.js";