@flowselections/floriday-voorraad 1.0.152 → 1.0.155

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 (86) hide show
  1. package/dist-lib/components/fs-ui/DataTable.d.ts.map +1 -1
  2. package/dist-lib/components/fs-ui/DataTable.js +8 -8
  3. package/dist-lib/components/fs-ui/FilterChips.d.ts +1 -1
  4. package/dist-lib/components/fs-ui/FilterChips.d.ts.map +1 -1
  5. package/dist-lib/components/fs-ui/FilterChips.js +3 -3
  6. package/dist-lib/components/fs-ui/FilterPanel.d.ts +19 -0
  7. package/dist-lib/components/fs-ui/FilterPanel.d.ts.map +1 -0
  8. package/dist-lib/components/fs-ui/FilterPanel.js +10 -0
  9. package/dist-lib/components/fs-ui/FiltersButton.d.ts +6 -0
  10. package/dist-lib/components/fs-ui/FiltersButton.d.ts.map +1 -0
  11. package/dist-lib/components/fs-ui/FiltersButton.js +7 -0
  12. package/dist-lib/components/fs-ui/HeaderButton.d.ts +16 -0
  13. package/dist-lib/components/fs-ui/HeaderButton.d.ts.map +1 -0
  14. package/dist-lib/components/fs-ui/HeaderButton.js +10 -0
  15. package/dist-lib/components/fs-ui/KpiRow.d.ts +2 -2
  16. package/dist-lib/components/fs-ui/KpiRow.js +3 -3
  17. package/dist-lib/components/fs-ui/NoticeBar.d.ts +10 -0
  18. package/dist-lib/components/fs-ui/NoticeBar.d.ts.map +1 -0
  19. package/dist-lib/components/fs-ui/NoticeBar.js +16 -0
  20. package/dist-lib/components/fs-ui/PageHeader.d.ts +6 -5
  21. package/dist-lib/components/fs-ui/PageHeader.d.ts.map +1 -1
  22. package/dist-lib/components/fs-ui/PageHeader.js +4 -3
  23. package/dist-lib/components/fs-ui/Pagination.d.ts +10 -0
  24. package/dist-lib/components/fs-ui/Pagination.d.ts.map +1 -0
  25. package/dist-lib/components/fs-ui/Pagination.js +10 -0
  26. package/dist-lib/components/fs-ui/PillTabs.d.ts +3 -5
  27. package/dist-lib/components/fs-ui/PillTabs.d.ts.map +1 -1
  28. package/dist-lib/components/fs-ui/PillTabs.js +25 -15
  29. package/dist-lib/components/fs-ui/RowMenu.d.ts +13 -0
  30. package/dist-lib/components/fs-ui/RowMenu.d.ts.map +1 -0
  31. package/dist-lib/components/fs-ui/RowMenu.js +7 -0
  32. package/dist-lib/components/fs-ui/SearchInput.d.ts +1 -4
  33. package/dist-lib/components/fs-ui/SearchInput.d.ts.map +1 -1
  34. package/dist-lib/components/fs-ui/SearchInput.js +23 -19
  35. package/dist-lib/components/fs-ui/ShortcutHelp.d.ts +8 -0
  36. package/dist-lib/components/fs-ui/ShortcutHelp.d.ts.map +1 -0
  37. package/dist-lib/components/fs-ui/ShortcutHelp.js +6 -0
  38. package/dist-lib/components/fs-ui/Toolbar.d.ts +7 -3
  39. package/dist-lib/components/fs-ui/Toolbar.d.ts.map +1 -1
  40. package/dist-lib/components/fs-ui/Toolbar.js +6 -3
  41. package/dist-lib/components/fs-ui/UpdatedAt.d.ts +6 -2
  42. package/dist-lib/components/fs-ui/UpdatedAt.d.ts.map +1 -1
  43. package/dist-lib/components/fs-ui/UpdatedAt.js +16 -8
  44. package/dist-lib/components/voorraad/FloridayConnectionNotice.d.ts +2 -1
  45. package/dist-lib/components/voorraad/FloridayConnectionNotice.d.ts.map +1 -1
  46. package/dist-lib/components/voorraad/FloridayConnectionNotice.js +9 -4
  47. package/dist-lib/components/voorraad/FustenPage.d.ts.map +1 -1
  48. package/dist-lib/components/voorraad/FustenPage.js +90 -26
  49. package/dist-lib/components/voorraad/OrderHistoryCard.d.ts +3 -1
  50. package/dist-lib/components/voorraad/OrderHistoryCard.d.ts.map +1 -1
  51. package/dist-lib/components/voorraad/OrderHistoryCard.js +26 -50
  52. package/dist-lib/components/voorraad/PublicatiesPage.d.ts.map +1 -1
  53. package/dist-lib/components/voorraad/PublicatiesPage.js +41 -36
  54. package/dist-lib/components/voorraad/Sneltoetsen.d.ts +1 -1
  55. package/dist-lib/components/voorraad/Sneltoetsen.d.ts.map +1 -1
  56. package/dist-lib/components/voorraad/Sneltoetsen.js +12 -13
  57. package/dist-lib/components/voorraad/StockIntegrityAlert.d.ts +42 -1
  58. package/dist-lib/components/voorraad/StockIntegrityAlert.d.ts.map +1 -1
  59. package/dist-lib/components/voorraad/StockIntegrityAlert.js +30 -6
  60. package/dist-lib/components/voorraad/StockMutationHistoryCard.d.ts.map +1 -1
  61. package/dist-lib/components/voorraad/StockMutationHistoryCard.js +10 -46
  62. package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts.map +1 -1
  63. package/dist-lib/components/voorraad/ValidationOverviewTable.js +7 -38
  64. package/dist-lib/components/voorraad/ValidationPage.d.ts.map +1 -1
  65. package/dist-lib/components/voorraad/ValidationPage.js +3 -3
  66. package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
  67. package/dist-lib/components/voorraad/VoorraadPage.js +28 -10
  68. package/dist-lib/components/voorraad/artikel/ArtikelPagina.d.ts.map +1 -1
  69. package/dist-lib/components/voorraad/artikel/ArtikelPagina.js +16 -3
  70. package/dist-lib/components/voorraad/lijst/ImporteerKnop.d.ts.map +1 -1
  71. package/dist-lib/components/voorraad/lijst/ImporteerKnop.js +1 -1
  72. package/dist-lib/components/voorraad/lijst/LijstExportKnop.d.ts.map +1 -1
  73. package/dist-lib/components/voorraad/lijst/LijstExportKnop.js +1 -1
  74. package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.js +10 -10
  75. package/dist-lib/integrations/supabase/types.d.ts +102 -0
  76. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  77. package/dist-lib/lib/labels.d.ts +42 -0
  78. package/dist-lib/lib/labels.d.ts.map +1 -0
  79. package/dist-lib/lib/labels.js +152 -0
  80. package/dist-lib/lib/notatie.d.ts +4 -0
  81. package/dist-lib/lib/notatie.d.ts.map +1 -0
  82. package/dist-lib/lib/notatie.js +18 -0
  83. package/dist-lib/lib/voorraad-lijst.d.ts +4 -1
  84. package/dist-lib/lib/voorraad-lijst.d.ts.map +1 -1
  85. package/dist-lib/lib/voorraad-lijst.js +16 -5
  86. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
- import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@flowselections/core";
4
3
  import { isTypen } from "../fs-ui/SearchInput.js";
4
+ import { ShortcutHelp } from "../fs-ui/ShortcutHelp.js";
5
5
  /**
6
6
  * Sneltoetsen zoals in Verkooporders: N = nieuw (alleen als er een maak-actie is),
7
7
  * ? = overzicht. "/" (zoeken), J/K/Enter (rijen) en Esc zitten in SearchInput en DataTable.
@@ -28,18 +28,17 @@ export function Sneltoetsen({ onNieuw, nieuwLabel = "Nieuw artikel" }) {
28
28
  window.addEventListener("keydown", h);
29
29
  return () => window.removeEventListener("keydown", h);
30
30
  }, [onNieuw]);
31
- const regels = [
32
- ...(onNieuw ? [["N", nieuwLabel]] : []),
33
- ["/", "Zoeken"],
34
- ["J", "Volgende rij"],
35
- ["K", "Vorige rij"],
36
- ["Enter", "Openen"],
37
- ["Esc", "Sluiten of wissen"],
38
- ["?", "Dit overzicht"],
31
+ const shortcuts = [
32
+ [["/"], "Zoeken"],
33
+ ...(onNieuw ? [[["N"], nieuwLabel]] : []),
34
+ [["J", "K"], "Volgende / vorige rij"],
35
+ [["Enter"], "Geselecteerde rij openen"],
36
+ [["Esc"], "Zoeken wissen / sluiten"],
37
+ [["?"], "Dit overzicht"],
39
38
  ];
40
- return (_jsx(Dialog, { open: open, onOpenChange: setOpen, children: _jsxs(DialogContent, { className: "max-w-sm rounded-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Sneltoetsen" }), _jsx(DialogDescription, { children: "Werken niet terwijl je in een veld typt." })] }), _jsx("dl", { className: "divide-y divide-border text-sm", children: regels.map(([t, l]) => (_jsxs("div", { className: "flex items-center justify-between py-2", children: [_jsx("dt", { children: l }), _jsx("dd", { children: _jsx("kbd", { className: "rounded-sm border bg-muted px-1.5 py-0.5 text-xs", children: t }) })] }, t))) })] }) }));
39
+ return _jsx(ShortcutHelp, { open: open, onOpenChange: setOpen, shortcuts: shortcuts });
41
40
  }
42
- /** Kleine sneltoets-hint in een knop; alleen vanaf tablet. */
41
+ /** Kleine sneltoets-hint in een primaire knop, exact naar Verkooporders. */
43
42
  export function Kbd({ children }) {
44
- return _jsx("kbd", { className: "ml-2 hidden rounded-sm border border-current/30 px-1 text-[11px] leading-4 opacity-80 md:inline", children: children });
43
+ return _jsx("kbd", { "aria-hidden": true, className: "ml-2 hidden rounded border border-primary-foreground/30 bg-primary-foreground/15 px-1.5 font-mono text-[10px] leading-4 text-primary-foreground sm:inline-block", children: children });
45
44
  }
@@ -1,2 +1,43 @@
1
- export declare function StockIntegrityAlert(): import("react").JSX.Element | null;
1
+ /**
2
+ * Rode melding wanneer in één transactie twee of meer artikelen van een
3
+ * positieve fysieke voorraad naar 0 zijn gegaan (bewaking in de database:
4
+ * `stock_integrity_alerts`). Blijft staan tot iemand op "Gezien" klikt.
5
+ */
6
+ import { type ReactNode } from "react";
7
+ type AlertItem = {
8
+ trade_item_key: string;
9
+ physical_before: number;
10
+ change_source: string | null;
11
+ product_id?: string | null;
12
+ article_code?: string | null;
13
+ name?: string | null;
14
+ };
15
+ type IntegrityAlert = {
16
+ id: string;
17
+ created_at: string;
18
+ item_count: number;
19
+ alert_kind?: string | null;
20
+ items: (AlertItem & {
21
+ qty?: number | null;
22
+ order_number?: string | null;
23
+ })[];
24
+ };
25
+ /** Open voorraadbewakingsmeldingen, met namen en "Gezien". */
26
+ export declare function useStockIntegrityAlerts(): {
27
+ alerts: IntegrityAlert[];
28
+ names: Map<string, {
29
+ code: string | null;
30
+ name: string | null;
31
+ }>;
32
+ acknowledge: (id: string) => Promise<void>;
33
+ };
34
+ /**
35
+ * Meldingen als losse regels voor de NoticeBar: één regel per melding met
36
+ * "Details" (lijst in een venster, nooit in de melding zelf) en "Gezien".
37
+ */
38
+ export declare function useStockIntegrityNotices(): {
39
+ items: ReactNode[];
40
+ dialog: ReactNode;
41
+ };
42
+ export {};
2
43
  //# sourceMappingURL=StockIntegrityAlert.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StockIntegrityAlert.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockIntegrityAlert.tsx"],"names":[],"mappings":"AA4CA,wBAAgB,mBAAmB,uCAiIlC"}
1
+ {"version":3,"file":"StockIntegrityAlert.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockIntegrityAlert.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKzE,KAAK,SAAS,GAAG;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAmBF,KAAK,cAAc,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,CAAC,SAAS,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,EAAE,CAAC;CAC9E,CAAC;AAEF,8DAA8D;AAC9D,wBAAgB,uBAAuB;;;cAEkB,MAAM,GAAG,IAAI;cAAQ,MAAM,GAAG,IAAI;;sBAsD1D,MAAM;EAiBtC;AAUD;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI;IAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAyCpF"}
@@ -1,11 +1,11 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * Rode melding wanneer in één transactie twee of meer artikelen van een
4
4
  * positieve fysieke voorraad naar 0 zijn gegaan (bewaking in de database:
5
5
  * `stock_integrity_alerts`). Blijft staan tot iemand op "Gezien" klikt.
6
6
  */
7
7
  import { useCallback, useEffect, useState } from "react";
8
- import { AlertOctagon } from "lucide-react";
8
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@flowselections/core";
9
9
  import { toast } from "sonner";
10
10
  import { supabase } from "../../integrations/supabase/client.js";
11
11
  /** Bron van een voorraadwijziging in gewone woorden; onbekende codes niet tonen. */
@@ -23,7 +23,8 @@ function label(it, names) {
23
23
  return [code, name].filter(Boolean).join(" – ");
24
24
  return "onbekend artikel";
25
25
  }
26
- export function StockIntegrityAlert() {
26
+ /** Open voorraadbewakingsmeldingen, met namen en "Gezien". */
27
+ export function useStockIntegrityAlerts() {
27
28
  const [alerts, setAlerts] = useState([]);
28
29
  const [names, setNames] = useState(new Map());
29
30
  const load = useCallback(async () => {
@@ -88,7 +89,30 @@ export function StockIntegrityAlert() {
88
89
  }
89
90
  void load();
90
91
  };
91
- if (alerts.length === 0)
92
- return null;
93
- return (_jsx("div", { className: "space-y-2", children: alerts.map((a) => (_jsxs("div", { role: "alert", className: "flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2.5 text-sm text-foreground", children: [_jsx(AlertOctagon, { className: "mt-0.5 h-4 w-4 shrink-0 text-destructive", "aria-hidden": true }), _jsx("div", { className: "flex-1 space-y-1", children: a.alert_kind === "FLORIDAY_NOT_UPDATED" ? (_jsxs(_Fragment, { children: [_jsxs("p", { className: "font-medium", children: ["Verkoop niet in Floriday verwerkt \u2013 pas de Floriday-voorraad aan (", new Date(a.created_at).toLocaleString("nl-NL"), ")."] }), _jsx("p", { className: "text-xs text-foreground/80", children: "Floriday leidt deze artikelen. Deze verkoop kwam niet via Floriday, dus Floriday weet er niets van." }), _jsx("ul", { className: "text-xs text-foreground/80", children: (Array.isArray(a.items) ? a.items : []).slice(0, 10).map((it, i) => (_jsxs("li", { children: [label(it, names), ": ", it.qty ?? "?", " stuks", it.order_number ? ` (order ${it.order_number})` : ""] }, `${it.trade_item_key}-${i}`))) })] })) : (_jsxs(_Fragment, { children: [_jsxs("p", { className: "font-medium", children: [a.item_count, " artikelen gingen tegelijk naar voorraad 0 (", new Date(a.created_at).toLocaleString("nl-NL"), "). Controleer of dit klopt."] }), _jsx("ul", { className: "text-xs text-foreground/80", children: (Array.isArray(a.items) ? a.items : []).slice(0, 10).map((it, i) => (_jsxs("li", { children: [label(it, names), ": was ", it.physical_before, bronTekst(it.change_source)] }, `${it.trade_item_key}-${i}`))) })] })) }), _jsx("button", { type: "button", className: "h-8 rounded-lg border border-border bg-card px-3 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => void acknowledge(a.id), children: "Gezien" })] }, a.id))) }));
92
+ return { alerts, names, acknowledge };
93
+ }
94
+ const tijd = (iso) => new Date(iso).toLocaleString("nl-NL", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).replace(/\./g, "");
95
+ function samenvatting(a) {
96
+ return a.alert_kind === "FLORIDAY_NOT_UPDATED"
97
+ ? `Verkoop niet in Floriday verwerkt (${tijd(a.created_at)}): pas de Floriday-voorraad aan`
98
+ : `${a.item_count} artikelen gingen tegelijk naar 0 (${tijd(a.created_at)}): controleer of dit klopt`;
99
+ }
100
+ /**
101
+ * Meldingen als losse regels voor de NoticeBar: één regel per melding met
102
+ * "Details" (lijst in een venster, nooit in de melding zelf) en "Gezien".
103
+ */
104
+ export function useStockIntegrityNotices() {
105
+ const { alerts, names, acknowledge } = useStockIntegrityAlerts();
106
+ const [open, setOpen] = useState(null);
107
+ const items = alerts.map((a) => (_jsxs("span", { className: "inline-flex min-w-0 max-w-full items-center gap-2", children: [_jsx("span", { className: "truncate", children: samenvatting(a) }), _jsx("span", { role: "button", tabIndex: 0, className: "shrink-0 font-medium underline underline-offset-2", onClick: (e) => { e.stopPropagation(); setOpen(a); }, onKeyDown: (e) => { if (e.key === "Enter") {
108
+ e.stopPropagation();
109
+ setOpen(a);
110
+ } }, children: "Details" }), _jsx("span", { role: "button", tabIndex: 0, className: "shrink-0 font-medium underline underline-offset-2", onClick: (e) => { e.stopPropagation(); void acknowledge(a.id); }, onKeyDown: (e) => { if (e.key === "Enter") {
111
+ e.stopPropagation();
112
+ void acknowledge(a.id);
113
+ } }, children: "Gezien" })] }, a.id)));
114
+ const dialog = (_jsx(Dialog, { open: !!open, onOpenChange: (o) => !o && setOpen(null), children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Voorraadmelding" }) }), open && (_jsxs("div", { className: "space-y-3 text-sm", children: [_jsxs("p", { children: [samenvatting(open), "."] }), open.alert_kind === "FLORIDAY_NOT_UPDATED" && (_jsx("p", { className: "text-muted-foreground", children: "Floriday leidt deze artikelen. Deze verkoop kwam niet via Floriday, dus Floriday weet er niets van." })), _jsx("ul", { className: "max-h-80 divide-y divide-border overflow-auto rounded-lg border border-border", children: (Array.isArray(open.items) ? open.items : []).map((it, i) => (_jsxs("li", { className: "flex justify-between gap-3 px-3 py-2", children: [_jsx("span", { className: "min-w-0 truncate", children: label(it, names) }), _jsx("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: open.alert_kind === "FLORIDAY_NOT_UPDATED"
115
+ ? `${it.qty ?? "?"} stuks${it.order_number ? ` · order ${it.order_number}` : ""}`
116
+ : `was ${it.physical_before} stuks${bronTekst(it.change_source)}` })] }, `${it.trade_item_key}-${i}`))) }), _jsx("div", { className: "flex justify-end", children: _jsx("button", { type: "button", className: "h-8 rounded-md border border-border bg-card px-3 text-sm font-medium hover:bg-muted", onClick: () => { void acknowledge(open.id); setOpen(null); }, children: "Gezien" }) })] }))] }) }));
117
+ return { items, dialog };
94
118
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StockMutationHistoryCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockMutationHistoryCard.tsx"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAiDD,wBAAgB,wBAAwB,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,KAAK,+BAgPpF"}
1
+ {"version":3,"file":"StockMutationHistoryCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockMutationHistoryCard.tsx"],"names":[],"mappings":"AAcA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAiBD,wBAAgB,wBAAwB,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,KAAK,+BA2MpF"}
@@ -6,42 +6,12 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
6
6
  */
7
7
  import { useEffect, useState } from "react";
8
8
  import { dbFoutTekst } from "../../lib/db-error-message.js";
9
- import { Card, CardContent, Badge, Button } from "@flowselections/core";
9
+ import { Card, CardContent, Button } from "@flowselections/core";
10
+ import { mutatieSoort, redenTekst } from "../../lib/labels.js";
11
+ import { datum, getal } from "../../lib/notatie.js";
12
+ import { HoverTip } from "../fs-ui/HoverTip.js";
10
13
  import { ChevronDown, ChevronUp, Loader2, History } from "lucide-react";
11
14
  import { supabase } from "../../integrations/supabase/client.js";
12
- import { CollapsibleText } from "./CollapsibleText.js";
13
- const TYPE_LABEL = {
14
- consumption: { label: "Afboeking (verkoop)", tone: "bg-rose-100 text-rose-800 border-rose-200" },
15
- consumption_blocked: { label: "Afboeking geblokkeerd", tone: "bg-amber-100 text-amber-800 border-amber-200" },
16
- consumption_skipped: { label: "Afboeking overgeslagen", tone: "bg-amber-100 text-amber-800 border-amber-200" },
17
- reservation: { label: "Reservering", tone: "bg-blue-100 text-blue-800 border-blue-200" },
18
- reservation_release: { label: "Reservering vrijgegeven", tone: "bg-blue-100 text-blue-800 border-blue-200" },
19
- reservation_skipped: { label: "Reservering overgeslagen", tone: "bg-amber-100 text-amber-800 border-amber-200" },
20
- manual_writeoff: { label: "Afgeboekt (met reden)", tone: "bg-rose-100 text-rose-800 border-rose-200" },
21
- manual_correction: { label: "Handmatige correctie", tone: "bg-slate-100 text-slate-700 border-slate-200" },
22
- order_sync: { label: "Verwerking verkooporders", tone: "bg-indigo-100 text-indigo-800 border-indigo-200" },
23
- import: { label: "Import", tone: "bg-slate-100 text-slate-700 border-slate-200" },
24
- production: { label: "Productie", tone: "bg-emerald-100 text-emerald-800 border-emerald-200" },
25
- stock_update: { label: "Voorraad bijgewerkt", tone: "bg-slate-100 text-slate-700 border-slate-200" },
26
- new_article: { label: "Nieuw artikel", tone: "bg-emerald-100 text-emerald-800 border-emerald-200" },
27
- };
28
- function formatMoment(v) {
29
- try {
30
- const d = new Date(v);
31
- if (Number.isNaN(d.getTime()))
32
- return v;
33
- return d.toLocaleString("nl-NL", {
34
- day: "2-digit",
35
- month: "short",
36
- year: "numeric",
37
- hour: "2-digit",
38
- minute: "2-digit",
39
- });
40
- }
41
- catch {
42
- return v;
43
- }
44
- }
45
15
  export function StockMutationHistoryCard({ tradeItemKey, productId, sleutels }) {
46
16
  const [rows, setRows] = useState(null);
47
17
  const [error, setError] = useState(null);
@@ -142,17 +112,11 @@ export function StockMutationHistoryCard({ tradeItemKey, productId, sleutels })
142
112
  supabase.removeChannel(channel);
143
113
  };
144
114
  }, [tradeItemKey, productId, sleutels?.join("|")]); // eslint-disable-line react-hooks/exhaustive-deps
145
- return (_jsxs(Card, { children: [_jsxs("div", { className: "grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-3 px-6 py-4", children: [_jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-full border border-primary/40 bg-primary/10 text-primary", children: _jsx(History, { className: "h-4 w-4" }) }), _jsx("span", { className: "font-medium", children: "Afboekgeschiedenis" }), _jsx("span", { className: "text-xs text-muted-foreground tabular-nums", children: rows ? `${rows.length} mutatie${rows.length === 1 ? "" : "s"}` : "" })] }), _jsxs(CardContent, { className: "pt-0", children: [error && (_jsx("div", { className: "text-sm text-destructive", children: error })), !rows && !error && (_jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Mutaties laden\u2026"] })), rows && rows.length === 0 && !error && (_jsx("div", { className: "text-sm text-muted-foreground", children: "Nog geen voorraadmutaties voor dit artikel." })), rows && rows.length > 0 && (_jsxs("div", { className: "overflow-x-auto rounded-md border", children: [_jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-muted/50 text-xs uppercase text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "px-3 py-2 text-left", children: "Wanneer" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Soort" }), _jsx("th", { className: "px-3 py-2 text-right", children: "Aantal" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Van \u2192 naar" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Order" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Door" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Reden" })] }) }), _jsx("tbody", { children: (expanded ? rows : rows.slice(0, 5)).map((r) => {
146
- const meta = TYPE_LABEL[r.mutation_type] ?? {
147
- label: r.mutation_type || "Onbekend",
148
- tone: "bg-slate-100 text-slate-700 border-slate-200",
149
- };
150
- const physChanged = r.physical_before !== null &&
151
- r.physical_after !== null &&
152
- r.physical_before !== r.physical_after;
153
- const resChanged = r.reserved_before !== null &&
154
- r.reserved_after !== null &&
155
- r.reserved_before !== r.reserved_after;
156
- return (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "whitespace-nowrap px-3 py-2", children: formatMoment(r.created_at) }), _jsx("td", { className: "px-3 py-2", children: _jsx(Badge, { variant: "outline", className: `border ${meta.tone}`, children: meta.label }) }), _jsxs("td", { className: `px-3 py-2 text-right tabular-nums font-medium ${r.qty_delta < 0 ? "text-rose-700" : r.qty_delta > 0 ? "text-emerald-700" : ""}`, children: [r.qty_delta > 0 ? "+" : "", r.qty_delta] }), _jsxs("td", { className: "whitespace-nowrap px-3 py-2 tabular-nums text-muted-foreground", children: [physChanged && (_jsxs("div", { children: ["Liggend ", r.physical_before, " \u2192 ", r.physical_after] })), resChanged && (_jsxs("div", { children: ["Gereserveerd ", r.reserved_before, " \u2192 ", r.reserved_after] })), !physChanged && !resChanged && _jsx("span", { children: "\u2014" })] }), _jsx("td", { className: "whitespace-nowrap px-3 py-2", children: r.order_id ? (_jsx("a", { href: `/floriday-verkoop/verkooporders/${r.order_id}`, className: "text-primary hover:underline", children: r.order_number ?? "Order" })) : (_jsx("span", { className: "text-muted-foreground", children: "\u2014" })) }), _jsx("td", { className: "whitespace-nowrap px-3 py-2 text-muted-foreground", children: r.created_by_name ?? "Systeem" }), _jsx("td", { className: "px-3 py-2 text-muted-foreground", children: _jsx(CollapsibleText, { text: r.reason }) })] }, r.id));
115
+ return (_jsxs(Card, { children: [_jsxs("div", { className: "grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-3 px-6 py-4", children: [_jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-full border border-primary/40 bg-primary/10 text-primary", children: _jsx(History, { className: "h-4 w-4" }) }), _jsx("span", { className: "font-medium", children: "Afboekgeschiedenis" }), _jsx("span", { className: "text-xs text-muted-foreground tabular-nums", children: rows ? `${rows.length} wijziging${rows.length === 1 ? "" : "en"}` : "" })] }), _jsxs(CardContent, { className: "pt-0", children: [error && (_jsx("div", { className: "text-sm text-destructive", children: error })), !rows && !error && (_jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Mutaties laden\u2026"] })), rows && rows.length === 0 && !error && (_jsx("div", { className: "text-sm text-muted-foreground", children: "Nog geen voorraadmutaties voor dit artikel." })), rows && rows.length > 0 && (_jsxs("div", { className: "overflow-x-auto rounded-md border border-border", children: [_jsxs("table", { className: "w-full min-w-[900px] table-fixed text-sm [&_thead_th]:h-10 [&_thead_th]:px-2 [&_thead_th]:text-left [&_thead_th]:align-middle [&_thead_th]:text-[11px] [&_thead_th]:font-semibold [&_thead_th]:uppercase [&_thead_th]:tracking-wide [&_thead_th]:text-muted-foreground", children: [_jsxs("colgroup", { children: [_jsx("col", { style: { width: "132px" } }), _jsx("col", { style: { width: "184px" } }), _jsx("col", { style: { width: "104px" } }), _jsx("col", { style: { width: "184px" } }), _jsx("col", { style: { width: "112px" } }), _jsx("col", { style: { width: "132px" } }), _jsx("col", {})] }), _jsx("thead", { children: _jsxs("tr", { className: "border-b border-border", children: [_jsx("th", { children: "Wanneer" }), _jsx("th", { children: "Soort" }), _jsx("th", { children: "Aantal" }), _jsx("th", { children: "Van \u2192 naar" }), _jsx("th", { children: "Order" }), _jsx("th", { children: "Door" }), _jsx("th", { children: "Reden" })] }) }), _jsx("tbody", { children: (expanded ? rows : rows.slice(0, 5)).map((r) => {
116
+ const physChanged = r.physical_before !== null && r.physical_after !== null && r.physical_before !== r.physical_after;
117
+ const resChanged = r.reserved_before !== null && r.reserved_after !== null && r.reserved_before !== r.reserved_after;
118
+ const reden = redenTekst(r.reason);
119
+ const cel = "truncate px-2 py-0 align-middle";
120
+ return (_jsxs("tr", { className: "h-[60px] border-b border-border last:border-0", children: [_jsx("td", { className: cel + " tabular-nums", children: datum(r.created_at, true) }), _jsx("td", { className: cel, children: mutatieSoort(r.mutation_type) }), _jsxs("td", { className: cel + " tabular-nums " + (r.qty_delta < 0 ? "text-destructive" : r.qty_delta > 0 ? "text-primary" : "text-muted-foreground"), children: [r.qty_delta > 0 ? "+" : "", getal(r.qty_delta), " ", _jsx("span", { className: "text-xs text-muted-foreground", children: "stuks" })] }), _jsxs("td", { className: cel + " tabular-nums", children: [physChanged && _jsxs("div", { className: "truncate", children: ["Liggend ", getal(r.physical_before), " \u2192 ", getal(r.physical_after)] }), resChanged && _jsxs("div", { className: "truncate " + (physChanged ? "text-xs text-muted-foreground" : ""), children: ["Gereserveerd ", getal(r.reserved_before), " \u2192 ", getal(r.reserved_after)] }), !physChanged && !resChanged && _jsx("span", { className: "text-muted-foreground", children: "\u2014" })] }), _jsx("td", { className: cel, children: r.order_id ? (_jsx("a", { href: `/floriday-verkoop/verkooporders/${r.order_id}`, className: "text-primary hover:underline", children: r.order_number ?? "Order" })) : _jsx("span", { className: "text-muted-foreground", children: "\u2014" }) }), _jsx("td", { className: cel + " text-muted-foreground", children: r.created_by_name ?? "Systeem" }), _jsx("td", { className: cel + " text-muted-foreground", children: reden ? _jsx(HoverTip, { label: reden, content: _jsx("div", { className: "max-w-xs text-xs", children: reden }), align: "start", className: "block max-w-full truncate text-left", children: _jsx("span", { className: "truncate", children: reden }) }) : "—" })] }, r.id));
157
121
  }) })] }), rows.length > 5 && (_jsx("div", { className: "flex justify-center border-t bg-muted/20 px-3 py-2", children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setExpanded((current) => !current), className: "gap-1.5", children: expanded ? (_jsxs(_Fragment, { children: [_jsx(ChevronUp, { className: "h-4 w-4" }), " Inklappen"] })) : (_jsxs(_Fragment, { children: [_jsx(ChevronDown, { className: "h-4 w-4" }), " Meer tonen (", rows.length - 5, ")"] })) }) }))] }))] })] }));
158
122
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ValidationOverviewTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ValidationOverviewTable.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAoB3D,wBAAgB,uBAAuB,CAAC,EACtC,KAAK,EACL,YAAY,EACZ,SAAS,GACV,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,+BAwKA"}
1
+ {"version":3,"file":"ValidationOverviewTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ValidationOverviewTable.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAkB3D,wBAAgB,uBAAuB,CAAC,EACtC,KAAK,EACL,YAAY,EACZ,SAAS,GACV,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,+BA6IA"}
@@ -1,11 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useState } from "react";
3
3
  import { useNavigate } from "@tanstack/react-router";
4
- import { Badge, Button } from "@flowselections/core";
4
+ import { Button } from "@flowselections/core";
5
5
  import { Link2, Loader2, Pencil, Send } from "lucide-react";
6
6
  import { conceptMetArtikel, validateDraftForPublish } from "../../lib/floriday-import-validator.js";
7
- import { updateDraftMeta } from "../../hooks/useLocalTradeItems.js";
8
- import { floriday } from "../../lib/floriday-client.js";
9
7
  import { relinkProducts } from "../../lib/floriday-relink.js";
10
8
  import { toast } from "@flowselections/core";
11
9
  /**
@@ -52,51 +50,22 @@ export function ValidationOverviewTable({ items, connectionId, onChanged, }) {
52
50
  }
53
51
  return "Nog geen overeenkomend Floriday-artikel gevonden (streepjescode, artikelcode of naam)";
54
52
  };
55
- const publish = async (item) => {
56
- const productId = item.productId ?? item.localId;
57
- if (!productId || !connectionId)
58
- return;
59
- const payload = item.raw?.custom_fields?.floriday_payload ??
60
- item.raw?.floriday_payload ??
61
- item.raw?.data ??
62
- {};
63
- const v = validateDraftForPublish(conceptMetArtikel(payload, artikelVan(item)));
64
- if (!v.ok) {
65
- toast.error("Nog niet compleet: " + v.missing.join(", "));
66
- return;
67
- }
68
- try {
69
- const { buildAddTradeItemPayload } = await import("../../lib/floriday-payload.js");
70
- const built = buildAddTradeItemPayload(conceptMetArtikel(payload, artikelVan(item)));
71
- const res = await floriday.createTradeItem(connectionId, built);
72
- await updateDraftMeta(productId, {
73
- floridayLinkStatus: "published",
74
- floridayId: res?.tradeItemId ?? null,
75
- floridayLinkError: null,
76
- lastFloridaySyncAt: new Date().toISOString(),
77
- });
78
- toast.success("Artikel staat nu op Floriday");
79
- await onChanged();
80
- }
81
- catch (e) {
82
- console.warn(e);
83
- toast.error("Op Floriday zetten is niet gelukt. Probeer het later opnieuw.");
84
- await onChanged();
85
- }
86
- };
87
53
  const relinkButton = (_jsxs(Button, { size: "sm", variant: "outline", onClick: runRelink, disabled: relinking, children: [relinking ? (_jsx(Loader2, { className: "h-3 w-3 mr-1 animate-spin" })) : (_jsx(Link2, { className: "h-3 w-3 mr-1" })), "Nu opnieuw koppelen"] }));
88
54
  if (rows.length === 0) {
89
55
  return (_jsxs("div", { className: "p-8 text-center text-sm text-muted-foreground space-y-3", children: [_jsx("div", { children: "Alle artikelen staan op Floriday." }), _jsx("div", { className: "flex justify-center", children: relinkButton })] }));
90
56
  }
91
- return (_jsxs("div", { className: "overflow-x-auto", children: [_jsxs("div", { className: "flex items-center justify-between gap-2 p-3 border-b", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: "Koppelen gebeurt automatisch zodra Floriday-artikelen binnenkomen en elk uur op de achtergrond." }), relinkButton] }), _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-muted/40 text-left text-xs font-medium text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "p-3", children: "Artikelcode" }), _jsx("th", { className: "p-3", children: "Artikelnaam" }), _jsx("th", { className: "p-3", children: "Floriday-status" }), _jsx("th", { className: "p-3", children: "Reden" }), _jsx("th", { className: "p-3", children: "Ontbrekende Floriday-velden" }), _jsx("th", { className: "p-3 text-right", children: "Acties" })] }) }), _jsx("tbody", { children: rows.map((it) => {
57
+ return (_jsxs("div", { className: "overflow-x-auto", children: [_jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-border p-3", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: "Koppelen gebeurt automatisch zodra Floriday-artikelen binnenkomen en elk uur op de achtergrond." }), relinkButton] }), _jsxs("table", { className: "w-full min-w-[900px] table-fixed text-sm [&_thead_th]:h-10 [&_thead_th]:px-2 [&_thead_th]:text-left [&_thead_th]:align-middle [&_thead_th]:text-[11px] [&_thead_th]:font-semibold [&_thead_th]:uppercase [&_thead_th]:tracking-wide [&_thead_th]:text-muted-foreground [&_tbody_td]:h-[60px] [&_tbody_td]:truncate [&_tbody_td]:px-2 [&_tbody_td]:py-0 [&_tbody_td]:align-middle", children: [_jsxs("colgroup", { children: [_jsx("col", { style: { width: "120px" } }), _jsx("col", { style: { width: "220px" } }), _jsx("col", { style: { width: "160px" } }), _jsx("col", {}), _jsx("col", { style: { width: "220px" } }), _jsx("col", { style: { width: "260px" } })] }), _jsx("thead", { children: _jsxs("tr", { className: "border-b border-border", children: [_jsx("th", { children: "Artikelnummer" }), _jsx("th", { children: "Artikel" }), _jsx("th", { children: "Floriday" }), _jsx("th", { children: "Reden" }), _jsx("th", { children: "Nog nodig" }), _jsx("th", { children: _jsx("span", { className: "sr-only", children: "Acties" }) })] }) }), _jsx("tbody", { children: rows.map((it) => {
92
58
  const payload = it.raw?.custom_fields?.floriday_payload ??
93
59
  it.raw?.floriday_payload ??
94
60
  it.raw?.data ??
95
61
  {};
96
62
  const v = validateDraftForPublish(conceptMetArtikel(payload, artikelVan(it)));
97
- return (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "p-3 text-xs tabular-nums", children: it.articleNumber || "—" }), _jsx("td", { className: "p-3", children: it.name }), _jsx("td", { className: "p-3", children: _jsx(Badge, { variant: "outline", className: "rounded-full border-border bg-muted text-muted-foreground", children: "Niet actief op Floriday" }) }), _jsx("td", { className: "p-3 text-xs text-muted-foreground max-w-[260px]", children: reasonFor(it) }), _jsx("td", { className: "p-3", children: v.missing.length === 0 ? (_jsx("span", { className: "text-xs text-success-text", children: "Klaar om te activeren" })) : (_jsxs("span", { className: "text-xs text-muted-foreground", title: v.missing.join(", "), children: ["Nog nodig: ", v.missing.slice(0, 3).join(", ").toLowerCase(), v.missing.length > 3 ? ` en nog ${v.missing.length - 3} andere` : "", "."] })) }), _jsx("td", { className: "p-3", children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
63
+ return (_jsxs("tr", { className: "border-b border-border last:border-0 hover:bg-muted/40", children: [_jsx("td", { children: it.articleNumber || "—" }), _jsx("td", { children: it.name }), _jsx("td", { children: _jsx("span", { className: "text-muted-foreground", children: "Niet actief op Floriday" }) }), _jsx("td", { children: reasonFor(it) }), _jsx("td", { children: v.missing.length === 0 ? (_jsx("span", { className: "text-primary", children: "Klaar om te activeren" })) : (_jsxs("span", { className: "text-muted-foreground", title: v.missing.join(", "), children: [v.missing.slice(0, 2).join(", ").toLowerCase(), v.missing.length > 2 ? ` +${v.missing.length - 2}` : ""] })) }), _jsx("td", { children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
98
64
  const target = it.productId ?? it.localId ?? it.id;
99
65
  navigate({ to: "/voorraad/$id", params: { id: target } });
100
- }, children: [_jsx(Pencil, { className: "h-3 w-3 mr-1" }), "Bewerken"] }), _jsxs(Button, { size: "sm", onClick: () => publish(it), disabled: !v.ok, children: [_jsx(Send, { className: "h-3 w-3 mr-1" }), "Activeer op Floriday"] })] }) })] }, it.id));
66
+ }, children: [_jsx(Pencil, { className: "mr-1 h-3.5 w-3.5" }), "Bewerken"] }), _jsxs(Button, { size: "sm", disabled: !v.ok, onClick: () => {
67
+ const target = it.productId ?? it.localId ?? it.id;
68
+ navigate({ to: "/voorraad/$id", params: { id: target }, state: { stuurOverzicht: true } });
69
+ }, children: [_jsx(Send, { className: "mr-1 h-3.5 w-3.5" }), "Activeer op Floriday"] })] }) })] }, it.id));
101
70
  }) })] })] }));
102
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ValidationPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ValidationPage.tsx"],"names":[],"mappings":"AAiBA,oHAAoH;AACpH,wBAAgB,cAAc,gCA0C7B"}
1
+ {"version":3,"file":"ValidationPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ValidationPage.tsx"],"names":[],"mappings":"AAiBA,oHAAoH;AACpH,wBAAgB,cAAc,gCAuC7B"}
@@ -8,10 +8,10 @@ import { supabase } from "../../integrations/supabase/client.js";
8
8
  import { productToTradeItem } from "../../hooks/useLocalTradeItems.js";
9
9
  import { dbFoutTekst } from "../../lib/db-error-message.js";
10
10
  import { ValidationOverviewTable } from "./ValidationOverviewTable.js";
11
- import { VoorraadPagination } from "./VoorraadPagination.js";
11
+ import { Pagination } from "../fs-ui/Pagination.js";
12
+ import { NoticeBar } from "../fs-ui/NoticeBar.js";
12
13
  import { PageHeader } from "../fs-ui/PageHeader.js";
13
14
  import { UpdatedAt } from "../fs-ui/UpdatedAt.js";
14
- import { InlineAlert } from "../fs-ui/InlineAlert.js";
15
15
  const GROOTTE = 50;
16
16
  /** Floriday-controle: artikelen die nog niet op Floriday staan, per pagina van de server (geen limiet van 1000). */
17
17
  export function ValidationPage() {
@@ -37,5 +37,5 @@ export function ValidationPage() {
37
37
  setBijgewerkt(new Date());
38
38
  }, [pagina]);
39
39
  useEffect(() => { void reload(); }, [reload]);
40
- return (_jsxs("main", { className: "flex flex-col gap-4 p-4 pb-24 sm:p-6 sm:pb-24", children: [_jsx(PageHeader, { crumb: _jsxs(Link, { to: "/voorraad", className: "inline-flex items-center gap-1 hover:text-foreground", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), " Voorraad"] }), title: "Floriday-controle", updated: _jsx(UpdatedAt, { at: bijgewerkt }), meta: _jsxs("span", { children: ["Artikelen die nog niet op Floriday staan", loading ? "" : ` · ${totaal.toLocaleString("nl-NL")}`] }) }), fout && _jsx(InlineAlert, { tone: "fout", children: fout }), _jsx(Card, { className: "overflow-hidden rounded-xl shadow-sm", children: loading ? (_jsx("div", { className: "space-y-2 p-4", "aria-busy": "true", children: Array.from({ length: 8 }).map((_, i) => _jsx(Skeleton, { className: "h-10 w-full rounded-lg" }, i)) })) : (_jsx(ValidationOverviewTable, { items: items, connectionId: activeId, onChanged: reload })) }), totaal > GROOTTE && (_jsx(VoorraadPagination, { page: pagina, pageSize: GROOTTE, pageSizeOptions: [GROOTTE], total: totaal, onPageChange: setPagina, onPageSizeChange: () => undefined }))] }));
40
+ return (_jsxs("main", { className: "flex w-full min-w-0 flex-col gap-4 overflow-x-clip p-4 pb-[calc(7rem+env(safe-area-inset-bottom))] sm:p-6 sm:pb-24", children: [_jsx(PageHeader, { crumb: _jsxs(Link, { to: "/voorraad", className: "inline-flex items-center gap-1 hover:text-foreground", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), " Voorraad"] }), title: "Voorraadcontrole", updated: _jsx(UpdatedAt, { at: bijgewerkt, info: "Artikelen die nog niet op Floriday staan. Koppelen gebeurt automatisch zodra Floriday-artikelen binnenkomen." }) }), _jsx(NoticeBar, { items: fout ? [fout] : [] }), _jsx(Card, { className: "overflow-hidden rounded-xl shadow-sm", children: loading ? (_jsx("div", { className: "space-y-2 p-4", "aria-busy": "true", children: Array.from({ length: 8 }).map((_, i) => _jsx(Skeleton, { className: "h-10 w-full rounded-lg" }, i)) })) : (_jsx(ValidationOverviewTable, { items: items, connectionId: activeId, onChanged: reload })) }), _jsx(Pagination, { page: pagina, pageSize: GROOTTE, totalCount: totaal, onPage: setPagina })] }));
41
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AAuEA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAsDnD,wBAAgB,YAAY,gCA2N3B"}
1
+ {"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AA2EA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAsDnD,wBAAgB,YAAY,gCA+M3B"}
@@ -3,23 +3,22 @@ import { TwijfelKiezen } from "./artikel/TwijfelKiezen.js";
3
3
  import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from "react";
4
4
  import { useNavigate } from "@tanstack/react-router";
5
5
  import { Button, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@flowselections/core";
6
- import { AlertTriangle, Archive, ArrowDownToLine, ClipboardCheck, Columns3, Euro, HelpCircle, Layers, Link2Off, ListChecks, MoreHorizontal, Package, PackageSearch, PackageX, Plus, Send, TrendingDown, } from "lucide-react";
6
+ import { Archive, ArrowDownToLine, ClipboardCheck, Columns3, Euro, HelpCircle, Layers, Link2Off, ListChecks, MoreHorizontal, Package, PackageSearch, PackageX, Plus, Send, TrendingDown, } from "lucide-react";
7
7
  import { supabase } from "../../integrations/supabase/client.js";
8
8
  import { pageRequestGuard } from "../../lib/request-guard.js";
9
9
  import { useFloridayConnection } from "../../hooks/useFloridayConnection.js";
10
10
  import { useEnsureVoorraadDefaults } from "../../hooks/useEnsureVoorraadDefaults.js";
11
11
  import { useVoorraadLijst } from "../../hooks/useVoorraadLijst.js";
12
- import { aantal, FILTER_LABEL, meldingen, volgendeSortering, zichtbareFilters, } from "../../lib/voorraad-lijst.js";
13
- import { FloridayConnectionNotice } from "./FloridayConnectionNotice.js";
14
- import { StockIntegrityAlert } from "./StockIntegrityAlert.js";
12
+ import { aantal, FILTER_LABEL, FILTER_HINT, meldingen, volgendeSortering, zichtbareFilters, } from "../../lib/voorraad-lijst.js";
13
+ import { floridayConnectionNotice } from "./FloridayConnectionNotice.js";
14
+ import { useStockIntegrityNotices } from "./StockIntegrityAlert.js";
15
15
  import { TelmomentButton } from "./TelmomentButton.js";
16
- import { VoorraadPagination } from "./VoorraadPagination.js";
17
16
  import { InventorySettingsDrawer } from "./InventorySettingsDrawer.js";
18
17
  import { OPTIONELE_KOLOMMEN, VoorraadLijstTabel } from "./lijst/VoorraadLijstTabel.js";
19
18
  import { AanpassenDialog, AfboekenDialog } from "./lijst/SnelActieDialogen.js";
20
19
  import { LijstExportKnop } from "./lijst/LijstExportKnop.js";
21
20
  import { ImporteerKnop } from "./lijst/ImporteerKnop.js";
22
- import { Kbd, Sneltoetsen } from "./Sneltoetsen.js";
21
+ import { Sneltoetsen } from "./Sneltoetsen.js";
23
22
  import { PageHeader } from "../fs-ui/PageHeader.js";
24
23
  import { UpdatedAt } from "../fs-ui/UpdatedAt.js";
25
24
  import { KpiRow } from "../fs-ui/KpiRow.js";
@@ -27,7 +26,12 @@ import { KpiTile } from "../fs-ui/KpiTile.js";
27
26
  import { PillTabs } from "../fs-ui/PillTabs.js";
28
27
  import { Toolbar } from "../fs-ui/Toolbar.js";
29
28
  import { SearchInput } from "../fs-ui/SearchInput.js";
30
- import { InlineAlert } from "../fs-ui/InlineAlert.js";
29
+ import { NoticeBar } from "../fs-ui/NoticeBar.js";
30
+ import { FiltersButton } from "../fs-ui/FiltersButton.js";
31
+ import { FilterChips } from "../fs-ui/FilterChips.js";
32
+ import { FilterPanel, FilterGroup } from "../fs-ui/FilterPanel.js";
33
+ import { Pagination } from "../fs-ui/Pagination.js";
34
+ import { HeaderPrimary } from "../fs-ui/HeaderButton.js";
31
35
  import { EmptyState } from "../fs-ui/EmptyState.js";
32
36
  import { MobilePrimaryAction } from "../fs-ui/MobilePrimaryAction.js";
33
37
  import { DataTable } from "../fs-ui/DataTable.js";
@@ -98,6 +102,8 @@ export function VoorraadPage() {
98
102
  const [selected, setSelected] = useState(new Set());
99
103
  const [drawerOpen, setDrawerOpen] = useState(false);
100
104
  const [telmomentOpen, setTelmomentOpen] = useState(false);
105
+ const [filterOpen, setFilterOpen] = useState(false);
106
+ const integriteit = useStockIntegrityNotices();
101
107
  const [aanpassen, setAanpassen] = useState(null);
102
108
  const [afboeken, setAfboeken] = useState(null);
103
109
  const { kolommen, toggle: toggleKolom } = useKolommen();
@@ -113,7 +119,7 @@ export function VoorraadPage() {
113
119
  // Twijfelgevallen bestaan alleen bij een koppeling; tonen als er iets te kiezen is of als je er al staat.
114
120
  const tabs = filters
115
121
  .filter((f) => f !== "twijfel" || heeftKoppeling || (data?.tellers?.twijfel ?? 0) > 0 || filter === "twijfel")
116
- .map((f) => ({ value: f, label: FILTER_LABEL[f], icon: FILTER_ICON[f], count: data?.tellers?.[f] ?? null }));
122
+ .map((f) => ({ value: f, label: FILTER_LABEL[f], icon: FILTER_ICON[f], hint: FILTER_HINT[f], count: data?.tellers?.[f] ?? null }));
117
123
  const toggleSelect = (id) => setSelected((cur) => {
118
124
  const next = new Set(cur);
119
125
  if (next.has(id))
@@ -125,8 +131,20 @@ export function VoorraadPage() {
125
131
  const toggleAll = (ids) => setSelected((cur) => (ids.length > 0 && ids.every((id) => cur.has(id)) ? new Set() : new Set(ids)));
126
132
  const selectieBalk = selected.size > 0 && filter !== "twijfel";
127
133
  const kpiLaden = kpi === null;
128
- const leeg = zoek || filter !== "alles" ? (_jsx(EmptyState, { icon: _jsx(PackageSearch, { className: "h-6 w-6" }), title: "Niets gevonden", text: zoek ? `Geen artikelen voor “${zoek}”${filter !== "alles" ? ` in ${FILTER_LABEL[filter].toLowerCase()}` : ""}.` : "Geen artikelen in deze weergave.", action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => { setZoek(""); setFilter("alles"); }, children: "Filters wissen" }) })) : (_jsx(EmptyState, { icon: _jsx(Package, { className: "h-6 w-6" }), title: "Nog geen artikelen", text: "Maak je eerste artikel aan of importeer een lijst.", action: _jsxs(Button, { size: "sm", onClick: nieuw, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Nieuw artikel"] }) }));
129
- return (_jsxs("main", { className: "flex flex-col gap-4 p-4 pb-24 sm:p-6 sm:pb-24", children: [_jsx(Sneltoetsen, { onNieuw: nieuw }), _jsx(PageHeader, { title: "Voorraad", updated: _jsx(UpdatedAt, { at: data?.bijgewerkt ?? null }), actions: _jsxs(_Fragment, { children: [_jsx(ImporteerKnop, { connectionId: conn.activeId ?? null, onImported: reload }), _jsx(LijstExportKnop, { vraag: { zoek, filter, sort: sorteer.sort, oplopend: sorteer.oplopend } }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-9", "aria-label": "Meer acties", children: [_jsx(MoreHorizontal, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Meer" })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsxs(DropdownMenuItem, { onSelect: () => setTelmomentOpen(true), children: [_jsx(ClipboardCheck, { className: "mr-2 h-4 w-4" }), "Telmoment vastleggen"] }), heeftKoppeling && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: "/voorraad/validatie" }), children: [_jsx(ListChecks, { className: "mr-2 h-4 w-4" }), "Controle koppeling"] }), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: "/voorraad/publicaties" }), children: [_jsx(Send, { className: "mr-2 h-4 w-4" }), "Verzonden naar Floriday"] })] }))] })] }), _jsxs(Button, { size: "sm", className: "hidden h-9 md:inline-flex", onClick: nieuw, title: "Sneltoets N", children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Nieuw artikel", _jsx(Kbd, { children: "N" })] })] }) }), _jsx(TelmomentButton, { verbergKnop: true, open: telmomentOpen, onOpenChange: setTelmomentOpen, onSaved: reload }), _jsxs(KpiRow, { children: [_jsx(KpiTile, { title: "Artikelen", icon: _jsx(Package, {}), loading: kpiLaden, value: aantal(kpi?.artikelen ?? 0), sub: "Actief, zonder gearchiveerd", onClick: () => setFilter("alles"), active: filter === "alles" }), _jsx(KpiTile, { title: "Onder minimum", icon: _jsx(TrendingDown, {}), tone: (kpi?.onder_minimum ?? 0) > 0 ? "warning" : "default", loading: kpiLaden, value: aantal(kpi?.onder_minimum ?? 0), sub: (kpi?.onder_minimum ?? 0) > 0 ? _jsx("span", { className: "text-destructive", children: "Bijbestellen of bijmaken" }) : "Alles boven het minimum", onClick: () => setFilter("onder_minimum"), active: filter === "onder_minimum" }), _jsx(KpiTile, { title: "Vrij beschikbaar", icon: _jsx(Layers, {}), loading: kpiLaden, value: aantal(kpi?.vrij ?? 0), sub: "Stuks, losse artikelen" }), _jsx(KpiTile, { title: "Inkomend", icon: _jsx(ArrowDownToLine, {}), loading: kpiLaden, value: aantal(kpi?.inkomend ?? 0), sub: "Stuks verwacht" })] }), guardTrips.length > 0 && (_jsx(InlineAlert, { tone: "fout", action: _jsx(Button, { size: "sm", variant: "outline", onClick: () => window.location.reload(), children: "Opnieuw laden" }), children: "De pagina is gestopt met laden. Laad de pagina opnieuw." })), _jsx(StockIntegrityAlert, {}), _jsx(FloridayConnectionNotice, { status: conn.status, environment: conn.selectedEnvironment, error: conn.error }), error && (_jsx(InlineAlert, { tone: "fout", action: _jsx(Button, { size: "sm", variant: "outline", onClick: () => void reload(), children: "Opnieuw proberen" }), children: "De voorraad laden lukt niet. Probeer opnieuw." })), melding.length > 0 && (_jsx(InlineAlert, { tone: "let_op", icon: _jsx(AlertTriangle, {}), children: _jsx("span", { className: "flex flex-wrap gap-x-4 gap-y-1", children: melding.map((m) => m.filter ? (_jsx("button", { type: "button", className: "underline-offset-2 hover:underline", onClick: () => setFilter(m.filter), children: m.tekst }, m.tekst)) : (_jsx("span", { children: m.tekst }, m.tekst))) }) })), _jsx(PillTabs, { tabs: tabs, value: filter, onChange: setFilter, label: "Filter" }), _jsx(Toolbar, { right: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-9", "aria-label": "Kolommen kiezen", children: [_jsx(Columns3, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Kolommen" })] }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuLabel, { children: "Kolommen kiezen" }), OPTIONELE_KOLOMMEN.map((c) => (_jsx(DropdownMenuCheckboxItem, { checked: kolommen.has(c.key), onCheckedChange: () => toggleKolom(c.key), children: c.label }, c.key)))] })] }), children: _jsx(SearchInput, { value: zoek, onChange: setZoek, placeholder: "Zoek op naam, artikelnummer of barcode\u2026" }) }), selectieBalk && (_jsxs("div", { className: "sticky top-2 z-20 flex flex-wrap items-center gap-2 rounded-lg border border-border bg-card px-4 py-2 text-sm shadow-lg", children: [_jsxs("span", { className: "font-medium tabular-nums", children: [selected.size, " gekozen"] }), _jsx(Button, { size: "sm", className: "h-8", onClick: () => setDrawerOpen(true), children: "Voorraadsturing instellen" }), _jsx(Button, { size: "sm", variant: "ghost", className: "h-8", onClick: () => setSelected(new Set()), children: "Keuze wissen" })] })), filter === "twijfel" ? (_jsx(TwijfelTabel, { rijen: data?.twijfel_rijen ?? [], loading: loading, onGekozen: () => void reload() })) : (_jsx(VoorraadLijstTabel, { rijen: data?.rijen ?? [], loading: loading, sort: sorteer.sort, oplopend: sorteer.oplopend, onSort: (k) => setSorteer((cur) => volgendeSortering(cur, k)), kolommen: kolommen, selected: selected, onToggleSelect: toggleSelect, onToggleAll: toggleAll, onAanpassen: setAanpassen, onAfboeken: setAfboeken, heeftKoppeling: heeftKoppeling, leeg: leeg })), _jsx(VoorraadPagination, { total: data?.totaal ?? 0, page: pagina, pageSize: grootte, onPageChange: setPagina, onPageSizeChange: setGrootte }), _jsx(AanpassenDialog, { rij: aanpassen, onClose: () => setAanpassen(null), onDone: reload }), _jsx(AfboekenDialog, { rij: afboeken, connectionId: stockConnId, onClose: () => setAfboeken(null), onDone: reload }), _jsx(InventorySettingsDrawer, { open: drawerOpen, onOpenChange: setDrawerOpen, connectionId: conn.activeId ?? null, productIds: [...selected], onSaved: reload }), _jsx(MobilePrimaryAction, { onClick: nieuw, hidden: selectieBalk, icon: _jsx(Plus, {}), children: "Nieuw artikel" })] }));
134
+ // Meldingen: één regel per melding, direct onder de kop.
135
+ const verbindingTekst = floridayConnectionNotice(conn.status, conn.error);
136
+ const noticeItems = [
137
+ ...(guardTrips.length > 0 ? [_jsxs("span", { children: ["De pagina is gestopt met laden. ", _jsx("span", { role: "button", tabIndex: 0, className: "font-medium underline underline-offset-2", onClick: () => window.location.reload(), children: "Opnieuw laden" })] }, "guard")] : []),
138
+ ...(error ? [_jsxs("span", { children: ["De voorraad laden lukt niet. ", _jsx("span", { role: "button", tabIndex: 0, className: "font-medium underline underline-offset-2", onClick: (e) => { e.stopPropagation(); void reload(); }, children: "Opnieuw proberen" })] }, "err")] : []),
139
+ ...integriteit.items,
140
+ ...(verbindingTekst ? [verbindingTekst] : []),
141
+ ...melding.map((m) => m.actie === "telmoment" ? (_jsxs("span", { className: "inline-flex min-w-0 max-w-full items-center gap-2", children: [_jsx("span", { className: "truncate", children: m.tekst }), _jsx("span", { role: "button", tabIndex: 0, className: "shrink-0 font-medium underline underline-offset-2", onClick: (e) => { e.stopPropagation(); setTelmomentOpen(true); }, onKeyDown: (e) => { if (e.key === "Enter") {
142
+ e.stopPropagation();
143
+ setTelmomentOpen(true);
144
+ } }, children: "Telmoment instellen" })] }, m.tekst)) : m.filter ? (_jsx("span", { role: "button", tabIndex: 0, className: "underline-offset-2 hover:underline", onClick: (e) => { e.stopPropagation(); setFilter(m.filter); }, children: m.tekst }, m.tekst)) : m.tekst),
145
+ ];
146
+ const leeg = zoek || filter !== "alles" ? (_jsx(EmptyState, { icon: _jsx(PackageSearch, { className: "h-6 w-6" }), title: "Niets gevonden", text: zoek ? `Geen artikelen voor “${zoek}”${filter !== "alles" ? ` in ${FILTER_HINT[filter].toLowerCase()}` : ""}.` : "Geen artikelen in deze weergave.", action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => { setZoek(""); setFilter("alles"); }, children: "Filters wissen" }) })) : (_jsx(EmptyState, { icon: _jsx(Package, { className: "h-6 w-6" }), title: "Nog geen artikelen", text: "Maak je eerste artikel aan of importeer een lijst.", action: _jsxs(Button, { size: "sm", onClick: nieuw, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Nieuw artikel"] }) }));
147
+ return (_jsxs("main", { className: "flex w-full min-w-0 flex-col gap-4 overflow-x-clip p-4 pb-[calc(7rem+env(safe-area-inset-bottom))] sm:p-6 sm:pb-24", children: [_jsx(Sneltoetsen, { onNieuw: nieuw }), _jsx(PageHeader, { title: "Voorraad", updated: _jsx(UpdatedAt, { at: data?.bijgewerkt ?? null }), actions: _jsxs(_Fragment, { children: [_jsx(ImporteerKnop, { connectionId: conn.activeId ?? null, onImported: reload }), _jsx(LijstExportKnop, { vraag: { zoek, filter, sort: sorteer.sort, oplopend: sorteer.oplopend } }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-10 w-10 p-0 sm:h-9 sm:w-auto sm:px-3", "aria-label": "Meer acties", children: [_jsx(MoreHorizontal, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Meer" })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsxs(DropdownMenuItem, { onSelect: () => setTelmomentOpen(true), children: [_jsx(ClipboardCheck, { className: "mr-2 h-4 w-4" }), "Telmoment vastleggen"] }), heeftKoppeling && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: "/voorraad/validatie" }), children: [_jsx(ListChecks, { className: "mr-2 h-4 w-4" }), "Controle koppeling"] }), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: "/voorraad/publicaties" }), children: [_jsx(Send, { className: "mr-2 h-4 w-4" }), "Verzonden naar Floriday"] })] }))] })] }), _jsx(HeaderPrimary, { icon: _jsx(Plus, {}), label: "Nieuw artikel", kbd: "N", onClick: nieuw })] }) }), _jsx(TelmomentButton, { verbergKnop: true, open: telmomentOpen, onOpenChange: setTelmomentOpen, onSaved: reload }), _jsx(NoticeBar, { items: noticeItems }), integriteit.dialog, _jsxs(KpiRow, { children: [_jsx(KpiTile, { title: "Artikelen", icon: _jsx(Package, {}), loading: kpiLaden, value: aantal(kpi?.artikelen ?? 0), sub: "Actief, zonder gearchiveerd", onClick: () => setFilter("alles"), active: false }), _jsx(KpiTile, { title: "Onder minimum", icon: _jsx(TrendingDown, {}), tone: (kpi?.onder_minimum ?? 0) > 0 ? "warning" : "default", loading: kpiLaden, value: aantal(kpi?.onder_minimum ?? 0), sub: (kpi?.onder_minimum ?? 0) > 0 ? _jsx("span", { className: "text-destructive", children: "Bijbestellen of bijmaken" }) : "Alles boven het minimum", onClick: () => setFilter("onder_minimum"), active: filter === "onder_minimum" }), _jsx(KpiTile, { title: "Vrij beschikbaar", icon: _jsx(Layers, {}), loading: kpiLaden, value: aantal(kpi?.vrij ?? 0), sub: "Stuks, losse artikelen" }), _jsx(KpiTile, { title: "Inkomend", icon: _jsx(ArrowDownToLine, {}), loading: kpiLaden, value: aantal(kpi?.inkomend ?? 0), sub: "Stuks verwacht" })] }), _jsx(PillTabs, { tabs: tabs, value: filter, onChange: setFilter, label: "Filter" }), _jsx(Toolbar, { filters: _jsx(FiltersButton, { count: filter !== "alles" ? 1 : 0, onClick: () => setFilterOpen(true) }), chips: _jsx(FilterChips, { chips: filter !== "alles" ? [{ key: "weergave", label: FILTER_HINT[filter], icon: FILTER_ICON[filter], onRemove: () => setFilter("alles") }] : [] }), right: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-9 px-3", "aria-label": "Kolommen kiezen", children: [_jsx(Columns3, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Kolommen" })] }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuLabel, { children: "Kolommen kiezen" }), OPTIONELE_KOLOMMEN.map((c) => (_jsx(DropdownMenuCheckboxItem, { checked: kolommen.has(c.key), onCheckedChange: () => toggleKolom(c.key), children: c.label }, c.key)))] })] }), children: _jsx(SearchInput, { value: zoek, onChange: setZoek, placeholder: "Zoek op naam, artikelnummer of barcode" }) }), selectieBalk && (_jsxs("div", { className: "sticky top-2 z-20 flex flex-wrap items-center gap-2 rounded-lg border border-border bg-card px-4 py-2 text-sm shadow-lg", children: [_jsxs("span", { className: "font-medium tabular-nums", children: [selected.size, " gekozen"] }), _jsx(Button, { size: "sm", className: "h-8", onClick: () => setDrawerOpen(true), children: "Voorraadsturing instellen" }), _jsx(Button, { size: "sm", variant: "ghost", className: "h-8", onClick: () => setSelected(new Set()), children: "Keuze wissen" })] })), filter === "twijfel" ? (_jsx(TwijfelTabel, { rijen: data?.twijfel_rijen ?? [], loading: loading, onGekozen: () => void reload() })) : (_jsx(VoorraadLijstTabel, { rijen: data?.rijen ?? [], loading: loading, sort: sorteer.sort, oplopend: sorteer.oplopend, onSort: (k) => setSorteer((cur) => volgendeSortering(cur, k)), kolommen: kolommen, selected: selected, onToggleSelect: toggleSelect, onToggleAll: toggleAll, onAanpassen: setAanpassen, onAfboeken: setAfboeken, heeftKoppeling: heeftKoppeling, leeg: leeg })), _jsx(Pagination, { totalCount: data?.totaal ?? 0, page: pagina, pageSize: grootte, onPage: setPagina, onPageSize: setGrootte }), _jsx(FilterPanel, { open: filterOpen, onOpenChange: setFilterOpen, onClear: () => setFilter("alles"), children: _jsx(FilterGroup, { title: "Weergave", value: filter, onChange: setFilter, options: tabs.map((t) => ({ value: t.value, label: FILTER_HINT[t.value] })) }) }), _jsx(AanpassenDialog, { rij: aanpassen, onClose: () => setAanpassen(null), onDone: reload }), _jsx(AfboekenDialog, { rij: afboeken, connectionId: stockConnId, onClose: () => setAfboeken(null), onDone: reload }), _jsx(InventorySettingsDrawer, { open: drawerOpen, onOpenChange: setDrawerOpen, connectionId: conn.activeId ?? null, productIds: [...selected], onSaved: reload }), _jsx(MobilePrimaryAction, { onClick: nieuw, hidden: selectieBalk, icon: _jsx(Plus, {}), children: "Nieuw artikel" })] }));
130
148
  }
131
149
  function TwijfelTabel({ rijen, loading, onGekozen }) {
132
150
  const [open, setOpen] = useState(null);
@@ -1 +1 @@
1
- {"version":3,"file":"ArtikelPagina.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/artikel/ArtikelPagina.tsx"],"names":[],"mappings":"AAkGA,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,+BAoenI"}
1
+ {"version":3,"file":"ArtikelPagina.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/artikel/ArtikelPagina.tsx"],"names":[],"mappings":"AAmGA,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,+BA6enI"}