@flowselections/floriday-voorraad 1.0.150 → 1.0.154

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 (141) hide show
  1. package/dist-lib/components/fs-ui/DataTable.d.ts +42 -0
  2. package/dist-lib/components/fs-ui/DataTable.d.ts.map +1 -0
  3. package/dist-lib/components/fs-ui/DataTable.js +68 -0
  4. package/dist-lib/components/fs-ui/EmptyState.d.ts +9 -0
  5. package/dist-lib/components/fs-ui/EmptyState.d.ts.map +1 -0
  6. package/dist-lib/components/fs-ui/EmptyState.js +5 -0
  7. package/dist-lib/components/fs-ui/FilterChips.d.ts +13 -0
  8. package/dist-lib/components/fs-ui/FilterChips.d.ts.map +1 -0
  9. package/dist-lib/components/fs-ui/FilterChips.js +8 -0
  10. package/dist-lib/components/fs-ui/FilterPanel.d.ts +19 -0
  11. package/dist-lib/components/fs-ui/FilterPanel.d.ts.map +1 -0
  12. package/dist-lib/components/fs-ui/FilterPanel.js +10 -0
  13. package/dist-lib/components/fs-ui/FiltersButton.d.ts +6 -0
  14. package/dist-lib/components/fs-ui/FiltersButton.d.ts.map +1 -0
  15. package/dist-lib/components/fs-ui/FiltersButton.js +7 -0
  16. package/dist-lib/components/fs-ui/HeaderButton.d.ts +16 -0
  17. package/dist-lib/components/fs-ui/HeaderButton.d.ts.map +1 -0
  18. package/dist-lib/components/fs-ui/HeaderButton.js +10 -0
  19. package/dist-lib/components/fs-ui/HoverTip.d.ts +15 -0
  20. package/dist-lib/components/fs-ui/HoverTip.d.ts.map +1 -0
  21. package/dist-lib/components/fs-ui/HoverTip.js +24 -0
  22. package/dist-lib/components/fs-ui/InlineAlert.d.ts +12 -0
  23. package/dist-lib/components/fs-ui/InlineAlert.d.ts.map +1 -0
  24. package/dist-lib/components/fs-ui/InlineAlert.js +15 -0
  25. package/dist-lib/components/fs-ui/KpiRow.d.ts +10 -0
  26. package/dist-lib/components/fs-ui/KpiRow.d.ts.map +1 -0
  27. package/dist-lib/components/fs-ui/KpiRow.js +8 -0
  28. package/dist-lib/components/fs-ui/KpiTile.d.ts +21 -0
  29. package/dist-lib/components/fs-ui/KpiTile.d.ts.map +1 -0
  30. package/dist-lib/components/fs-ui/KpiTile.js +40 -0
  31. package/dist-lib/components/fs-ui/MobilePrimaryAction.d.ts +13 -0
  32. package/dist-lib/components/fs-ui/MobilePrimaryAction.d.ts.map +1 -0
  33. package/dist-lib/components/fs-ui/MobilePrimaryAction.js +10 -0
  34. package/dist-lib/components/fs-ui/NoticeBar.d.ts +10 -0
  35. package/dist-lib/components/fs-ui/NoticeBar.d.ts.map +1 -0
  36. package/dist-lib/components/fs-ui/NoticeBar.js +16 -0
  37. package/dist-lib/components/fs-ui/PageHeader.d.ts +19 -0
  38. package/dist-lib/components/fs-ui/PageHeader.d.ts.map +1 -0
  39. package/dist-lib/components/fs-ui/PageHeader.js +9 -0
  40. package/dist-lib/components/fs-ui/Pagination.d.ts +10 -0
  41. package/dist-lib/components/fs-ui/Pagination.d.ts.map +1 -0
  42. package/dist-lib/components/fs-ui/Pagination.js +10 -0
  43. package/dist-lib/components/fs-ui/PillTabs.d.ts +17 -0
  44. package/dist-lib/components/fs-ui/PillTabs.d.ts.map +1 -0
  45. package/dist-lib/components/fs-ui/PillTabs.js +28 -0
  46. package/dist-lib/components/fs-ui/RowMenu.d.ts +13 -0
  47. package/dist-lib/components/fs-ui/RowMenu.d.ts.map +1 -0
  48. package/dist-lib/components/fs-ui/RowMenu.js +7 -0
  49. package/dist-lib/components/fs-ui/SearchInput.d.ts +11 -0
  50. package/dist-lib/components/fs-ui/SearchInput.d.ts.map +1 -0
  51. package/dist-lib/components/fs-ui/SearchInput.js +55 -0
  52. package/dist-lib/components/fs-ui/ShortcutHelp.d.ts +8 -0
  53. package/dist-lib/components/fs-ui/ShortcutHelp.d.ts.map +1 -0
  54. package/dist-lib/components/fs-ui/ShortcutHelp.js +6 -0
  55. package/dist-lib/components/fs-ui/StatusIcon.d.ts +13 -0
  56. package/dist-lib/components/fs-ui/StatusIcon.d.ts.map +1 -0
  57. package/dist-lib/components/fs-ui/StatusIcon.js +15 -0
  58. package/dist-lib/components/fs-ui/TableSkeleton.d.ts +7 -0
  59. package/dist-lib/components/fs-ui/TableSkeleton.d.ts.map +1 -0
  60. package/dist-lib/components/fs-ui/TableSkeleton.js +6 -0
  61. package/dist-lib/components/fs-ui/Toolbar.d.ts +12 -0
  62. package/dist-lib/components/fs-ui/Toolbar.d.ts.map +1 -0
  63. package/dist-lib/components/fs-ui/Toolbar.js +8 -0
  64. package/dist-lib/components/fs-ui/UpdatedAt.d.ts +10 -0
  65. package/dist-lib/components/fs-ui/UpdatedAt.d.ts.map +1 -0
  66. package/dist-lib/components/fs-ui/UpdatedAt.js +18 -0
  67. package/dist-lib/components/voorraad/ArtikelCompositionCard.d.ts.map +1 -1
  68. package/dist-lib/components/voorraad/ArtikelCompositionCard.js +46 -15
  69. package/dist-lib/components/voorraad/ArtikelWizard.js +4 -4
  70. package/dist-lib/components/voorraad/FloridayConnectionNotice.d.ts +7 -6
  71. package/dist-lib/components/voorraad/FloridayConnectionNotice.d.ts.map +1 -1
  72. package/dist-lib/components/voorraad/FloridayConnectionNotice.js +15 -12
  73. package/dist-lib/components/voorraad/FustenPage.d.ts.map +1 -1
  74. package/dist-lib/components/voorraad/FustenPage.js +92 -26
  75. package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts.map +1 -1
  76. package/dist-lib/components/voorraad/NieuwArtikelPage.js +2 -1
  77. package/dist-lib/components/voorraad/OrderHistoryCard.d.ts +3 -1
  78. package/dist-lib/components/voorraad/OrderHistoryCard.d.ts.map +1 -1
  79. package/dist-lib/components/voorraad/OrderHistoryCard.js +26 -50
  80. package/dist-lib/components/voorraad/PublicatiesPage.d.ts.map +1 -1
  81. package/dist-lib/components/voorraad/PublicatiesPage.js +42 -36
  82. package/dist-lib/components/voorraad/Sneltoetsen.d.ts +14 -0
  83. package/dist-lib/components/voorraad/Sneltoetsen.d.ts.map +1 -0
  84. package/dist-lib/components/voorraad/Sneltoetsen.js +44 -0
  85. package/dist-lib/components/voorraad/StockIntegrityAlert.d.ts +42 -1
  86. package/dist-lib/components/voorraad/StockIntegrityAlert.d.ts.map +1 -1
  87. package/dist-lib/components/voorraad/StockIntegrityAlert.js +38 -7
  88. package/dist-lib/components/voorraad/StockMutationHistoryCard.d.ts.map +1 -1
  89. package/dist-lib/components/voorraad/StockMutationHistoryCard.js +10 -46
  90. package/dist-lib/components/voorraad/StockPushMonitor.js +2 -2
  91. package/dist-lib/components/voorraad/TelmomentButton.d.ts +5 -1
  92. package/dist-lib/components/voorraad/TelmomentButton.d.ts.map +1 -1
  93. package/dist-lib/components/voorraad/TelmomentButton.js +13 -6
  94. package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts.map +1 -1
  95. package/dist-lib/components/voorraad/ValidationOverviewTable.js +11 -40
  96. package/dist-lib/components/voorraad/ValidationPage.d.ts +1 -0
  97. package/dist-lib/components/voorraad/ValidationPage.d.ts.map +1 -1
  98. package/dist-lib/components/voorraad/ValidationPage.js +33 -5
  99. package/dist-lib/components/voorraad/VoorraadBeheerCard.d.ts +4 -1
  100. package/dist-lib/components/voorraad/VoorraadBeheerCard.d.ts.map +1 -1
  101. package/dist-lib/components/voorraad/VoorraadBeheerCard.js +26 -5
  102. package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
  103. package/dist-lib/components/voorraad/VoorraadPage.js +67 -38
  104. package/dist-lib/components/voorraad/VoorraadSturingCard.js +1 -1
  105. package/dist-lib/components/voorraad/artikel/ArtikelPagina.d.ts.map +1 -1
  106. package/dist-lib/components/voorraad/artikel/ArtikelPagina.js +42 -19
  107. package/dist-lib/components/voorraad/lijst/ImporteerKnop.d.ts.map +1 -1
  108. package/dist-lib/components/voorraad/lijst/ImporteerKnop.js +1 -1
  109. package/dist-lib/components/voorraad/lijst/LijstExportKnop.d.ts.map +1 -1
  110. package/dist-lib/components/voorraad/lijst/LijstExportKnop.js +1 -1
  111. package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.d.ts +8 -2
  112. package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.d.ts.map +1 -1
  113. package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.js +62 -27
  114. package/dist-lib/hooks/useLocalTradeItems.d.ts +14 -0
  115. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
  116. package/dist-lib/hooks/useLocalTradeItems.js +5 -3
  117. package/dist-lib/hooks/useTradeItemStock.d.ts.map +1 -1
  118. package/dist-lib/hooks/useTradeItemStock.js +6 -3
  119. package/dist-lib/hooks/useVoorraadData.d.ts.map +1 -1
  120. package/dist-lib/hooks/useVoorraadData.js +16 -8
  121. package/dist-lib/hooks/useVoorraadLijst.d.ts +10 -0
  122. package/dist-lib/hooks/useVoorraadLijst.d.ts.map +1 -1
  123. package/dist-lib/hooks/useVoorraadLijst.js +22 -4
  124. package/dist-lib/integrations/supabase/types.d.ts +85 -0
  125. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  126. package/dist-lib/lib/alle-rijen.d.ts +15 -0
  127. package/dist-lib/lib/alle-rijen.d.ts.map +1 -0
  128. package/dist-lib/lib/alle-rijen.js +17 -0
  129. package/dist-lib/lib/db-error-message.d.ts.map +1 -1
  130. package/dist-lib/lib/db-error-message.js +3 -1
  131. package/dist-lib/lib/labels.d.ts +42 -0
  132. package/dist-lib/lib/labels.d.ts.map +1 -0
  133. package/dist-lib/lib/labels.js +152 -0
  134. package/dist-lib/lib/notatie.d.ts +4 -0
  135. package/dist-lib/lib/notatie.d.ts.map +1 -0
  136. package/dist-lib/lib/notatie.js +18 -0
  137. package/dist-lib/lib/voorraad-lijst.d.ts +2 -0
  138. package/dist-lib/lib/voorraad-lijst.d.ts.map +1 -1
  139. package/dist-lib/lib/voorraad-lijst.js +14 -3
  140. package/package.json +2 -1
  141. package/sql/floriday-voorraad-schema.sql +315 -39
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PillTabs.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/PillTabs.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEhE,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAChD,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,EACzC,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,KAAkB,GACnB,EAAE;IACD,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACnB,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,+BAwDA"}
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useLayoutEffect, useRef } from "react";
3
+ /** StatusTabs exact naar Verkooporders: altijd één regel, scrollt horizontaal met vervaging. */
4
+ export function PillTabs({ tabs, value, onChange, label = "Weergave", }) {
5
+ const listRef = useRef(null);
6
+ useLayoutEffect(() => {
7
+ const measure = () => {
8
+ const list = listRef.current;
9
+ const el = list?.querySelector(`[data-tab="${value}"]`);
10
+ if (el && list && (el.offsetLeft < list.scrollLeft || el.offsetLeft + el.offsetWidth > list.scrollLeft + list.clientWidth)) {
11
+ list.scrollLeft = el.offsetLeft - 8;
12
+ }
13
+ };
14
+ measure();
15
+ window.addEventListener("resize", measure);
16
+ return () => window.removeEventListener("resize", measure);
17
+ }, [value]);
18
+ return (_jsx("div", { className: "shrink-0", children: _jsx("div", { ref: listRef, role: "tablist", "aria-label": label, className: "relative -mx-4 flex items-center gap-2 overflow-x-auto px-4 pb-1 [scrollbar-width:none] [mask-image:linear-gradient(to_right,black_85%,transparent)] [&::-webkit-scrollbar]:hidden sm:mx-0 sm:px-0 sm:[mask-image:none]", children: tabs.map((t) => {
19
+ const active = t.value === value;
20
+ return (_jsxs("button", { "data-tab": t.value, type: "button", role: "tab", "aria-selected": active, onClick: () => onChange(t.value), title: t.hint, style: { transitionProperty: "color, background-color, border-color", transitionDuration: "150ms" }, className: "relative flex h-9 shrink-0 items-center gap-2 whitespace-nowrap rounded-lg border px-3 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&_svg]:h-4 [&_svg]:w-4 [&_svg]:shrink-0 " +
21
+ (active
22
+ ? "border-primary/30 bg-primary/10 font-semibold text-foreground"
23
+ : t.count === 0
24
+ ? "border-border bg-card text-muted-foreground/70 hover:text-foreground"
25
+ : "border-border bg-card text-foreground/80 hover:bg-muted hover:text-foreground"), children: [t.icon, _jsx("span", { children: t.label }), t.count !== undefined && (_jsx("span", { className: "inline-flex h-5 min-w-5 items-center justify-center rounded-full px-1.5 text-[11px] font-semibold tabular-nums " +
26
+ (active ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"), children: t.count === null ? "…" : t.count.toLocaleString("nl-NL") }))] }, t.value));
27
+ }) }) }));
28
+ }
@@ -0,0 +1,13 @@
1
+ export interface RowMenuItem {
2
+ label: string;
3
+ onClick: () => void;
4
+ disabled?: boolean;
5
+ title?: string;
6
+ destructive?: boolean;
7
+ }
8
+ /** Rijmenu exact naar Verkooporders; de acties komen van de pagina. */
9
+ export declare function RowMenu({ label, items }: {
10
+ label: string;
11
+ items: RowMenuItem[];
12
+ }): import("react").JSX.Element;
13
+ //# sourceMappingURL=RowMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RowMenu.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/RowMenu.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,uEAAuE;AACvE,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,EAAE,CAAA;CAAE,+BAyBhF"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { MoreVertical } from "lucide-react";
3
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@flowselections/core";
4
+ /** Rijmenu exact naar Verkooporders; de acties komen van de pagina. */
5
+ export function RowMenu({ label, items }) {
6
+ return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { "aria-label": `Acties voor ${label}`, onClick: (e) => e.stopPropagation(), className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: _jsx(MoreVertical, { className: "h-4 w-4" }) }), _jsx(DropdownMenuContent, { align: "end", onClick: (e) => e.stopPropagation(), children: items.map((it) => (_jsx(DropdownMenuItem, { disabled: it.disabled, title: it.title, onClick: () => !it.disabled && it.onClick(), className: it.destructive ? "text-destructive focus:text-destructive" : undefined, children: it.label }, it.label))) })] }));
7
+ }
@@ -0,0 +1,11 @@
1
+ /** True als de gebruiker in een invoerveld typt (sneltoetsen doen dan niets). */
2
+ export declare function isTypen(t: EventTarget | null): boolean;
3
+ /** Zoekveld exact naar Verkooporders: h-9 (mobiel h-10), sm:w-80, breder bij focus; "/" focust, Esc wist. */
4
+ export declare function SearchInput({ value, onChange, placeholder, label, delay, }: {
5
+ value: string;
6
+ onChange: (v: string) => void;
7
+ placeholder?: string;
8
+ label?: string;
9
+ delay?: number;
10
+ }): import("react").JSX.Element;
11
+ //# sourceMappingURL=SearchInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchInput.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/SearchInput.tsx"],"names":[],"mappings":"AAGA,iFAAiF;AACjF,wBAAgB,OAAO,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAItD;AAED,6GAA6G;AAC7G,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,WAAsB,EACtB,KAAgB,EAChB,KAAW,GACZ,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,+BA4EA"}
@@ -0,0 +1,55 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Search, X } from "lucide-react";
4
+ /** True als de gebruiker in een invoerveld typt (sneltoetsen doen dan niets). */
5
+ export function isTypen(t) {
6
+ const el = t;
7
+ if (!el)
8
+ return false;
9
+ return el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT" || el.isContentEditable;
10
+ }
11
+ /** Zoekveld exact naar Verkooporders: h-9 (mobiel h-10), sm:w-80, breder bij focus; "/" focust, Esc wist. */
12
+ export function SearchInput({ value, onChange, placeholder = "Zoeken", label = "Zoeken", delay = 250, }) {
13
+ const [search, setSearch] = useState(value);
14
+ const inputRef = useRef(null);
15
+ const laatst = useRef(value);
16
+ useEffect(() => {
17
+ if (value !== laatst.current) {
18
+ laatst.current = value;
19
+ setSearch(value);
20
+ }
21
+ }, [value]);
22
+ useEffect(() => {
23
+ if (search === laatst.current)
24
+ return;
25
+ const t = setTimeout(() => { laatst.current = search; onChange(search); }, delay);
26
+ return () => clearTimeout(t);
27
+ }, [search, delay, onChange]);
28
+ useEffect(() => {
29
+ const h = (e) => {
30
+ if (e.key === "/" && !e.metaKey && !e.ctrlKey && !e.altKey && !isTypen(e.target)) {
31
+ e.preventDefault();
32
+ inputRef.current?.focus();
33
+ }
34
+ };
35
+ window.addEventListener("keydown", h);
36
+ return () => window.removeEventListener("keydown", h);
37
+ }, []);
38
+ const clearSearch = () => { setSearch(""); laatst.current = ""; onChange(""); inputRef.current?.focus(); };
39
+ return (_jsxs("div", { className: "group relative flex h-10 sm:h-9 w-full items-center overflow-hidden rounded-md border border-border bg-card " +
40
+ "transition-[box-shadow,border-color,width] duration-[180ms] ease-out motion-reduce:transition-none " +
41
+ "focus-within:border-primary focus-within:ring-[3px] focus-within:ring-ring/20 " +
42
+ "sm:w-80 sm:focus-within:w-[400px]", children: [_jsx(Search, { className: "ml-3 h-4 w-4 shrink-0 text-muted-foreground transition-colors duration-[120ms] group-focus-within:text-primary", "aria-hidden": true }), _jsx("input", { ref: inputRef, type: "search", placeholder: placeholder, "aria-label": label, value: search, maxLength: 100, autoComplete: "off", spellCheck: false, onChange: (e) => setSearch(e.target.value), onKeyDown: (e) => {
43
+ if (e.key === "Escape") {
44
+ if (search) {
45
+ e.preventDefault();
46
+ e.stopPropagation();
47
+ clearSearch();
48
+ }
49
+ else
50
+ inputRef.current?.blur();
51
+ }
52
+ }, className: "h-full min-w-0 flex-1 appearance-none border-0 bg-transparent px-2 text-base sm:text-sm text-foreground outline-none ring-0 shadow-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-muted-foreground [&::-webkit-search-cancel-button]:hidden" }), _jsxs("span", { className: "relative mr-1.5 flex h-7 w-7 shrink-0 items-center justify-center", children: [_jsx("kbd", { className: "pointer-events-none absolute rounded border border-border px-1.5 font-mono text-[11px] leading-5 text-muted-foreground transition-opacity duration-[120ms] " +
53
+ (search ? "opacity-0" : "opacity-100 group-focus-within:opacity-0"), "aria-hidden": true, children: "/" }), _jsx("button", { type: "button", onClick: clearSearch, tabIndex: search ? 0 : -1, "aria-label": "Zoekopdracht wissen", className: "absolute inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground transition-[opacity,transform,background-color] duration-[120ms] ease-out hover:bg-muted hover:text-foreground " +
54
+ (search ? "scale-100 opacity-100" : "pointer-events-none scale-90 opacity-0"), children: _jsx(X, { className: "h-4 w-4" }) })] })] }));
55
+ }
@@ -0,0 +1,8 @@
1
+ export type Shortcut = [string[], string];
2
+ /** Sneltoetsenoverzicht exact naar Verkooporders; de lijst komt van de pagina. */
3
+ export declare function ShortcutHelp({ open, onOpenChange, shortcuts }: {
4
+ open: boolean;
5
+ onOpenChange: (o: boolean) => void;
6
+ shortcuts: Shortcut[];
7
+ }): import("react").JSX.Element;
8
+ //# sourceMappingURL=ShortcutHelp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShortcutHelp.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/ShortcutHelp.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;AAE1C,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAAC,SAAS,EAAE,QAAQ,EAAE,CAAA;CAAE,+BAwB3I"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@flowselections/core";
3
+ /** Sneltoetsenoverzicht exact naar Verkooporders; de lijst komt van de pagina. */
4
+ export function ShortcutHelp({ open, onOpenChange, shortcuts }) {
5
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-w-sm", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Sneltoetsen" }) }), _jsx("ul", { className: "divide-y divide-border text-sm", children: shortcuts.map(([keys, label]) => (_jsxs("li", { className: "flex items-center justify-between py-2", children: [_jsx("span", { className: "text-foreground", children: label }), _jsx("span", { className: "flex gap-1", children: keys.map((k) => (_jsx("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-[11px] text-muted-foreground", children: k }, k))) })] }, label))) })] }) }));
6
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from "react";
2
+ export type StatusTone = "klaar" | "open" | "bezig" | "fout";
3
+ /**
4
+ * Klein rond statusicoon met tooltip: groen klaar, grijs open, oker bezig, rood fout.
5
+ * Geen gekleurde vlakjes eromheen. Het label is de toegankelijke naam.
6
+ */
7
+ export declare function StatusIcon({ tone, icon, label, detail }: {
8
+ tone: StatusTone;
9
+ icon: ReactNode;
10
+ label: string;
11
+ detail?: ReactNode;
12
+ }): import("react").JSX.Element;
13
+ //# sourceMappingURL=StatusIcon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusIcon.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/StatusIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAS7D;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,+BAejI"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { HoverTip } from "./HoverTip.js";
3
+ const TONE = {
4
+ klaar: "text-primary",
5
+ open: "text-muted-foreground",
6
+ bezig: "text-warning-soft-foreground",
7
+ fout: "text-destructive",
8
+ };
9
+ /**
10
+ * Klein rond statusicoon met tooltip: groen klaar, grijs open, oker bezig, rood fout.
11
+ * Geen gekleurde vlakjes eromheen. Het label is de toegankelijke naam.
12
+ */
13
+ export function StatusIcon({ tone, icon, label, detail }) {
14
+ return (_jsx(HoverTip, { label: label, className: "h-6 w-6 [&_svg]:h-4 [&_svg]:w-4 " + TONE[tone], content: _jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "text-[13px] font-semibold text-foreground", children: label }), detail && _jsx("div", { className: "text-muted-foreground", children: detail })] }), children: icon }));
15
+ }
@@ -0,0 +1,7 @@
1
+ /** Skeletrijen in de echte vorm van de tabel (60 px hoog, zelfde kolombreedtes). */
2
+ export declare function TableSkeleton({ columns, rows, media }: {
3
+ columns: Array<string | undefined>;
4
+ rows?: number;
5
+ media?: boolean;
6
+ }): import("react").JSX.Element;
7
+ //# sourceMappingURL=TableSkeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TableSkeleton.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/TableSkeleton.tsx"],"names":[],"mappings":"AAEA,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,IAAQ,EAAE,KAAY,EAAE,EAAE;IAAE,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,+BAwBxI"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Skeleton } from "@flowselections/core";
3
+ /** Skeletrijen in de echte vorm van de tabel (60 px hoog, zelfde kolombreedtes). */
4
+ export function TableSkeleton({ columns, rows = 8, media = true }) {
5
+ return (_jsx(_Fragment, { children: Array.from({ length: rows }).map((_, r) => (_jsx("tr", { className: "h-[60px] border-b border-border last:border-0", "aria-hidden": true, children: columns.map((w, c) => (_jsx("td", { className: "px-3", style: w ? { width: w } : undefined, children: c === 0 && media ? (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "h-9 w-9 rounded-lg" }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Skeleton, { className: "h-3.5 w-40" }), _jsx(Skeleton, { className: "h-3 w-24" })] })] })) : (_jsx(Skeleton, { className: "h-3.5 w-14" })) }, c))) }, r))) }));
6
+ }
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from "react";
2
+ /**
3
+ * Werkbalk exact naar Verkooporders: zoekveld, direct rechts "Filters", dan de
4
+ * actieve chips op dezelfde regel; uiterst rechts alleen "Kolommen".
5
+ */
6
+ export declare function Toolbar({ children, filters, chips, right }: {
7
+ children?: ReactNode;
8
+ filters?: ReactNode;
9
+ chips?: ReactNode;
10
+ right?: ReactNode;
11
+ }): import("react").JSX.Element;
12
+ //# sourceMappingURL=Toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/Toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;GAGG;AACH,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,+BAS/I"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Werkbalk exact naar Verkooporders: zoekveld, direct rechts "Filters", dan de
4
+ * actieve chips op dezelfde regel; uiterst rechts alleen "Kolommen".
5
+ */
6
+ export function Toolbar({ children, filters, chips, right }) {
7
+ return (_jsxs("div", { className: "shrink-0 flex flex-wrap items-center gap-2", children: [_jsx("div", { className: "min-w-0 flex-1 sm:flex-none", children: children }), filters, chips, right && _jsx("div", { className: "ml-auto hidden items-center gap-2 md:flex", children: right })] }));
8
+ }
@@ -0,0 +1,10 @@
1
+ import type { ReactNode } from "react";
2
+ /** "Bijgewerkt hh:mm" met klokicoon (12 px tekst); extra uitleg alleen in de infoballon. */
3
+ export declare function UpdatedAt({ at, prefix, info, stale, }: {
4
+ at: string | Date | null | undefined;
5
+ prefix?: string;
6
+ /** Extra informatie, alleen zichtbaar in de infoballon. */
7
+ info?: ReactNode;
8
+ stale?: boolean;
9
+ }): import("react").JSX.Element | null;
10
+ //# sourceMappingURL=UpdatedAt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpdatedAt.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/UpdatedAt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,4FAA4F;AAC5F,wBAAgB,SAAS,CAAC,EACxB,EAAE,EACF,MAAqB,EACrB,IAAI,EACJ,KAAK,GACN,EAAE;IACD,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,sCAgBA"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Clock } from "lucide-react";
3
+ import { HoverTip } from "./HoverTip.js";
4
+ /** "Bijgewerkt hh:mm" met klokicoon (12 px tekst); extra uitleg alleen in de infoballon. */
5
+ export function UpdatedAt({ at, prefix = "Bijgewerkt", info, stale, }) {
6
+ let tekst = "Laden…";
7
+ if (at) {
8
+ const d = typeof at === "string" ? new Date(at) : at;
9
+ if (Number.isNaN(d.getTime()))
10
+ return null;
11
+ const t = d.toLocaleTimeString("nl-NL", { hour: "2-digit", minute: "2-digit" });
12
+ tekst = stale ? `Niet bijgewerkt sinds ${t}` : `${prefix} ${t}`;
13
+ }
14
+ const inhoud = (_jsxs("span", { className: "inline-flex items-center gap-1 tabular-nums " + (stale ? "text-warning" : ""), children: [_jsx(Clock, { className: "h-3.5 w-3.5", "aria-hidden": true }), tekst] }));
15
+ if (!info)
16
+ return inhoud;
17
+ return _jsx(HoverTip, { label: tekst, content: _jsx("div", { className: "max-w-xs text-xs", children: info }), align: "start", children: inhoud });
18
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"ArtikelCompositionCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ArtikelCompositionCard.tsx"],"names":[],"mappings":"AAMA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAkHD,wBAAgB,sBAAsB,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,KAAK,sCA6RtE"}
1
+ {"version":3,"file":"ArtikelCompositionCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ArtikelCompositionCard.tsx"],"names":[],"mappings":"AAOA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAkHD,wBAAgB,sBAAsB,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,KAAK,sCA0TtE"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useState } from "react";
3
- import { toast } from "sonner";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { useOpslagDeelnemer } from "./artikel/opslaan-context.js";
4
+ import { dbFoutTekst } from "../../lib/db-error-message.js";
4
5
  import { Card, CardContent, CardDescription, CardHeader, CardTitle, Badge } from "@flowselections/core";
5
6
  import { ArrowDown, ArrowUp, Loader2, Package } from "lucide-react";
6
7
  import { supabase } from "../../integrations/supabase/client.js";
@@ -89,7 +90,12 @@ export function ArtikelCompositionCard({ productId, floridayId }) {
89
90
  const [loading, setLoading] = useState(true);
90
91
  const [sections, setSections] = useState([]);
91
92
  const [reloadTick, setReloadTick] = useState(0);
92
- const [savingOrder, setSavingOrder] = useState(false);
93
+ const [savingOrder] = useState(false);
94
+ // Volgorde van de groepsleden bij openen (D1): pas bij "Opslaan" bewaard, met controle tegen deze stand.
95
+ const [volgordeBij, setVolgordeBij] = useState(null);
96
+ const volgordeBijRef = useRef(null);
97
+ volgordeBijRef.current = volgordeBij;
98
+ const lokaleVolgorde = useRef(null);
93
99
  useEffect(() => {
94
100
  let cancelled = false;
95
101
  (async () => {
@@ -218,6 +224,20 @@ export function ArtikelCompositionCard({ productId, floridayId }) {
218
224
  });
219
225
  }
220
226
  if (!cancelled) {
227
+ const grp = out.find((x) => x.kind === "productgroep");
228
+ const nieuwIds = grp ? grp.rows.map((r) => r.key) : null;
229
+ const lokaal = lokaleVolgorde.current;
230
+ const vuilNu = lokaal && volgordeBijRef.current && lokaal.join("|") !== volgordeBijRef.current.join("|");
231
+ if (grp && vuilNu) {
232
+ // Niet-opgeslagen volgorde houden; nieuwe leden achteraan.
233
+ const pos = new Map(lokaal.map((id, i) => [id, i]));
234
+ grp.rows = [...grp.rows].sort((a, b) => (pos.get(a.key) ?? 1e9) - (pos.get(b.key) ?? 1e9));
235
+ lokaleVolgorde.current = grp.rows.map((r) => r.key);
236
+ }
237
+ else {
238
+ setVolgordeBij(nieuwIds);
239
+ lokaleVolgorde.current = nieuwIds;
240
+ }
221
241
  setSections(out);
222
242
  setLoading(false);
223
243
  }
@@ -238,32 +258,43 @@ export function ArtikelCompositionCard({ productId, floridayId }) {
238
258
  supabase.removeChannel(channel);
239
259
  };
240
260
  }, [groupId]);
241
- const move = useCallback(async (index, dir) => {
261
+ const move = useCallback((index, dir) => {
242
262
  const sec = sections.find((x) => x.kind === "productgroep");
243
263
  if (!sec)
244
264
  return;
245
265
  const target = index + dir;
246
266
  if (target < 0 || target >= sec.rows.length)
247
267
  return;
248
- const prev = sections;
249
268
  const rows = [...sec.rows];
250
269
  [rows[index], rows[target]] = [rows[target], rows[index]];
270
+ lokaleVolgorde.current = rows.map((r) => r.key);
251
271
  setSections(sections.map((x) => (x === sec ? { ...x, rows } : x)));
252
- setSavingOrder(true);
253
- const results = await Promise.all(rows.map((r, i) => supabase.from("product_group_items").update({ sort_order: i }).eq("id", r.key)));
254
- setSavingOrder(false);
255
- const failed = results.find((r) => r.error);
256
- if (failed?.error) {
257
- setSections(prev);
258
- toast.error(`Volgorde opslaan mislukt: ${failed.error.message}`);
259
- }
260
272
  }, [sections]);
273
+ const huidigeVolgorde = sections.find((x) => x.kind === "productgroep")?.rows.map((r) => r.key) ?? null;
274
+ const volgordeVuil = Boolean(groupId && volgordeBij && huidigeVolgorde && huidigeVolgorde.join("|") !== volgordeBij.join("|"));
275
+ useOpslagDeelnemer("groepsvolgorde", volgordeVuil, async () => {
276
+ if (!groupId || !volgordeBij || !huidigeVolgorde)
277
+ return { ok: true };
278
+ const { data, error } = await supabase.rpc("voorraad_groep_volgorde_opslaan", { p_group_id: groupId, p_oud: volgordeBij, p_nieuw: huidigeVolgorde });
279
+ if (error)
280
+ return { ok: false, melding: dbFoutTekst(error, "Opslaan") };
281
+ const r = data;
282
+ if (!r.ok) {
283
+ // Conflict: de volgorde van de ander overnemen en opnieuw laten kiezen.
284
+ lokaleVolgorde.current = null;
285
+ setReloadTick((t) => t + 1);
286
+ return { ok: false, melding: r.melding ?? "Iemand anders heeft de volgorde intussen gewijzigd. Er is niets opgeslagen." };
287
+ }
288
+ setVolgordeBij(huidigeVolgorde);
289
+ lokaleVolgorde.current = huidigeVolgorde;
290
+ return { ok: true };
291
+ });
261
292
  if (loading) {
262
293
  return (_jsx(Card, { children: _jsxs(CardContent, { className: "flex items-center gap-2 py-4 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Samenstelling laden\u2026"] }) }));
263
294
  }
264
295
  if (sections.length === 0)
265
296
  return null;
266
297
  return (_jsx(_Fragment, { children: sections.map((s) => (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(CardTitle, { children: s.title }), _jsx(Badge, { className: s.kind === "productgroep"
267
- ? "bg-indigo-500/15 text-indigo-700 border-indigo-500/30"
268
- : "bg-emerald-500/15 text-emerald-700 border-emerald-500/30", children: s.kind === "productgroep" ? "Productgroep" : "Samenstelling" })] }), _jsx(CardDescription, { children: s.description })] }), _jsx(CardContent, { children: s.rows.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground py-4 text-center", children: "Nog geen onderdelen toegevoegd." })) : (_jsx("ul", { className: "divide-y", children: s.rows.map((r, idx) => (_jsxs("li", { className: "flex items-center gap-3 py-2", children: [s.kind === "productgroep" && (_jsxs("div", { className: "flex flex-col shrink-0", children: [_jsx("button", { type: "button", "aria-label": "Omhoog", disabled: idx === 0 || savingOrder, onClick: () => move(idx, -1), className: "p-0.5 text-muted-foreground hover:text-foreground disabled:opacity-30", children: _jsx(ArrowUp, { className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", "aria-label": "Omlaag", disabled: idx === s.rows.length - 1 || savingOrder, onClick: () => move(idx, 1), className: "p-0.5 text-muted-foreground hover:text-foreground disabled:opacity-30", children: _jsx(ArrowDown, { className: "h-3.5 w-3.5" }) })] })), _jsx("div", { className: "h-8 w-8 rounded bg-muted flex items-center justify-center shrink-0", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-sm truncate", children: r.name }), r.code && (_jsx("div", { className: "text-xs text-muted-foreground truncate", children: r.code })), r.detail && (_jsx("div", { className: "text-xs text-muted-foreground truncate", children: r.detail }))] }), s.kind === "productgroep" && (_jsx("div", { className: "text-right shrink-0 w-40", children: r.stock ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "text-sm font-medium tabular-nums", children: ["Beschikbaar: ", r.stock.available] }), _jsxs("div", { className: "text-xs text-muted-foreground tabular-nums", children: ["fysiek ", r.stock.physical, " \u00B7 gereserveerd ", r.stock.reserved] })] })) : (_jsx("div", { className: "text-xs text-muted-foreground", children: "Nog geen voorraad" })) })), r.quantity !== undefined && r.quantity !== null && (_jsxs("div", { className: "text-sm tabular-nums text-muted-foreground shrink-0", title: s.kind === "productgroep" ? "Aantal in groep" : undefined, children: [r.quantity, r.unit ? ` ${r.unit}` : ""] }))] }, r.key))) })) })] }, s.kind))) }));
298
+ ? "rounded-full border-border bg-muted text-muted-foreground"
299
+ : "rounded-full border-primary/30 bg-primary/10 text-primary", children: s.kind === "productgroep" ? "Productgroep" : "Samenstelling" })] }), _jsxs(CardDescription, { children: [s.description, s.kind === "productgroep" && volgordeVuil && _jsx("span", { className: "ml-2 font-medium text-warning-soft-foreground", children: "\u00B7 Volgorde nog niet opgeslagen" })] })] }), _jsx(CardContent, { children: s.rows.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground py-4 text-center", children: "Nog geen onderdelen toegevoegd." })) : (_jsx("ul", { className: "divide-y", children: s.rows.map((r, idx) => (_jsxs("li", { className: "flex items-center gap-3 py-2", children: [s.kind === "productgroep" && (_jsxs("div", { className: "flex flex-col shrink-0", children: [_jsx("button", { type: "button", "aria-label": "Omhoog", disabled: idx === 0 || savingOrder, onClick: () => move(idx, -1), className: "p-0.5 text-muted-foreground hover:text-foreground disabled:opacity-30", children: _jsx(ArrowUp, { className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", "aria-label": "Omlaag", disabled: idx === s.rows.length - 1 || savingOrder, onClick: () => move(idx, 1), className: "p-0.5 text-muted-foreground hover:text-foreground disabled:opacity-30", children: _jsx(ArrowDown, { className: "h-3.5 w-3.5" }) })] })), _jsx("div", { className: "h-8 w-8 rounded bg-muted flex items-center justify-center shrink-0", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-sm truncate", children: r.name }), r.code && (_jsx("div", { className: "text-xs text-muted-foreground truncate", children: r.code })), r.detail && (_jsx("div", { className: "text-xs text-muted-foreground truncate", children: r.detail }))] }), s.kind === "productgroep" && (_jsx("div", { className: "text-right shrink-0 w-40", children: r.stock ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "text-sm font-medium tabular-nums", children: ["Beschikbaar: ", r.stock.available] }), _jsxs("div", { className: "text-xs text-muted-foreground tabular-nums", children: ["fysiek ", r.stock.physical, " \u00B7 gereserveerd ", r.stock.reserved] })] })) : (_jsx("div", { className: "text-xs text-muted-foreground", children: "Nog geen voorraad" })) })), r.quantity !== undefined && r.quantity !== null && (_jsxs("div", { className: "text-sm tabular-nums text-muted-foreground shrink-0", title: s.kind === "productgroep" ? "Aantal in groep" : undefined, children: [r.quantity, r.unit ? ` ${r.unit}` : ""] }))] }, r.key))) })) })] }, s.kind))) }));
269
300
  }
@@ -634,7 +634,7 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
634
634
  return;
635
635
  }
636
636
  if (!row) {
637
- toast.error("Artikel niet gevonden in de cache");
637
+ toast.error("Artikel niet gevonden bij de Floriday-artikelen");
638
638
  return;
639
639
  }
640
640
  // Lokale rij met nog niet doorgegeven wijzigingen? Die is leidend.
@@ -916,7 +916,7 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
916
916
  if (hasRegulatoryLookup && regulatoryQuery.isLoading) {
917
917
  return {
918
918
  ok: false,
919
- errors: ["Verplichte Floricode-karakteristieken worden nog geladen"],
919
+ errors: ["Verplichte kenmerken worden nog geladen"],
920
920
  };
921
921
  }
922
922
  if (hasRegulatoryLookup && regulatoryQuery.isError) {
@@ -1852,7 +1852,7 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
1852
1852
  const payload = buildUpdateTradeItemPayload(snapshot);
1853
1853
  const res = await floriday.updateTradeItem(activeId, pushTargetId, payload);
1854
1854
  if (!res?.attemptId) {
1855
- throw new Error("Gateway gaf geen attemptId terug");
1855
+ throw new Error("Floriday gaf geen bevestiging terug");
1856
1856
  }
1857
1857
  // Geen eigen kopie in floriday_trade_items_cache: Floriday-auth vult die.
1858
1858
  if (localId) {
@@ -2916,7 +2916,7 @@ function PackingConfigDialog({ open, onOpenChange, initial, isFirst, packagingTy
2916
2916
  packagingSupplierId: v,
2917
2917
  packagingSupplierName: sup?.name,
2918
2918
  }));
2919
- }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Kies leverancier..." }) }), _jsx(SelectContent, { children: PACKAGING_SUPPLIERS.map((s) => (_jsx(SelectItem, { value: s.id, children: s.name }, s.id))) })] }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Floricode VRS-materiaal UUID (optioneel)" }), _jsx(Input, { value: draft.packagingMaterialId ?? "", onChange: (e) => patch("packagingMaterialId", e.target.value.trim()), placeholder: "00000000-0000-0000-0000-000000000000", className: materialInvalid ? "border-destructive" : "" }), materialInvalid ? (_jsx("p", { className: "text-xs text-destructive", children: "Deze code klopt niet. Laat het veld leeg of kopieer de materiaalcode uit Floricode." })) : (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Wanneer ingevuld gaat het als ", _jsx("code", { children: "customPackageId" }), "naar Floriday en vervangt het de VBN-fust."] }))] })] }), hasCustomPkg && (_jsx("div", { className: "rounded-md border border-primary/30 bg-primary/5 px-3 py-2 text-xs", children: "Eigen verpakking gekozen; het VBN-fust hieronder wordt niet naar Floriday gestuurd." }))] })), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: hasCustomPkg
2919
+ }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Kies leverancier..." }) }), _jsx(SelectContent, { children: PACKAGING_SUPPLIERS.map((s) => (_jsx(SelectItem, { value: s.id, children: s.name }, s.id))) })] }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Materiaalcode (optioneel)" }), _jsx(Input, { value: draft.packagingMaterialId ?? "", onChange: (e) => patch("packagingMaterialId", e.target.value.trim()), placeholder: "00000000-0000-0000-0000-000000000000", className: materialInvalid ? "border-destructive" : "" }), materialInvalid ? (_jsx("p", { className: "text-xs text-destructive", children: "Deze code klopt niet. Laat het veld leeg of kopieer de materiaalcode uit Floricode." })) : (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Wanneer ingevuld gaat het als ", _jsx("code", { children: "customPackageId" }), "naar Floriday en vervangt het de VBN-fust."] }))] })] }), hasCustomPkg && (_jsx("div", { className: "rounded-md border border-primary/30 bg-primary/5 px-3 py-2 text-xs", children: "Eigen verpakking gekozen; het VBN-fust hieronder wordt niet naar Floriday gestuurd." }))] })), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: hasCustomPkg
2920
2920
  ? "VBN-fust (genegeerd — custom package actief)"
2921
2921
  : draft.source === "SUPPLIER"
2922
2922
  ? "Fallback VBN-fust"
@@ -1,12 +1,13 @@
1
- import { type ConnectionStatus } from "../../lib/stock-scope.js";
1
+ import type { ConnectionStatus } from "../../lib/stock-scope.js";
2
2
  /**
3
- * Meldt in gewone taal waarom Floriday-acties ontbreken. Geen link: de route
4
- * naar de Floriday-koppeling hoort bij de Shell/Floriday-auth en is hier niet
5
- * aantoonbaar bekend.
3
+ * Werkpagina's tonen geen uitnodiging om een koppeling in te stellen (dat hoort bij Instellingen).
4
+ * Alleen als een bestaande koppeling niet geladen kan worden: één rustige meldingsregel.
5
+ * De technische reden gaat naar de console.
6
6
  */
7
- export declare function FloridayConnectionNotice({ status, environment, error, }: {
7
+ export declare function floridayConnectionNotice(status: ConnectionStatus, error: string | null): string | null;
8
+ export declare function FloridayConnectionNotice({ status, error, }: {
8
9
  status: ConnectionStatus;
9
- environment: string | null;
10
+ environment?: string | null;
10
11
  error: string | null;
11
12
  }): import("react").JSX.Element | null;
12
13
  //# sourceMappingURL=FloridayConnectionNotice.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FloridayConnectionNotice.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FloridayConnectionNotice.tsx"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEhF;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,MAAM,EACN,WAAW,EACX,KAAK,GACN,EAAE;IACD,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,sCAsBA"}
1
+ {"version":3,"file":"FloridayConnectionNotice.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FloridayConnectionNotice.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAItG;AAED,wBAAgB,wBAAwB,CAAC,EACvC,MAAM,EACN,KAAK,GACN,EAAE;IACD,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,sCAMA"}
@@ -1,16 +1,19 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { AlertTriangle } from "lucide-react";
3
- import { noConnectionText } from "../../lib/stock-scope.js";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
4
2
  /**
5
- * Meldt in gewone taal waarom Floriday-acties ontbreken. Geen link: de route
6
- * naar de Floriday-koppeling hoort bij de Shell/Floriday-auth en is hier niet
7
- * aantoonbaar bekend.
3
+ * Werkpagina's tonen geen uitnodiging om een koppeling in te stellen (dat hoort bij Instellingen).
4
+ * Alleen als een bestaande koppeling niet geladen kan worden: één rustige meldingsregel.
5
+ * De technische reden gaat naar de console.
8
6
  */
9
- export function FloridayConnectionNotice({ status, environment, error, }) {
10
- if (status === "fout") {
11
- return (_jsxs("div", { role: "alert", className: "flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Floriday-koppeling laden mislukt \u2013 alleen eigen artikelen mogelijk." }), _jsxs("p", { className: "mt-1 break-words", children: ["Melding: ", error] })] })] }));
12
- }
13
- if (status !== "geen_koppeling")
7
+ export function floridayConnectionNotice(status, error) {
8
+ if (status !== "fout")
14
9
  return null;
15
- return (_jsxs("div", { role: "status", className: "flex items-start gap-2 rounded-md border border-amber-500/30 bg-amber-500/10 p-3 text-sm text-amber-800", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: noConnectionText(environment) }), _jsx("p", { className: "mt-1", children: "Een Floriday-koppeling kies je bij de Floriday-instellingen van de Shell." })] })] }));
10
+ if (error)
11
+ console.warn("Floriday-koppeling laden mislukt:", error);
12
+ return "De koppeling met Floriday kon niet geladen worden. Je eigen artikelen werken gewoon; probeer het later opnieuw.";
13
+ }
14
+ export function FloridayConnectionNotice({ status, error, }) {
15
+ const t = floridayConnectionNotice(status, error);
16
+ if (!t)
17
+ return null;
18
+ return (_jsx("div", { role: "status", className: "shrink-0 rounded-lg border border-border bg-warning-soft px-3 py-2 text-sm text-warning-soft-foreground", children: t }));
16
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FustenPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FustenPage.tsx"],"names":[],"mappings":"AAmLA,wBAAgB,UAAU,gCA0PzB"}
1
+ {"version":3,"file":"FustenPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FustenPage.tsx"],"names":[],"mappings":"AAmMA,wBAAgB,UAAU,gCAiNzB"}