@flowselections/floriday-klanten-module 1.0.11 → 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.
- package/dist-lib/components/klanten/DiscountsTab.d.ts +4 -0
- package/dist-lib/components/klanten/DiscountsTab.d.ts.map +1 -0
- package/dist-lib/components/klanten/DiscountsTab.js +92 -0
- package/dist-lib/components/klanten/GroupedKlantDetail.d.ts.map +1 -1
- package/dist-lib/components/klanten/GroupedKlantDetail.js +5 -2
- package/dist-lib/components/klanten/KlantDetail.d.ts.map +1 -1
- package/dist-lib/components/klanten/KlantDetail.js +3 -2
- package/dist-lib/components/klanten/KlantenOverzicht.d.ts.map +1 -1
- package/dist-lib/components/klanten/KlantenOverzicht.js +83 -23
- package/dist-lib/components/klanten/LocalDiscountFormDialog.d.ts +10 -0
- package/dist-lib/components/klanten/LocalDiscountFormDialog.d.ts.map +1 -0
- package/dist-lib/components/klanten/LocalDiscountFormDialog.js +107 -0
- package/dist-lib/components/klanten/LocalDiscountsTab.d.ts +4 -0
- package/dist-lib/components/klanten/LocalDiscountsTab.d.ts.map +1 -0
- package/dist-lib/components/klanten/LocalDiscountsTab.js +101 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +1788 -107
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +1788 -107
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +1788 -107
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +1819 -104
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/accounting.functions.d.ts +5362 -319
- package/dist-lib/lib/accounting.functions.d.ts.map +1 -1
- package/dist-lib/lib/customer-analytics.functions.d.ts +1788 -107
- package/dist-lib/lib/customer-analytics.functions.d.ts.map +1 -1
- package/dist-lib/lib/customers.functions.d.ts +11767 -0
- package/dist-lib/lib/customers.functions.d.ts.map +1 -1
- package/dist-lib/lib/delivery-locations.functions.d.ts +6724 -0
- package/dist-lib/lib/delivery-locations.functions.d.ts.map +1 -1
- package/dist-lib/lib/external-customers.functions.d.ts +6724 -0
- package/dist-lib/lib/external-customers.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-discounts.functions.d.ts +21974 -0
- package/dist-lib/lib/floriday-discounts.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-discounts.functions.js +83 -0
- package/dist-lib/lib/local-discounts.functions.d.ts +76898 -0
- package/dist-lib/lib/local-discounts.functions.d.ts.map +1 -0
- package/dist-lib/lib/local-discounts.functions.js +185 -0
- package/dist-lib/lib/overdue-invoices.functions.d.ts +10984 -0
- package/dist-lib/lib/overdue-invoices.functions.d.ts.map +1 -0
- package/dist-lib/lib/overdue-invoices.functions.js +72 -0
- package/package.json +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
+
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Button, Input, Label, toast, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
|
|
6
|
+
import { upsertLocalAgreement, upsertLocalSalesStrategy, upsertLocalPriceGroup, listLocalProducts, } from "../../lib/local-discounts.functions";
|
|
7
|
+
export function LocalDiscountFormDialog({ open, onOpenChange, customerId, editing }) {
|
|
8
|
+
const qc = useQueryClient();
|
|
9
|
+
const listProducts = useServerFn(listLocalProducts);
|
|
10
|
+
const saveAgreement = useServerFn(upsertLocalAgreement);
|
|
11
|
+
const saveSalesStrategy = useServerFn(upsertLocalSalesStrategy);
|
|
12
|
+
const savePriceGroup = useServerFn(upsertLocalPriceGroup);
|
|
13
|
+
const { data: prodData } = useQuery({
|
|
14
|
+
queryKey: ["local-products"],
|
|
15
|
+
queryFn: () => listProducts(),
|
|
16
|
+
enabled: open,
|
|
17
|
+
});
|
|
18
|
+
const products = prodData?.products ?? [];
|
|
19
|
+
const [source, setSource] = useState("agreement");
|
|
20
|
+
const [productId, setProductId] = useState("");
|
|
21
|
+
const [basePrice, setBasePrice] = useState("");
|
|
22
|
+
const [netPrice, setNetPrice] = useState("");
|
|
23
|
+
const [discountType, setDiscountType] = useState("percentage");
|
|
24
|
+
const [discountValue, setDiscountValue] = useState("");
|
|
25
|
+
const [minQuantity, setMinQuantity] = useState("0");
|
|
26
|
+
const [validFrom, setValidFrom] = useState("");
|
|
27
|
+
const [validUntil, setValidUntil] = useState("");
|
|
28
|
+
const [notes, setNotes] = useState("");
|
|
29
|
+
const [currency] = useState("EUR");
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!open)
|
|
32
|
+
return;
|
|
33
|
+
if (editing) {
|
|
34
|
+
setSource(editing.source);
|
|
35
|
+
setProductId(editing.product_id ?? "");
|
|
36
|
+
setBasePrice(editing.base_price != null ? String(editing.base_price) : "");
|
|
37
|
+
setNetPrice(editing.net_price != null ? String(editing.net_price) : "");
|
|
38
|
+
setDiscountType(editing.discount_type ?? "percentage");
|
|
39
|
+
setDiscountValue(editing.discount_value != null ? String(editing.discount_value) : "");
|
|
40
|
+
setMinQuantity(String(editing.min_quantity ?? 0));
|
|
41
|
+
setValidFrom(editing.valid_from ?? "");
|
|
42
|
+
setValidUntil(editing.valid_until ?? "");
|
|
43
|
+
setNotes("");
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
setSource("agreement");
|
|
47
|
+
setProductId("");
|
|
48
|
+
setBasePrice("");
|
|
49
|
+
setNetPrice("");
|
|
50
|
+
setDiscountValue("");
|
|
51
|
+
setDiscountType("percentage");
|
|
52
|
+
setMinQuantity("0");
|
|
53
|
+
setValidFrom("");
|
|
54
|
+
setValidUntil("");
|
|
55
|
+
setNotes("");
|
|
56
|
+
}
|
|
57
|
+
}, [open, editing]);
|
|
58
|
+
const save = useMutation({
|
|
59
|
+
mutationFn: async () => {
|
|
60
|
+
const common = {
|
|
61
|
+
id: editing?.source_id,
|
|
62
|
+
customer_id: customerId,
|
|
63
|
+
product_id: productId || null,
|
|
64
|
+
currency,
|
|
65
|
+
valid_from: validFrom || null,
|
|
66
|
+
valid_until: validUntil || null,
|
|
67
|
+
notes: notes || null,
|
|
68
|
+
};
|
|
69
|
+
if (source === "agreement") {
|
|
70
|
+
return saveAgreement({
|
|
71
|
+
data: {
|
|
72
|
+
...common,
|
|
73
|
+
base_price: basePrice ? Number(basePrice) : null,
|
|
74
|
+
net_price: Number(netPrice),
|
|
75
|
+
min_quantity: Number(minQuantity || 0),
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (source === "sales_strategy") {
|
|
80
|
+
return saveSalesStrategy({
|
|
81
|
+
data: {
|
|
82
|
+
...common,
|
|
83
|
+
discount_type: discountType,
|
|
84
|
+
discount_value: Number(discountValue),
|
|
85
|
+
min_quantity: Number(minQuantity || 0),
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return savePriceGroup({
|
|
90
|
+
data: {
|
|
91
|
+
...common,
|
|
92
|
+
discount_type: discountType,
|
|
93
|
+
discount_value: Number(discountValue),
|
|
94
|
+
min_quantity: Number(minQuantity || 0),
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
onSuccess: () => {
|
|
99
|
+
toast.success(editing ? "Korting bijgewerkt" : "Korting toegevoegd");
|
|
100
|
+
qc.invalidateQueries({ queryKey: ["local-discounts", customerId] });
|
|
101
|
+
onOpenChange(false);
|
|
102
|
+
},
|
|
103
|
+
onError: (err) => toast.error(err.message),
|
|
104
|
+
});
|
|
105
|
+
const canSave = (source === "agreement" ? !!netPrice : !!discountValue) && !save.isPending;
|
|
106
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: editing ? "Korting bewerken" : "Nieuwe korting" }) }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Bron" }), _jsxs(Select, { value: source, onValueChange: (v) => setSource(v), disabled: !!editing, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "agreement", children: "Contract (vaste nettoprijs)" }), _jsx(SelectItem, { value: "sales_strategy", children: "Kortingsregel (%/bedrag)" }), _jsx(SelectItem, { value: "price_group", children: "Staffelkorting (o.b.v. hoeveelheid)" })] })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Product" }), _jsxs(Select, { value: productId, onValueChange: setProductId, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Kies een product" }) }), _jsx(SelectContent, { children: products.map((p) => (_jsxs(SelectItem, { value: p.id, children: [p.product, p.sale_price != null ? ` — € ${Number(p.sale_price).toFixed(2)}` : ""] }, p.id))) })] })] }), source === "agreement" ? (_jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Basisprijs (optioneel)" }), _jsx(Input, { type: "number", step: "0.01", value: basePrice, onChange: (e) => setBasePrice(e.target.value) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Nettoprijs *" }), _jsx(Input, { type: "number", step: "0.01", value: netPrice, onChange: (e) => setNetPrice(e.target.value) })] })] })) : (_jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Type" }), _jsxs(Select, { value: discountType, onValueChange: (v) => setDiscountType(v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "percentage", children: "Percentage (%)" }), _jsx(SelectItem, { value: "amount", children: "Vast bedrag" })] })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Waarde *" }), _jsx(Input, { type: "number", step: "0.01", value: discountValue, onChange: (e) => setDiscountValue(e.target.value) })] })] })), _jsxs("div", { className: "grid grid-cols-3 gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Min. hoeveelheid" }), _jsx(Input, { type: "number", step: "1", value: minQuantity, onChange: (e) => setMinQuantity(e.target.value) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Geldig van" }), _jsx(Input, { type: "date", value: validFrom, onChange: (e) => setValidFrom(e.target.value) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Geldig tot" }), _jsx(Input, { type: "date", value: validUntil, onChange: (e) => setValidUntil(e.target.value) })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Notities" }), _jsx(Input, { value: notes, onChange: (e) => setNotes(e.target.value) })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Annuleren" }), _jsx(Button, { disabled: !canSave, onClick: () => save.mutate(), children: save.isPending ? "Opslaan…" : "Opslaan" })] })] }) }));
|
|
107
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalDiscountsTab.d.ts","sourceRoot":"","sources":["../../../src/components/klanten/LocalDiscountsTab.tsx"],"names":[],"mappings":"AAiDA,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,+BA2JvE"}
|
|
@@ -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
|
+
}
|