@flowselections/floriday-klanten-module 1.0.12 → 1.0.13

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 (43) hide show
  1. package/dist-lib/components/klanten/DiscountsTab.d.ts +4 -0
  2. package/dist-lib/components/klanten/DiscountsTab.d.ts.map +1 -0
  3. package/dist-lib/components/klanten/DiscountsTab.js +92 -0
  4. package/dist-lib/components/klanten/GroupedKlantDetail.d.ts.map +1 -1
  5. package/dist-lib/components/klanten/GroupedKlantDetail.js +4 -1
  6. package/dist-lib/components/klanten/KlantDetail.d.ts.map +1 -1
  7. package/dist-lib/components/klanten/KlantDetail.js +2 -1
  8. package/dist-lib/components/klanten/KlantenOverzicht.d.ts.map +1 -1
  9. package/dist-lib/components/klanten/KlantenOverzicht.js +83 -23
  10. package/dist-lib/components/klanten/LocalDiscountFormDialog.d.ts +10 -0
  11. package/dist-lib/components/klanten/LocalDiscountFormDialog.d.ts.map +1 -0
  12. package/dist-lib/components/klanten/LocalDiscountFormDialog.js +107 -0
  13. package/dist-lib/components/klanten/LocalDiscountsTab.d.ts +4 -0
  14. package/dist-lib/components/klanten/LocalDiscountsTab.d.ts.map +1 -0
  15. package/dist-lib/components/klanten/LocalDiscountsTab.js +101 -0
  16. package/dist-lib/integrations/supabase/auth-middleware.d.ts +1497 -43
  17. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  18. package/dist-lib/integrations/supabase/client.d.ts +1497 -43
  19. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  20. package/dist-lib/integrations/supabase/client.server.d.ts +1497 -43
  21. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  22. package/dist-lib/integrations/supabase/types.d.ts +1519 -39
  23. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  24. package/dist-lib/lib/accounting.functions.d.ts +4512 -150
  25. package/dist-lib/lib/accounting.functions.d.ts.map +1 -1
  26. package/dist-lib/lib/customer-analytics.functions.d.ts +1497 -43
  27. package/dist-lib/lib/customer-analytics.functions.d.ts.map +1 -1
  28. package/dist-lib/lib/customers.functions.d.ts +10178 -0
  29. package/dist-lib/lib/customers.functions.d.ts.map +1 -1
  30. package/dist-lib/lib/delivery-locations.functions.d.ts +5816 -0
  31. package/dist-lib/lib/delivery-locations.functions.d.ts.map +1 -1
  32. package/dist-lib/lib/external-customers.functions.d.ts +5816 -0
  33. package/dist-lib/lib/external-customers.functions.d.ts.map +1 -1
  34. package/dist-lib/lib/floriday-discounts.functions.d.ts +21974 -0
  35. package/dist-lib/lib/floriday-discounts.functions.d.ts.map +1 -0
  36. package/dist-lib/lib/floriday-discounts.functions.js +83 -0
  37. package/dist-lib/lib/local-discounts.functions.d.ts +76898 -0
  38. package/dist-lib/lib/local-discounts.functions.d.ts.map +1 -0
  39. package/dist-lib/lib/local-discounts.functions.js +185 -0
  40. package/dist-lib/lib/overdue-invoices.functions.d.ts +10984 -0
  41. package/dist-lib/lib/overdue-invoices.functions.d.ts.map +1 -0
  42. package/dist-lib/lib/overdue-invoices.functions.js +72 -0
  43. package/package.json +1 -1
@@ -0,0 +1,101 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from "react";
3
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4
+ import { useServerFn } from "@tanstack/react-start";
5
+ import { Card, CardContent, Badge, Input, Button, toast, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@flowselections/core";
6
+ import { Percent, FileText, Users, Plus, Pencil, Trash2 } from "lucide-react";
7
+ import { listLocalCustomerDiscounts, deleteLocalDiscount, } from "../../lib/local-discounts.functions";
8
+ import { LocalDiscountFormDialog } from "./LocalDiscountFormDialog";
9
+ const SOURCE_LABEL = {
10
+ agreement: "Contract",
11
+ sales_strategy: "Kortingsregel",
12
+ price_group: "Staffel",
13
+ };
14
+ const SOURCE_ICON = {
15
+ agreement: _jsx(FileText, { className: "h-3 w-3" }),
16
+ sales_strategy: _jsx(Percent, { className: "h-3 w-3" }),
17
+ price_group: _jsx(Users, { className: "h-3 w-3" }),
18
+ };
19
+ function fmtMoney(v, currency = "EUR") {
20
+ if (v == null)
21
+ return "—";
22
+ try {
23
+ return new Intl.NumberFormat("nl-NL", { style: "currency", currency }).format(v);
24
+ }
25
+ catch {
26
+ return `${v.toFixed(2)} ${currency}`;
27
+ }
28
+ }
29
+ function fmtDiscount(row) {
30
+ if (row.discount_type == null || row.discount_value == null)
31
+ return "—";
32
+ return row.discount_type === "percentage"
33
+ ? `${row.discount_value}%`
34
+ : fmtMoney(row.discount_value, row.currency);
35
+ }
36
+ function fmtDate(v) {
37
+ if (!v)
38
+ return "—";
39
+ try {
40
+ return new Date(v).toLocaleDateString("nl-NL");
41
+ }
42
+ catch {
43
+ return v;
44
+ }
45
+ }
46
+ function isActiveOn(row, date) {
47
+ if (row.valid_from && row.valid_from > date)
48
+ return false;
49
+ if (row.valid_until && row.valid_until < date)
50
+ return false;
51
+ return true;
52
+ }
53
+ export function LocalDiscountsTab({ customerId }) {
54
+ const qc = useQueryClient();
55
+ const fn = useServerFn(listLocalCustomerDiscounts);
56
+ const del = useServerFn(deleteLocalDiscount);
57
+ const { data, isLoading, error } = useQuery({
58
+ queryKey: ["local-discounts", customerId],
59
+ queryFn: () => fn({ data: { customerId } }),
60
+ });
61
+ const [source, setSource] = useState("all");
62
+ const [search, setSearch] = useState("");
63
+ const [onlyActive, setOnlyActive] = useState(true);
64
+ const [dialogOpen, setDialogOpen] = useState(false);
65
+ const [editing, setEditing] = useState(null);
66
+ const today = new Date().toISOString().slice(0, 10);
67
+ const delMut = useMutation({
68
+ mutationFn: (row) => del({ data: { source: row.source, id: row.source_id } }),
69
+ onSuccess: () => {
70
+ toast.success("Korting verwijderd");
71
+ qc.invalidateQueries({ queryKey: ["local-discounts", customerId] });
72
+ },
73
+ onError: (err) => toast.error(err.message),
74
+ });
75
+ const filtered = useMemo(() => {
76
+ const rows = data?.rows ?? [];
77
+ return rows.filter((r) => {
78
+ if (source !== "all" && r.source !== source)
79
+ return false;
80
+ if (onlyActive && !isActiveOn(r, today))
81
+ return false;
82
+ if (search) {
83
+ const q = search.toLowerCase();
84
+ const hay = [r.product_name, r.product_id].filter(Boolean).join(" ").toLowerCase();
85
+ if (!hay.includes(q))
86
+ return false;
87
+ }
88
+ return true;
89
+ });
90
+ }, [data, source, search, onlyActive, today]);
91
+ if (isLoading)
92
+ return _jsx(Card, { children: _jsx(CardContent, { className: "pt-6", children: "Kortingen laden\u2026" }) });
93
+ if (error) {
94
+ return (_jsx(Card, { children: _jsxs(CardContent, { className: "pt-6 text-sm text-destructive", children: ["Kortingen konden niet worden geladen: ", error.message] }) }));
95
+ }
96
+ const s = data?.summary;
97
+ return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-3 md:grid-cols-3", children: [_jsx(SummaryCard, { label: "Contracten", value: s?.agreements ?? 0, icon: _jsx(FileText, { className: "h-4 w-4" }) }), _jsx(SummaryCard, { label: "Kortingsregels", value: s?.sales_strategies ?? 0, icon: _jsx(Percent, { className: "h-4 w-4" }) }), _jsx(SummaryCard, { label: "Staffels", value: s?.price_groups ?? 0, icon: _jsx(Users, { className: "h-4 w-4" }) })] }), _jsx(Card, { children: _jsxs(CardContent, { className: "pt-6 space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Input, { placeholder: "Zoek op product\u2026", value: search, onChange: (e) => setSearch(e.target.value), className: "max-w-xs" }), _jsxs(Select, { value: source, onValueChange: (v) => setSource(v), children: [_jsx(SelectTrigger, { className: "w-44", children: _jsx(SelectValue, { placeholder: "Bron" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "Alle bronnen" }), _jsx(SelectItem, { value: "agreement", children: "Contract" }), _jsx(SelectItem, { value: "sales_strategy", children: "Kortingsregel" }), _jsx(SelectItem, { value: "price_group", children: "Staffel" })] })] }), _jsxs("label", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx("input", { type: "checkbox", checked: onlyActive, onChange: (e) => setOnlyActive(e.target.checked) }), "Alleen actief vandaag"] }), _jsxs(Button, { className: "ml-auto", size: "sm", onClick: () => { setEditing(null); setDialogOpen(true); }, children: [_jsx(Plus, { className: "h-4 w-4 mr-1" }), " Nieuwe korting"] })] }), _jsx("div", { className: "rounded-md border overflow-x-auto", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Product" }), _jsx(TableHead, { children: "Bron" }), _jsx(TableHead, { className: "text-right", children: "Basisprijs" }), _jsx(TableHead, { className: "text-right", children: "Korting" }), _jsx(TableHead, { className: "text-right", children: "Netto" }), _jsx(TableHead, { children: "Geldig" }), _jsx(TableHead, { className: "text-right", children: "Min. hvh" }), _jsx(TableHead, { className: "w-20" })] }) }), _jsx(TableBody, { children: filtered.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 8, className: "text-center text-muted-foreground py-6", children: "Nog geen kortingen voor deze klant." }) })) : filtered.map((r) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: r.product_name ?? "—" }), _jsx(TableCell, { children: _jsxs(Badge, { variant: "secondary", className: "gap-1", children: [SOURCE_ICON[r.source], SOURCE_LABEL[r.source]] }) }), _jsx(TableCell, { className: "text-right tabular-nums", children: fmtMoney(r.base_price, r.currency) }), _jsx(TableCell, { className: "text-right tabular-nums", children: fmtDiscount(r) }), _jsx(TableCell, { className: "text-right tabular-nums font-medium", children: fmtMoney(r.net_price, r.currency) }), _jsxs(TableCell, { className: "text-sm text-muted-foreground", children: [fmtDate(r.valid_from), " \u2013 ", fmtDate(r.valid_until)] }), _jsx(TableCell, { className: "text-right tabular-nums", children: r.min_quantity || "—" }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex gap-1 justify-end", children: [_jsx(Button, { variant: "ghost", size: "icon", onClick: () => { setEditing(r); setDialogOpen(true); }, children: _jsx(Pencil, { className: "h-3.5 w-3.5" }) }), _jsx(Button, { variant: "ghost", size: "icon", onClick: () => delMut.mutate(r), children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) })] }) })] }, `${r.source}-${r.source_id}`))) })] }) })] }) }), _jsx(LocalDiscountFormDialog, { open: dialogOpen, onOpenChange: setDialogOpen, customerId: customerId, editing: editing })] }));
98
+ }
99
+ function SummaryCard({ label, value, icon, }) {
100
+ return (_jsx(Card, { children: _jsxs(CardContent, { className: "p-4", children: [_jsxs("div", { className: "flex items-center gap-2 text-xs uppercase text-muted-foreground", children: [icon, label] }), _jsx("div", { className: "text-2xl font-semibold mt-1", children: value })] }) }));
101
+ }