@flowselections/floriday-klanten-module 1.0.25 → 1.0.27

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 (96) hide show
  1. package/dist-lib/components/klanten/BewerkKlantRoute.d.ts +4 -1
  2. package/dist-lib/components/klanten/BewerkKlantRoute.d.ts.map +1 -1
  3. package/dist-lib/components/klanten/BewerkKlantRoute.js +7 -4
  4. package/dist-lib/components/klanten/ChannelBadges.d.ts +11 -0
  5. package/dist-lib/components/klanten/ChannelBadges.d.ts.map +1 -0
  6. package/dist-lib/components/klanten/ChannelBadges.js +21 -0
  7. package/dist-lib/components/klanten/DeliveryLocationsTab.d.ts.map +1 -1
  8. package/dist-lib/components/klanten/DeliveryLocationsTab.js +9 -1
  9. package/dist-lib/components/klanten/GroupedKlantDetail.d.ts.map +1 -1
  10. package/dist-lib/components/klanten/GroupedKlantDetail.js +30 -5
  11. package/dist-lib/components/klanten/GroupedKlantDetailRoute.d.ts +4 -1
  12. package/dist-lib/components/klanten/GroupedKlantDetailRoute.d.ts.map +1 -1
  13. package/dist-lib/components/klanten/GroupedKlantDetailRoute.js +7 -4
  14. package/dist-lib/components/klanten/KlantDetail.d.ts.map +1 -1
  15. package/dist-lib/components/klanten/KlantDetail.js +26 -3
  16. package/dist-lib/components/klanten/KlantDetailLayout.d.ts +4 -2
  17. package/dist-lib/components/klanten/KlantDetailLayout.d.ts.map +1 -1
  18. package/dist-lib/components/klanten/KlantDetailLayout.js +23 -21
  19. package/dist-lib/components/klanten/KlantDetailRoute.d.ts +4 -1
  20. package/dist-lib/components/klanten/KlantDetailRoute.d.ts.map +1 -1
  21. package/dist-lib/components/klanten/KlantDetailRoute.js +7 -4
  22. package/dist-lib/components/klanten/KlantFormulier.d.ts +1 -1
  23. package/dist-lib/components/klanten/KlantFormulier.d.ts.map +1 -1
  24. package/dist-lib/components/klanten/KlantFormulier.js +14 -4
  25. package/dist-lib/components/klanten/KlantenOverzicht.d.ts.map +1 -1
  26. package/dist-lib/components/klanten/KlantenOverzicht.js +103 -16
  27. package/dist-lib/components/klanten/MultiSearchableSelect.d.ts +21 -0
  28. package/dist-lib/components/klanten/MultiSearchableSelect.d.ts.map +1 -0
  29. package/dist-lib/components/klanten/MultiSearchableSelect.js +86 -0
  30. package/dist-lib/components/klanten/NetwerkPagina.d.ts.map +1 -1
  31. package/dist-lib/components/klanten/NetwerkPagina.js +2 -1
  32. package/dist-lib/components/klanten/OvernemenTwinfieldKlant.d.ts.map +1 -1
  33. package/dist-lib/components/klanten/OvernemenTwinfieldKlant.js +1 -3
  34. package/dist-lib/components/klanten/OvernemenTwinfieldKlantRoute.d.ts +4 -1
  35. package/dist-lib/components/klanten/OvernemenTwinfieldKlantRoute.d.ts.map +1 -1
  36. package/dist-lib/components/klanten/OvernemenTwinfieldKlantRoute.js +7 -4
  37. package/dist-lib/components/klanten/SearchableSelect.d.ts +17 -0
  38. package/dist-lib/components/klanten/SearchableSelect.d.ts.map +1 -0
  39. package/dist-lib/components/klanten/SearchableSelect.js +57 -0
  40. package/dist-lib/components/klanten/pricegroups/CustomerPickerDialog.d.ts.map +1 -1
  41. package/dist-lib/components/klanten/pricegroups/CustomerPickerDialog.js +3 -2
  42. package/dist-lib/components/klanten/pricegroups/PriceGroupFormPage.d.ts.map +1 -1
  43. package/dist-lib/components/klanten/pricegroups/PriceGroupFormPage.js +2 -1
  44. package/dist-lib/integrations/supabase/auth-middleware.d.ts +33 -0
  45. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  46. package/dist-lib/integrations/supabase/client.d.ts +33 -0
  47. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  48. package/dist-lib/integrations/supabase/client.server.d.ts +33 -0
  49. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  50. package/dist-lib/integrations/supabase/types.d.ts +35 -0
  51. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  52. package/dist-lib/lib/accounting/twinfield/worker.functions.d.ts +99 -0
  53. package/dist-lib/lib/accounting/twinfield/worker.functions.d.ts.map +1 -1
  54. package/dist-lib/lib/accounting.functions.d.ts +99 -0
  55. package/dist-lib/lib/accounting.functions.d.ts.map +1 -1
  56. package/dist-lib/lib/countries.d.ts +31 -0
  57. package/dist-lib/lib/countries.d.ts.map +1 -0
  58. package/dist-lib/lib/countries.js +194 -0
  59. package/dist-lib/lib/customer-analytics.functions.d.ts +33 -0
  60. package/dist-lib/lib/customer-analytics.functions.d.ts.map +1 -1
  61. package/dist-lib/lib/customer-notes.functions.d.ts +39638 -0
  62. package/dist-lib/lib/customer-notes.functions.d.ts.map +1 -0
  63. package/dist-lib/lib/customer-notes.functions.js +59 -0
  64. package/dist-lib/lib/customers.functions.d.ts +297 -0
  65. package/dist-lib/lib/customers.functions.d.ts.map +1 -1
  66. package/dist-lib/lib/delivery-locations.functions.d.ts +132 -0
  67. package/dist-lib/lib/delivery-locations.functions.d.ts.map +1 -1
  68. package/dist-lib/lib/external-customers.functions.d.ts +132 -0
  69. package/dist-lib/lib/external-customers.functions.d.ts.map +1 -1
  70. package/dist-lib/lib/floriday-assortment.functions.d.ts +33 -0
  71. package/dist-lib/lib/floriday-assortment.functions.d.ts.map +1 -1
  72. package/dist-lib/lib/floriday-discounts.functions.d.ts +66 -0
  73. package/dist-lib/lib/floriday-discounts.functions.d.ts.map +1 -1
  74. package/dist-lib/lib/floriday-trade-items.functions.d.ts +33 -0
  75. package/dist-lib/lib/floriday-trade-items.functions.d.ts.map +1 -1
  76. package/dist-lib/lib/local-discounts.functions.d.ts +231 -0
  77. package/dist-lib/lib/local-discounts.functions.d.ts.map +1 -1
  78. package/dist-lib/lib/logistics-events.functions.d.ts +33 -0
  79. package/dist-lib/lib/logistics-events.functions.d.ts.map +1 -1
  80. package/dist-lib/lib/logistics-strategy.functions.d.ts +132 -0
  81. package/dist-lib/lib/logistics-strategy.functions.d.ts.map +1 -1
  82. package/dist-lib/lib/overdue-invoices.functions.d.ts +33 -0
  83. package/dist-lib/lib/overdue-invoices.functions.d.ts.map +1 -1
  84. package/dist-lib/lib/payment-method.d.ts +22 -0
  85. package/dist-lib/lib/payment-method.d.ts.map +1 -0
  86. package/dist-lib/lib/payment-method.js +74 -0
  87. package/dist-lib/lib/price-groups-local.functions.d.ts +231 -0
  88. package/dist-lib/lib/price-groups-local.functions.d.ts.map +1 -1
  89. package/dist-lib/lib/price-groups.functions.d.ts +33 -0
  90. package/dist-lib/lib/price-groups.functions.d.ts.map +1 -1
  91. package/dist-lib/lib/twinfield-adopt.functions.d.ts +66 -0
  92. package/dist-lib/lib/twinfield-adopt.functions.d.ts.map +1 -1
  93. package/dist-lib/lib/twinfield-ledger.functions.d.ts +33 -0
  94. package/dist-lib/lib/twinfield-ledger.functions.d.ts.map +1 -1
  95. package/package.json +1 -1
  96. package/public/flowselections-assets/Klanten/twinfield-logo.svg +218 -0
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useRef, useState } from "react";
3
+ import { Button, Input, Popover, PopoverContent, PopoverTrigger, } from "@flowselections/core";
4
+ import { ChevronDown, X } from "lucide-react";
5
+ import { cn } from "@flowselections/core";
6
+ export function SearchableSelect({ value, onValueChange, options, placeholder = "Selecteer...", triggerClassName, autoFocus = true, }) {
7
+ const [open, setOpen] = useState(false);
8
+ const [query, setQuery] = useState("");
9
+ const inputRef = useRef(null);
10
+ const selected = useMemo(() => options.find((o) => o.value === value), [options, value]);
11
+ const filtered = useMemo(() => {
12
+ const q = query.trim().toLowerCase();
13
+ if (!q)
14
+ return options;
15
+ return options.filter((o) => {
16
+ const haystack = [normalizeForSearch(o.label), o.search]
17
+ .filter(Boolean)
18
+ .join(" ")
19
+ .toLowerCase();
20
+ return haystack.includes(q);
21
+ });
22
+ }, [options, query]);
23
+ const handleSelect = (next) => {
24
+ onValueChange(next);
25
+ setQuery("");
26
+ setOpen(false);
27
+ };
28
+ const handleClear = (e) => {
29
+ e.stopPropagation();
30
+ const allOption = options.find((o) => o.value === "__all__");
31
+ onValueChange(allOption ? "__all__" : "");
32
+ setQuery("");
33
+ };
34
+ const showClear = Boolean(value && value !== "__all__" && value !== "__none__");
35
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "outline", role: "combobox", "aria-expanded": open, className: cn("justify-between font-normal bg-background hover:bg-accent", triggerClassName), children: [_jsx("span", { className: "truncate", children: selected ? selected.label : placeholder }), _jsxs("span", { className: "ml-2 flex shrink-0 items-center gap-1", children: [showClear && (_jsx("span", { role: "button", tabIndex: 0, onClick: handleClear, onKeyDown: (e) => {
36
+ if (e.key === "Enter" || e.key === " ") {
37
+ e.preventDefault();
38
+ handleClear(e);
39
+ }
40
+ }, className: "inline-flex rounded-sm hover:bg-muted", "aria-label": "Keuze wissen", children: _jsx(X, { className: "h-4 w-4 text-muted-foreground" }) })), _jsx(ChevronDown, { className: "h-4 w-4 text-muted-foreground" })] })] }) }), _jsxs(PopoverContent, { className: "p-0 w-[var(--radix-popover-trigger-width)]", align: "start", sideOffset: 4, onOpenAutoFocus: (e) => {
41
+ if (!autoFocus)
42
+ e.preventDefault();
43
+ }, children: [_jsx("div", { className: "p-2 border-b", children: _jsxs("div", { className: "relative", children: [_jsx(Input, { ref: inputRef, placeholder: "Zoeken...", value: query, onChange: (e) => setQuery(e.target.value), className: "pr-8", autoFocus: autoFocus }), query && (_jsx("button", { type: "button", onClick: () => setQuery(""), className: "absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground", "aria-label": "Zoekopdracht wissen", children: _jsx(X, { className: "h-4 w-4" }) }))] }) }), _jsx("div", { className: "max-h-[40vh] overflow-y-auto overscroll-contain py-1", children: filtered.length === 0 ? (_jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: "Geen resultaten" })) : (filtered.map((o) => (_jsx("button", { type: "button", onClick: () => handleSelect(o.value), className: cn("w-full text-left px-3 py-2 text-sm flex items-center gap-2 hover:bg-accent hover:text-accent-foreground", value === o.value && "bg-accent text-accent-foreground"), children: _jsx("span", { className: "truncate", children: o.label }) }, o.value)))) })] })] }));
44
+ }
45
+ function normalizeForSearch(node) {
46
+ if (typeof node === "string")
47
+ return node;
48
+ if (typeof node === "number")
49
+ return String(node);
50
+ if (Array.isArray(node))
51
+ return node.map(normalizeForSearch).join(" ");
52
+ if (node && typeof node === "object" && "props" in node) {
53
+ const children = node.props?.children;
54
+ return normalizeForSearch(children);
55
+ }
56
+ return "";
57
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"CustomerPickerDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/klanten/pricegroups/CustomerPickerDialog.tsx"],"names":[],"mappings":"AAcA,wBAAgB,oBAAoB,CAAC,EACnC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,GAClD,EAAE;IACD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACrC,+BA+HA"}
1
+ {"version":3,"file":"CustomerPickerDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/klanten/pricegroups/CustomerPickerDialog.tsx"],"names":[],"mappings":"AAcA,wBAAgB,oBAAoB,CAAC,EACnC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,GAClD,EAAE;IACD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACrC,+BA+IA"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
3
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4
4
  import { useServerFn } from "@tanstack/react-start";
@@ -7,6 +7,7 @@ import { Search } from "lucide-react";
7
7
  import { listExternalCustomers } from "../../../lib/external-customers.functions";
8
8
  import { setPriceGroupMembers, getCustomerPriceGroup, } from "../../../lib/price-groups-local.functions";
9
9
  import { decodeDeep } from "../../../lib/decode-html";
10
+ import { countryNameToFlag } from "../../../lib/countries";
10
11
  export function CustomerPickerDialog({ priceGroupId, open, onOpenChange, value, onChange, }) {
11
12
  const qc = useQueryClient();
12
13
  const listCustomers = useServerFn(listExternalCustomers);
@@ -71,6 +72,6 @@ export function CustomerPickerDialog({ priceGroupId, open, onOpenChange, value,
71
72
  };
72
73
  return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-[720px]", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Klanten toewijzen" }) }), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), _jsx(Input, { placeholder: "Zoek op naam, plaats of BTW-nummer\u2026", value: search, onChange: (e) => setSearch(e.target.value), className: "pl-9" })] }), _jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [_jsxs("span", { children: [filtered.length, " klanten"] }), _jsxs("span", { children: [_jsx("strong", { className: "text-foreground", children: selected.size }), " geselecteerd"] })] }), _jsx("div", { className: "max-h-[380px] overflow-y-auto border rounded-md divide-y", children: isLoading ? (_jsx("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "Laden\u2026" })) : filtered.length === 0 ? (_jsx("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "Geen klanten gevonden." })) : filtered.map((c) => {
73
74
  const checked = selected.has(c.group_key);
74
- return (_jsxs("label", { className: "flex items-center gap-3 p-2.5 hover:bg-muted/50 cursor-pointer", children: [_jsx(Checkbox, { checked: checked, onCheckedChange: () => toggle(c.group_key) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-sm font-medium truncate", children: c.display_name }), _jsx("div", { className: "text-xs text-muted-foreground truncate", children: [c.city, c.country].filter(Boolean).join(" · ") || "—" })] }), _jsx("div", { className: "flex gap-1", children: c.providers.slice(0, 3).map((p) => (_jsx(Badge, { variant: "secondary", className: "text-[10px]", children: p }, p))) })] }, c.group_key));
75
+ return (_jsxs("label", { className: "flex items-center gap-3 p-2.5 hover:bg-muted/50 cursor-pointer", children: [_jsx(Checkbox, { checked: checked, onCheckedChange: () => toggle(c.group_key) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-sm font-medium truncate", children: c.display_name }), _jsx("div", { className: "text-xs text-muted-foreground truncate", children: c.city ? (_jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx("span", { children: c.city }), c.country && (_jsxs(_Fragment, { children: [_jsx("span", { children: "\u00B7" }), _jsx("span", { className: "text-base", "aria-hidden": "true", children: countryNameToFlag(c.country) ?? "🌐" }), _jsx("span", { children: c.country })] }))] })) : c.country ? (_jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx("span", { className: "text-base", "aria-hidden": "true", children: countryNameToFlag(c.country) ?? "🌐" }), _jsx("span", { children: c.country })] })) : "—" })] }), _jsx("div", { className: "flex gap-1", children: c.providers.slice(0, 3).map((p) => (_jsx(Badge, { variant: "secondary", className: "text-[10px]", children: p }, p))) })] }, c.group_key));
75
76
  }) }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), children: "Annuleren" }), _jsx(Button, { onClick: handleSave, disabled: !isControlled && saveMut.isPending, children: !isControlled && saveMut.isPending ? "Opslaan…" : "Selectie opslaan" })] })] }) }));
76
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PriceGroupFormPage.d.ts","sourceRoot":"","sources":["../../../../src/components/klanten/pricegroups/PriceGroupFormPage.tsx"],"names":[],"mappings":"AAmLA,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,+BA0rB9E"}
1
+ {"version":3,"file":"PriceGroupFormPage.d.ts","sourceRoot":"","sources":["../../../../src/components/klanten/pricegroups/PriceGroupFormPage.tsx"],"names":[],"mappings":"AAoLA,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,+BAusB9E"}
@@ -14,6 +14,7 @@ import { CustomerPickerDialog } from "./CustomerPickerDialog";
14
14
  import { UserPlus, Users2 } from "lucide-react";
15
15
  import { listExternalCustomers } from "../../../lib/external-customers.functions";
16
16
  import { decodeDeep } from "../../../lib/decode-html";
17
+ import { countryNameToFlag } from "../../../lib/countries";
17
18
  import { Badge } from "@flowselections/core";
18
19
  import { toast } from "sonner";
19
20
  const emptyInput = {
@@ -254,7 +255,7 @@ export function PriceGroupFormPage({ editingId }) {
254
255
  "De ingestelde transport- en afleverkosten in de levervoorwaarden worden in rekening gebracht",
255
256
  ] }))] }), _jsxs("div", { className: "pt-2", children: [_jsx("div", { className: "text-sm text-muted-foreground mb-2", children: "Diensten" }), _jsx(Separator, { className: "mb-3" }), _jsxs("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [_jsx(Checkbox, { checked: form.include_stickers, onCheckedChange: (v) => patch({ include_stickers: v === true }) }), _jsx("span", { className: "text-sm font-medium", children: "Inclusief stickeren" })] })] }), _jsxs("div", { className: "pt-2", children: [_jsx("div", { className: "text-sm text-muted-foreground mb-2", children: "Afname" }), _jsx(Separator, { className: "mb-3" }), _jsxs("div", { className: "max-w-sm", children: [_jsx(Label, { children: "Afname-eenheid" }), _jsxs(Select, { value: form.unit, onValueChange: (v) => patch({ unit: v }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "- Selecteer een eenheid -" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "per_fust", children: "Per fust" }), _jsx(SelectItem, { value: "per_laag", children: "Per laag" }), _jsx(SelectItem, { value: "per_ladingdrager", children: "Per ladingdrager" })] })] })] }), _jsxs("div", { className: "text-xs text-muted-foreground mt-2 leading-relaxed", children: ["Afname-eenheid per aangeboden artikel.", _jsx("br", {}), "Deze instelling geldt voor alle klanten in deze prijsgroep, per aangeboden artikel, niet per bestelling."] })] }), _jsx("div", { className: "pt-2 flex justify-end", children: _jsxs(Button, { onClick: () => nextStep(1), children: ["Volgende stap ", _jsx(ArrowRight, { className: "h-4 w-4 ml-1" })] }) })] }) }), _jsx(StepSection, { index: 2, title: STEP_TITLES[2], subtitle: summaries[2], open: openStep === 2, completed: form.pricing_mode === "calculated" && maxReached >= 2 && openStep !== 2, disabled: maxReached < 2 || form.pricing_mode !== "calculated", onToggle: () => goToStep(2), children: _jsx("div", { className: "space-y-4", children: form.pricing_mode !== "calculated" ? (_jsx("div", { className: "text-sm text-muted-foreground p-4 border rounded-md bg-muted/30", children: "Deze prijsgroep gebruikt handmatige prijzen. Prijsberekening is niet van toepassing." })) : (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx(Label, { children: "Korting/opslag per stuk" }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-3 mt-1.5", children: [_jsxs(Select, { value: form.calc_type ?? "discount", onValueChange: (v) => patch({ calc_type: v }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "discount", children: "Korting" }), _jsx(SelectItem, { value: "surcharge", children: "Opslag" })] })] }), _jsxs(Select, { value: form.calc_value_type ?? "fixed", onValueChange: (v) => patch({ calc_value_type: v }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "percentage", children: "Percentage" }), _jsx(SelectItem, { value: "fixed", children: "Vast bedrag" })] })] }), _jsxs("div", { className: "relative", children: [form.calc_value_type !== "percentage" && (_jsx("span", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground pointer-events-none", children: "\u20AC" })), _jsx(Input, { type: "number", step: form.calc_value_type === "percentage" ? "1" : "0.001", value: form.calc_value ?? 0, onChange: (e) => patch({ calc_value: Number(e.target.value) }), className: form.calc_value_type === "percentage" ? "pr-8" : "pl-7" }), form.calc_value_type === "percentage" && (_jsx("span", { className: "absolute right-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground pointer-events-none", children: "%" }))] })] })] }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsxs(Label, { className: "flex items-center gap-1.5", children: ["Afhandelingskosten (optioneel)", _jsx(Info, { className: "h-3.5 w-3.5 text-muted-foreground", "aria-label": "Extra kosten die bovenop de prijs komen. Kies hoe deze verdeeld worden." })] }), _jsxs("div", { className: "relative mt-1.5", children: [_jsx("span", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground pointer-events-none", children: "\u20AC" }), _jsx(Input, { type: "number", step: "0.01", value: form.handling_fee ?? 0, onChange: (e) => patch({ handling_fee: Number(e.target.value) }), className: "pl-7" })] })] }), _jsxs("div", { children: [_jsx(Label, { children: "Verdeeld over het aantal planten of bloemen op een" }), _jsxs(Select, { value: form.distribute_over ?? "ladingdrager", onValueChange: (v) => patch({ distribute_over: v }), children: [_jsx(SelectTrigger, { className: "mt-1.5", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "ladingdrager", children: "Ladingdrager" }), _jsx(SelectItem, { value: "laag", children: "Laag" }), _jsx(SelectItem, { value: "fust", children: "Fust" })] })] })] })] }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsx(Label, { children: "Prijs afronden" }), _jsxs(Select, { value: form.rounding, onValueChange: (v) => patch({ rounding: v }), children: [_jsx(SelectTrigger, { className: "mt-1.5", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "none", children: "Niet afronden" }), _jsx(SelectItem, { value: "up", children: "Omhoog" }), _jsx(SelectItem, { value: "down", children: "Omlaag" }), _jsx(SelectItem, { value: "nearest", children: "Dichtstbijzijnde" })] })] })] }), form.rounding !== "none" && (_jsxs("div", { children: [_jsx(Label, { children: "Op" }), _jsxs(Select, { value: String(form.rounding_step ?? 0.05), onValueChange: (v) => patch({ rounding_step: Number(v) }), children: [_jsx(SelectTrigger, { className: "mt-1.5", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "0.01", children: "\u20AC 0,01" }), _jsx(SelectItem, { value: "0.05", children: "\u20AC 0,05" }), _jsx(SelectItem, { value: "0.1", children: "\u20AC 0,10" })] })] })] }))] }), _jsx("div", { className: "pt-2 flex justify-end", children: _jsxs(Button, { onClick: () => nextStep(2), children: ["Volgende stap ", _jsx(ArrowRight, { className: "h-4 w-4 ml-1" })] }) })] })) }) }), _jsxs(StepSection, { index: 3, title: STEP_TITLES[3], subtitle: summaries[3], open: openStep === 3, completed: form.group_type === "customer_specific" && maxReached >= 3 && openStep !== 3 && selectedCustomerKeys.length > 0, disabled: maxReached < 3 || form.group_type !== "customer_specific", onToggle: () => goToStep(3), children: [form.group_type !== "customer_specific" ? (_jsx("div", { className: "text-sm text-muted-foreground p-4 border rounded-md bg-muted/30", children: "Algemene prijsgroepen zijn zichtbaar voor alle klanten \u2014 een doelgroep is niet van toepassing." })) : selectedCustomerKeys.length === 0 ? (_jsxs("div", { className: "rounded-lg border bg-muted/20 p-8", children: [_jsxs("div", { className: "flex flex-col items-center text-center gap-3", children: [_jsxs("div", { className: "relative h-16 w-16 rounded-full bg-muted flex items-center justify-center", children: [_jsx(Users2, { className: "h-8 w-8 text-muted-foreground/60" }), _jsx("span", { className: "absolute -top-1 -right-1 h-6 w-6 rounded-full bg-background border flex items-center justify-center", children: _jsx(UserPlus, { className: "h-3.5 w-3.5 text-muted-foreground" }) })] }), _jsx("div", { children: _jsx("div", { className: "font-medium text-sm", children: "Nog geen klanten toegevoegd" }) })] }), _jsx("div", { className: "flex justify-end mt-4", children: _jsxs(Button, { variant: "outline", onClick: () => setCustomerPickerOpen(true), children: [_jsx(UserPlus, { className: "h-4 w-4 mr-1.5" }), " Organisaties wijzigen"] }) })] })) : (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "text-sm text-muted-foreground", children: [_jsx("strong", { className: "text-foreground", children: selectedCustomerKeys.length }), " ", "klant", selectedCustomerKeys.length === 1 ? "" : "en", " gekoppeld"] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setCustomerPickerOpen(true), children: [_jsx(UserPlus, { className: "h-4 w-4 mr-1.5" }), " Organisaties wijzigen"] })] }), _jsx("div", { className: "max-h-[320px] overflow-y-auto border rounded-md divide-y", children: selectedCustomerKeys.map((k) => {
256
257
  const c = customersByKey.get(k);
257
- return (_jsxs("div", { className: "flex items-center gap-3 p-2.5", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-sm font-medium truncate", children: c?.display_name ?? k }), _jsx("div", { className: "text-xs text-muted-foreground truncate", children: c ? [c.city, c.country].filter(Boolean).join(" · ") || "—" : "Niet in cache" })] }), _jsx("div", { className: "flex gap-1", children: (c?.providers ?? []).slice(0, 3).map((p) => (_jsx(Badge, { variant: "secondary", className: "text-[10px]", children: p }, p))) })] }, k));
258
+ return (_jsxs("div", { className: "flex items-center gap-3 p-2.5", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-sm font-medium truncate", children: c?.display_name ?? k }), _jsx("div", { className: "text-xs text-muted-foreground truncate", children: c ? (c.city || c.country ? (_jsxs("span", { className: "inline-flex items-center gap-1", children: [c.city && _jsx("span", { children: c.city }), c.city && c.country && _jsx("span", { children: "\u00B7" }), c.country && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-base", "aria-hidden": "true", children: countryNameToFlag(c.country) ?? "🌐" }), _jsx("span", { children: c.country })] }))] })) : "—") : "Niet in cache" })] }), _jsx("div", { className: "flex gap-1", children: (c?.providers ?? []).slice(0, 3).map((p) => (_jsx(Badge, { variant: "secondary", className: "text-[10px]", children: p }, p))) })] }, k));
258
259
  }) })] })), _jsx(CustomerPickerDialog, { open: customerPickerOpen, onOpenChange: setCustomerPickerOpen, value: selectedCustomerKeys, onChange: setSelectedCustomerKeys })] }), error && _jsx("div", { className: "text-sm text-destructive", children: error })] }), form.pricing_mode === "calculated" && (_jsxs("aside", { className: "lg:sticky lg:top-4 space-y-3", children: [_jsx(Card, { children: _jsxs(CardContent, { className: "p-4 space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-sm font-medium", children: "Voorbeeld prijscalculatie" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Button, { variant: "outline", size: "icon", className: "h-7 w-7", onClick: () => cycleItem(-1), disabled: items.length < 2, "aria-label": "Vorige product", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsx(Button, { variant: "outline", size: "icon", className: "h-7 w-7", onClick: () => cycleItem(1), disabled: items.length < 2, "aria-label": "Volgend product", children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] })] }), _jsxs("button", { type: "button", onClick: () => setPickerOpen(true), className: "w-full flex items-center gap-3 text-left hover:bg-muted/30 rounded-md p-2 -m-2", children: [_jsx("div", { className: "h-14 w-14 rounded bg-muted flex items-center justify-center overflow-hidden shrink-0", children: selectedItem?.image_url
259
260
  ? _jsx("img", { src: selectedItem.image_url, alt: "", className: "h-full w-full object-contain" })
260
261
  : _jsx(ImageIcon, { className: "h-6 w-6 text-muted-foreground" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-sm font-medium truncate", children: selectedItem?.name ?? "Geen product beschikbaar" }), _jsx("div", { className: "text-xs text-muted-foreground truncate", children: selectedItem
@@ -1859,6 +1859,39 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
1859
1859
  referencedColumns: ["id"];
1860
1860
  }];
1861
1861
  };
1862
+ customer_notes: {
1863
+ Row: {
1864
+ created_at: string;
1865
+ customer_id: string | null;
1866
+ group_key: string | null;
1867
+ id: string;
1868
+ notes: string | null;
1869
+ updated_at: string;
1870
+ };
1871
+ Insert: {
1872
+ created_at?: string;
1873
+ customer_id?: string | null;
1874
+ group_key?: string | null;
1875
+ id?: string;
1876
+ notes?: string | null;
1877
+ updated_at?: string;
1878
+ };
1879
+ Update: {
1880
+ created_at?: string;
1881
+ customer_id?: string | null;
1882
+ group_key?: string | null;
1883
+ id?: string;
1884
+ notes?: string | null;
1885
+ updated_at?: string;
1886
+ };
1887
+ Relationships: [{
1888
+ foreignKeyName: "customer_notes_customer_id_fkey";
1889
+ columns: ["customer_id"];
1890
+ isOneToOne: true;
1891
+ referencedRelation: "customers";
1892
+ referencedColumns: ["id"];
1893
+ }];
1894
+ };
1862
1895
  customer_price_group_members: {
1863
1896
  Row: {
1864
1897
  created_at: string;