@flowselections/actie-mail-kwekers-erp-mathot 1.0.7 → 1.0.9
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/AanbiedingsmailtjePage.d.ts.map +1 -1
- package/dist-lib/components/AanbiedingsmailtjePage.js +135 -24
- package/dist-lib/components/ActiePage.d.ts.map +1 -1
- package/dist-lib/components/ActiePage.js +37 -8
- package/dist-lib/components/CampagneDetail.d.ts.map +1 -1
- package/dist-lib/components/CampagneDetail.js +10 -1
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +1 -2
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +9550 -1645
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +9550 -1645
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +9550 -1645
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +9771 -1655
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +20 -1
- package/dist-lib/lib/campaigns.functions.d.ts +48026 -8501
- package/dist-lib/lib/campaigns.functions.d.ts.map +1 -1
- package/dist-lib/lib/campaigns.functions.js +28 -27
- package/dist-lib/lib/public-offer.functions.d.ts.map +1 -1
- package/dist-lib/lib/public-offer.functions.js +37 -21
- package/dist-lib/lib/stats.functions.d.ts +19140 -3330
- package/dist-lib/lib/stats.functions.d.ts.map +1 -1
- package/dist-lib/lib/voorraad-service.d.ts +23 -0
- package/dist-lib/lib/voorraad-service.d.ts.map +1 -0
- package/dist-lib/lib/voorraad-service.js +31 -0
- package/package.json +4 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AanbiedingsmailtjePage.d.ts","sourceRoot":"","sources":["../../src/components/AanbiedingsmailtjePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AanbiedingsmailtjePage.d.ts","sourceRoot":"","sources":["../../src/components/AanbiedingsmailtjePage.tsx"],"names":[],"mappings":"AA0CA,wBAAgB,sBAAsB,gCAylBrC"}
|
|
@@ -5,6 +5,7 @@ import { useServerFn } from "@tanstack/react-start";
|
|
|
5
5
|
import { useNavigate } from "@tanstack/react-router";
|
|
6
6
|
import { Mail, Send, Search, X, Package, Users, Percent, Tag, List, BarChart3 } from "lucide-react";
|
|
7
7
|
import { createCampaign, sendCampaign } from "../lib/campaigns.functions";
|
|
8
|
+
import { createVoorraadStockMap, voorraadAvailableStock } from "../lib/voorraad-service";
|
|
8
9
|
export function AanbiedingsmailtjePage() {
|
|
9
10
|
const { user } = useAuth();
|
|
10
11
|
const navigate = useNavigate();
|
|
@@ -49,18 +50,130 @@ export function AanbiedingsmailtjePage() {
|
|
|
49
50
|
(async () => {
|
|
50
51
|
setLoading(true);
|
|
51
52
|
const sb = supabase;
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
// 1) Bepaal actieve Floriday-koppeling
|
|
54
|
+
const { data: activeConn } = await sb.rpc("get_active_floriday_connection_public");
|
|
55
|
+
const activeId = Array.isArray(activeConn) && activeConn.length > 0
|
|
56
|
+
? (activeConn[0]?.id ?? activeConn[0]?.connection_id ?? null)
|
|
57
|
+
: (activeConn?.id ?? activeConn?.connection_id ?? null);
|
|
58
|
+
// 2) Producten uit Floriday (gepubliceerd + concepten), klanten + instellingen
|
|
59
|
+
const cachePromise = activeId
|
|
60
|
+
? sb.from("floriday_trade_items_cache")
|
|
61
|
+
.select("floriday_id, data")
|
|
62
|
+
.eq("connection_id", activeId)
|
|
63
|
+
.eq("is_deleted", false)
|
|
64
|
+
.limit(1000)
|
|
65
|
+
: Promise.resolve({ data: [] });
|
|
66
|
+
const draftPromise = activeId
|
|
67
|
+
? sb.from("trade_item_drafts")
|
|
68
|
+
.select("id, data, updated_at")
|
|
69
|
+
.eq("connection_id", activeId)
|
|
70
|
+
.order("updated_at", { ascending: false })
|
|
71
|
+
.limit(1000)
|
|
72
|
+
: Promise.resolve({ data: [] });
|
|
73
|
+
const stockPromise = activeId
|
|
74
|
+
? sb.from("trade_item_stock")
|
|
75
|
+
.select("trade_item_key, physical_stock, reserved_stock, updated_at")
|
|
76
|
+
.eq("connection_id", activeId)
|
|
77
|
+
.limit(5000)
|
|
78
|
+
: Promise.resolve({ data: [] });
|
|
79
|
+
const [{ data: cacheRows }, { data: draftRows }, { data: stockRows }, { data: cs }, { data: extCs }, { data: settings }] = await Promise.all([
|
|
80
|
+
cachePromise,
|
|
81
|
+
draftPromise,
|
|
82
|
+
stockPromise,
|
|
54
83
|
sb.from("customers").select("id, company_name, email, customer_class, country").not("email", "is", null).order("company_name").limit(1000),
|
|
55
|
-
sb.from("
|
|
84
|
+
sb.from("external_customers_grouped").select("group_key, display_name, email, country, is_active").not("email", "is", null).eq("is_active", true).limit(2000),
|
|
85
|
+
sb.from("offer_settings").select("default_subject, default_intro, default_sticker_cost, show_customer_classes").maybeSingle(),
|
|
56
86
|
]);
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
const stockMap = createVoorraadStockMap((Array.isArray(stockRows) ? stockRows : []));
|
|
88
|
+
const stockFor = (key) => {
|
|
89
|
+
const s = stockMap.get(key);
|
|
90
|
+
return voorraadAvailableStock(s);
|
|
91
|
+
};
|
|
92
|
+
const pickName = (n) => {
|
|
93
|
+
if (!n)
|
|
94
|
+
return "";
|
|
95
|
+
if (typeof n === "string")
|
|
96
|
+
return n;
|
|
97
|
+
return n.nl || n.en || n.de || Object.values(n)[0] || "";
|
|
98
|
+
};
|
|
99
|
+
const pickImage = (d) => {
|
|
100
|
+
const photos = Array.isArray(d?.photos) ? d.photos : [];
|
|
101
|
+
const primary = photos.find((p) => p?.primary || p?.isPrimary) ?? photos[0];
|
|
102
|
+
if (primary?.url)
|
|
103
|
+
return primary.url;
|
|
104
|
+
if (Array.isArray(d?.images) && d.images[0])
|
|
105
|
+
return d.images[0].url ?? d.images[0].previewUrl ?? null;
|
|
106
|
+
if (Array.isArray(d?.imageUrls) && d.imageUrls[0])
|
|
107
|
+
return d.imageUrls[0];
|
|
108
|
+
return null;
|
|
109
|
+
};
|
|
110
|
+
const pickPacking = (d) => {
|
|
111
|
+
const cfgs = Array.isArray(d?.packingConfigurations) ? d.packingConfigurations : [];
|
|
112
|
+
const primary = cfgs.find((c) => c?.primary) ?? cfgs[0];
|
|
113
|
+
if (!primary)
|
|
114
|
+
return { plants_per_crate: null, belading: null };
|
|
115
|
+
const ppc = Number(primary.piecesPerPackage);
|
|
116
|
+
const perLayer = Number(primary.packagesPerLayer);
|
|
117
|
+
const layers = Number(primary.layersPerLoadCarrier);
|
|
118
|
+
const parts = [ppc, perLayer, layers].filter((n) => Number.isFinite(n) && n > 0);
|
|
119
|
+
return {
|
|
120
|
+
plants_per_crate: Number.isFinite(ppc) && ppc > 0 ? ppc : null,
|
|
121
|
+
belading: parts.length === 3 ? `${ppc}x${perLayer}x${layers}` : null,
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
const published = (cacheRows ?? []).map((r) => {
|
|
125
|
+
const d = r.data ?? {};
|
|
126
|
+
const packing = pickPacking(d);
|
|
127
|
+
return {
|
|
128
|
+
id: r.floriday_id,
|
|
129
|
+
product: pickName(d.tradeItemName) || pickName(d.name) || pickName(d.vbnName) || (d.botanicalNames?.[0] ?? "(naamloos)"),
|
|
130
|
+
sale_price: null,
|
|
131
|
+
quantity: stockFor(r.floriday_id),
|
|
132
|
+
image_url: pickImage(d),
|
|
133
|
+
barcode: d.supplierArticleCode ?? d.articleCode ?? d.gtin ?? d.articleGtin ?? d.tradeItemReference ?? "",
|
|
134
|
+
plants_per_crate: packing.plants_per_crate,
|
|
135
|
+
belading: packing.belading,
|
|
136
|
+
is_draft: false,
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
const drafts = (draftRows ?? []).map((r) => {
|
|
140
|
+
const d = r.data ?? {};
|
|
141
|
+
const firstImage = Array.isArray(d.images) && d.images[0] ? d.images[0] : null;
|
|
142
|
+
const packing = pickPacking(d);
|
|
143
|
+
return {
|
|
144
|
+
id: `local:${r.id}`,
|
|
145
|
+
product: d.name || d.vbnName || "(naamloos)",
|
|
146
|
+
sale_price: null,
|
|
147
|
+
quantity: stockFor(`draft:${r.id}`),
|
|
148
|
+
image_url: firstImage?.url ?? firstImage?.previewUrl ?? null,
|
|
149
|
+
barcode: d.articleCode ?? d.gtin ?? "",
|
|
150
|
+
plants_per_crate: packing.plants_per_crate,
|
|
151
|
+
belading: packing.belading,
|
|
152
|
+
is_draft: true,
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
const merged = [
|
|
156
|
+
...drafts,
|
|
157
|
+
...published.sort((a, b) => a.product.localeCompare(b.product)),
|
|
158
|
+
];
|
|
159
|
+
setProducts(merged);
|
|
160
|
+
const localList = (cs ?? []).map((c) => ({
|
|
161
|
+
id: c.id, company_name: c.company_name, email: c.email, customer_class: c.customer_class, country: c.country, source: "local",
|
|
162
|
+
}));
|
|
163
|
+
const seenEmails = new Set(localList.map((c) => (c.email ?? "").toLowerCase()).filter(Boolean));
|
|
164
|
+
const extList = (extCs ?? [])
|
|
165
|
+
.filter((r) => r.email && !seenEmails.has(String(r.email).toLowerCase()))
|
|
166
|
+
.map((r) => ({
|
|
167
|
+
id: `ext:${r.group_key}`,
|
|
168
|
+
company_name: r.display_name ?? "(naamloos)",
|
|
169
|
+
email: r.email,
|
|
170
|
+
customer_class: null,
|
|
171
|
+
country: r.country ?? null,
|
|
172
|
+
source: "ext",
|
|
173
|
+
}));
|
|
174
|
+
const mergedCustomers = [...localList, ...extList].sort((a, b) => (a.company_name ?? "").localeCompare(b.company_name ?? ""));
|
|
175
|
+
setCustomers(mergedCustomers);
|
|
59
176
|
if (settings) {
|
|
60
|
-
if (settings.from_name)
|
|
61
|
-
setFromName(settings.from_name);
|
|
62
|
-
if (settings.from_email)
|
|
63
|
-
setFromEmail(settings.from_email);
|
|
64
177
|
if (settings.default_subject)
|
|
65
178
|
setSubject(settings.default_subject);
|
|
66
179
|
if (settings.default_intro)
|
|
@@ -71,28 +184,30 @@ export function AanbiedingsmailtjePage() {
|
|
|
71
184
|
if (typeof settings.show_customer_classes === "boolean")
|
|
72
185
|
setShowCustomerClasses(settings.show_customer_classes);
|
|
73
186
|
}
|
|
187
|
+
if (!activeId) {
|
|
188
|
+
toast.error("Geen actieve Floriday-koppeling — stel deze in via de Voorraad Module");
|
|
189
|
+
}
|
|
74
190
|
setLoading(false);
|
|
75
191
|
})();
|
|
76
192
|
}, []);
|
|
77
193
|
const addProduct = (p) => {
|
|
78
194
|
if (selProducts.find((sp) => sp.product_id === p.id))
|
|
79
195
|
return;
|
|
80
|
-
const price = Number(p.sale_price ?? 0);
|
|
81
196
|
setSelProducts((prev) => [...prev, {
|
|
82
197
|
product_id: p.id,
|
|
83
198
|
product_name: p.product,
|
|
84
199
|
description: "",
|
|
85
200
|
image_url: p.image_url,
|
|
86
|
-
normal_price:
|
|
87
|
-
discount_price:
|
|
201
|
+
normal_price: 0,
|
|
202
|
+
discount_price: 0,
|
|
88
203
|
available_stock: p.quantity ?? 0,
|
|
89
|
-
plants_per_crate: 10,
|
|
90
|
-
belading: "",
|
|
204
|
+
plants_per_crate: p.plants_per_crate ?? 10,
|
|
205
|
+
belading: p.belading ?? "",
|
|
91
206
|
barcode: p.barcode ?? "",
|
|
92
207
|
crate_price: 0,
|
|
93
208
|
sticker_cost: null,
|
|
94
209
|
sticker_available: true,
|
|
95
|
-
tiers: [{ min_crates: 1, price_per_crate:
|
|
210
|
+
tiers: [{ min_crates: 1, price_per_crate: 0 }],
|
|
96
211
|
}]);
|
|
97
212
|
setProductSearch("");
|
|
98
213
|
};
|
|
@@ -162,16 +277,12 @@ export function AanbiedingsmailtjePage() {
|
|
|
162
277
|
toast.error("Selecteer minimaal één klant");
|
|
163
278
|
return;
|
|
164
279
|
}
|
|
165
|
-
if (!fromEmail) {
|
|
166
|
-
toast.error("Vul een afzender e-mailadres in");
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
280
|
setBusy(true);
|
|
170
281
|
try {
|
|
171
282
|
const recipients = customers
|
|
172
283
|
.filter((c) => selCustomers.has(c.id) && c.email)
|
|
173
284
|
.map((c) => ({
|
|
174
|
-
customer_id: c.id,
|
|
285
|
+
customer_id: c.id.startsWith("ext:") ? null : c.id,
|
|
175
286
|
recipient_name: c.company_name,
|
|
176
287
|
recipient_email: c.email,
|
|
177
288
|
}));
|
|
@@ -197,10 +308,10 @@ export function AanbiedingsmailtjePage() {
|
|
|
197
308
|
setBusy(false);
|
|
198
309
|
}
|
|
199
310
|
};
|
|
200
|
-
const filteredProducts = products.filter((p) =>
|
|
311
|
+
const filteredProducts = products.filter((p) => p.product.toLowerCase().includes(productSearch.toLowerCase()));
|
|
201
312
|
if (loading)
|
|
202
313
|
return _jsxs("div", { className: "p-6 space-y-4", children: [_jsx(Skeleton, { className: "h-32 w-full" }), _jsx(Skeleton, { className: "h-64 w-full" })] });
|
|
203
|
-
return (_jsxs("main", { className: "p-6 pb-28 space-y-6", children: [_jsxs("div", { className: "flex items-start justify-between gap-4 flex-wrap", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Tag, { className: "h-6 w-6 text-primary" }), _jsx("h1", { className: "text-2xl font-bold", children: "Acties & Promoties" })] }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Maak promoties en verstuur naar klanten" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", onClick: () => navigate({ to: "/aanbiedingsmailtje/overzicht" }), children: [_jsx(List, { className: "h-4 w-4 mr-2" }), "Overzicht"] }), _jsxs(Button, { variant: "outline", onClick: () => navigate({ to: "/aanbiedingsmailtje/rapportage" }), children: [_jsx(BarChart3, { className: "h-4 w-4 mr-2" }), "Rapportage"] })] })] }), _jsxs("div", { className: "grid gap-6 xl:grid-cols-2", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Package, { className: "h-5 w-5" }), _jsx(CardTitle, { children: "Producten Selecteren" })] }), _jsx(CardDescription, { children: "Kies producten en stel actieprijzen in" })] }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "pl-9", placeholder: "Zoek product...", value: productSearch, onChange: (e) => setProductSearch(e.target.value) })] }), productSearch && (_jsx("div", { className: "max-h-40 overflow-y-auto border rounded-md", children: filteredProducts.slice(0, 20).map((p) => (_jsxs("button", { onClick: () => addProduct(p), className: "w-full text-left px-3 py-2 hover:bg-muted text-sm", children: [p.product, " ",
|
|
314
|
+
return (_jsxs("main", { className: "p-6 pb-28 space-y-6", children: [_jsxs("div", { className: "flex items-start justify-between gap-4 flex-wrap", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Tag, { className: "h-6 w-6 text-primary" }), _jsx("h1", { className: "text-2xl font-bold", children: "Acties & Promoties" })] }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Maak promoties en verstuur naar klanten" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", onClick: () => navigate({ to: "/aanbiedingsmailtje/overzicht" }), children: [_jsx(List, { className: "h-4 w-4 mr-2" }), "Overzicht"] }), _jsxs(Button, { variant: "outline", onClick: () => navigate({ to: "/aanbiedingsmailtje/rapportage" }), children: [_jsx(BarChart3, { className: "h-4 w-4 mr-2" }), "Rapportage"] })] })] }), _jsxs("div", { className: "grid gap-6 xl:grid-cols-2", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Package, { className: "h-5 w-5" }), _jsx(CardTitle, { children: "Producten Selecteren" })] }), _jsx(CardDescription, { children: "Kies producten en stel actieprijzen in" })] }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "pl-9", placeholder: "Zoek product...", value: productSearch, onChange: (e) => setProductSearch(e.target.value) })] }), productSearch && (_jsx("div", { className: "max-h-40 overflow-y-auto border rounded-md", children: filteredProducts.slice(0, 20).map((p) => (_jsxs("button", { onClick: () => addProduct(p), className: "w-full text-left px-3 py-2 hover:bg-muted text-sm", children: [p.product, " ", _jsx("span", { className: "text-muted-foreground", children: p.is_draft ? "· concept" : `· voorraad ${p.quantity ?? 0}` })] }, p.id))) })), _jsxs("div", { className: "text-sm font-medium", children: ["Geselecteerde producten (", selProducts.length, ")"] }), selProducts.length === 0 ? (_jsx("div", { className: "text-sm text-muted-foreground py-6", children: "Geen producten geselecteerd" })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: "Snelle korting:" }), [10, 15, 20, 25, 30].map((p) => (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => applyDiscount(p), children: [_jsx(Percent, { className: "h-3 w-3 mr-1" }), p, "%"] }, p)))] }), _jsxs("div", { className: "flex flex-wrap gap-2 items-center rounded-md border bg-muted/30 p-2", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: "Stickeropdruk \u2014 \u00E9\u00E9n prijs voor \u00E1lle producten: \u20AC" }), _jsx(Input, { type: "number", step: "0.01", placeholder: "0,00", className: "w-28 h-8", value: bulkPrice, onChange: (e) => setBulkPrice(e.target.value) }), _jsxs("div", { className: "flex items-center gap-2 ml-2", children: [_jsx(Switch, { id: "bulk-sticker-toggle", checked: bulkStickerOn, onCheckedChange: (checked) => {
|
|
204
315
|
setBulkStickerOn(checked);
|
|
205
316
|
if (!checked) {
|
|
206
317
|
setSelProducts((prev) => prev.map((p) => ({ ...p, sticker_cost: null })));
|
|
@@ -228,12 +339,12 @@ export function AanbiedingsmailtjePage() {
|
|
|
228
339
|
return (_jsxs("div", { className: "border rounded-md p-3 space-y-3 bg-muted/30", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsxs("div", { children: [_jsx("div", { className: "font-medium text-sm", children: p.product_name }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Originele prijs: \u20AC ", p.normal_price.toFixed(2)] })] }), _jsx(Button, { variant: "ghost", size: "icon", onClick: () => removeProduct(p.product_id), children: _jsx(X, { className: "h-4 w-4" }) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: "text-xs w-24 shrink-0", children: "Planten/fust:" }), _jsx(Input, { type: "number", value: p.plants_per_crate, onChange: (e) => updateProd(p.product_id, { plants_per_crate: Number(e.target.value) }) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: "text-xs w-20 shrink-0", children: "Belading:" }), _jsx(Input, { placeholder: "AxBxC", value: p.belading, onChange: (e) => updateProd(p.product_id, { belading: e.target.value }) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: "text-xs w-24 shrink-0", children: "Barcode:" }), _jsx(Input, { value: p.barcode, onChange: (e) => updateProd(p.product_id, { barcode: e.target.value }) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: "text-xs w-20 shrink-0", children: "Fustprijs: \u20AC" }), _jsx(Input, { type: "number", step: "0.01", value: p.crate_price, onChange: (e) => updateProd(p.product_id, { crate_price: Number(e.target.value) }) })] })] }), _jsxs("div", { className: "flex items-center gap-2 border-t pt-2", children: [_jsx(Label, { className: "text-xs", children: "Stickeropdruk beschikbaar:" }), _jsx(Button, { type: "button", size: "sm", variant: p.sticker_available ? "default" : "outline", onClick: () => updateProd(p.product_id, { sticker_available: true }), children: "Ja" }), _jsx(Button, { type: "button", size: "sm", variant: !p.sticker_available ? "default" : "outline", onClick: () => updateProd(p.product_id, { sticker_available: false }), children: "Nee" })] }), _jsxs("div", { className: "space-y-2 border-t pt-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs font-medium", children: "Prijs aftuin ex. Fust vanaf .." }), _jsx(Button, { variant: "outline", size: "sm", onClick: addTier, children: "+ Staffel" })] }), p.tiers.map((t, idx) => {
|
|
229
340
|
const pct = p.normal_price > 0 ? Math.round((1 - t.price_per_crate / p.normal_price) * 100) : 0;
|
|
230
341
|
return (_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: "Vanaf" }), _jsx(Input, { type: "number", className: "w-20", value: t.min_crates, onChange: (e) => updateTier(idx, { min_crates: Number(e.target.value) }) }), _jsx("span", { className: "text-xs text-muted-foreground", children: "fust(en): \u20AC" }), _jsx(Input, { type: "number", step: "0.01", className: "w-24", value: t.price_per_crate, onChange: (e) => updateTier(idx, { price_per_crate: Number(e.target.value) }) }), _jsxs("span", { className: `text-xs font-medium ${pct > 0 ? "text-destructive" : "text-muted-foreground"}`, children: ["(", pct, "%)"] }), p.tiers.length > 1 && (_jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => removeTier(idx), children: _jsx(X, { className: "h-3 w-3" }) }))] }, idx));
|
|
231
|
-
})] }),
|
|
342
|
+
})] }), _jsx(Textarea, { placeholder: "Omschrijving (optioneel)", rows: 2, value: p.description, onChange: (e) => updateProd(p.product_id, { description: e.target.value }) })] }, p.product_id));
|
|
232
343
|
}) })] }))] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Users, { className: "h-5 w-5" }), _jsx(CardTitle, { children: "Klanten Selecteren" })] }), _jsx(CardDescription, { children: "Kies klanten om de actie naar te versturen" })] }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "pl-9", placeholder: "Zoek klant...", value: customerSearch, onChange: (e) => setCustomerSearch(e.target.value) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: allVisibleSelected, onChange: toggleAllVisible }), "Selecteer alle klanten met email"] }), _jsxs(Badge, { variant: "secondary", children: [selCustomers.size, " geselecteerd"] })] }), showCustomerClasses && (_jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground", children: "Selecteer op klantgroep" }), _jsx("div", { className: "flex flex-wrap gap-2", children: classGroups.map((g) => {
|
|
233
344
|
const allSel = g.customers.length > 0 && g.customers.every((c) => selCustomers.has(c.id));
|
|
234
345
|
return (_jsxs(Button, { type: "button", variant: allSel ? "default" : "outline", size: "sm", onClick: () => toggleClass(g.letter), className: "gap-2", children: ["Klasse ", g.letter, _jsx(Badge, { variant: "secondary", className: "px-1.5 py-0 text-xs", children: g.customers.length })] }, g.letter));
|
|
235
346
|
}) })] })), _jsx(Separator, {}), _jsx("div", { className: "max-h-[500px] overflow-y-auto space-y-2 pr-1", children: filteredCustomers.slice(0, 500).map((c) => {
|
|
236
347
|
const checked = selCustomers.has(c.id);
|
|
237
|
-
return (_jsxs("button", { onClick: () => toggleCustomer(c.id), className: `w-full text-left p-3 rounded-md border hover:bg-muted text-sm flex items-center gap-3 ${checked ? "bg-primary/5 border-primary/40" : ""}`, children: [_jsx("input", { type: "checkbox", checked: checked, readOnly: true }), _jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
348
|
+
return (_jsxs("button", { onClick: () => toggleCustomer(c.id), className: `w-full text-left p-3 rounded-md border hover:bg-muted text-sm flex items-center gap-3 ${checked ? "bg-primary/5 border-primary/40" : ""}`, children: [_jsx("input", { type: "checkbox", checked: checked, readOnly: true }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "font-medium truncate flex items-center gap-2", children: [_jsx("span", { className: "truncate", children: c.company_name }), c.source === "ext" && _jsx(Badge, { variant: "outline", className: "text-[10px] px-1.5 py-0", children: "Floriday" })] }), _jsx("div", { className: "text-xs text-muted-foreground truncate", children: c.email })] }), c.customer_class && _jsx(Badge, { variant: "secondary", children: c.customer_class })] }, c.id));
|
|
238
349
|
}) })] })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "h-5 w-5" }), _jsx(CardTitle, { children: "Email Inhoud" })] }), _jsx(CardDescription, { children: "Pas het onderwerp en de boodschap aan" })] }), _jsxs(CardContent, { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Onderwerp" }), _jsx(Input, { value: subject, onChange: (e) => setSubject(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Bericht" }), _jsx(Textarea, { value: intro, onChange: (e) => setIntro(e.target.value), rows: 3 })] }), _jsxs("div", { className: "space-y-2 md:col-span-2 max-w-xs", children: [_jsx(Label, { children: "Kosten opdrukken eigen sticker (\u20AC per stuk)" }), _jsx(Input, { type: "number", step: "0.01", placeholder: "0,00", value: bulkPrice, onChange: (e) => setBulkPrice(e.target.value) })] }), _jsxs("div", { className: "space-y-2 md:col-span-2 hidden", children: [_jsx(Label, { children: "Naam (intern)" }), _jsx(Input, { value: name, onChange: (e) => setName(e.target.value) }), _jsx(Label, { children: "Afzendernaam" }), _jsx(Input, { value: fromName, onChange: (e) => setFromName(e.target.value) }), _jsx(Label, { children: "Afzender e-mail" }), _jsx(Input, { type: "email", value: fromEmail, onChange: (e) => setFromEmail(e.target.value) })] })] })] }), _jsx("div", { className: "fixed bottom-0 left-0 right-0 z-30 border-t bg-background/95 backdrop-blur px-6 py-3", children: _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("div", { className: "font-semibold", children: "Samenvatting" }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [selProducts.length, " product(en) \u2022 ", selCustomers.size, " klant(en)"] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", disabled: busy, onClick: () => handleSave(false), children: "Opslaan als concept" }), _jsxs(Button, { disabled: busy || selProducts.length === 0 || selCustomers.size === 0, onClick: () => handleSave(true), children: [_jsx(Send, { className: "h-4 w-4 mr-2" }), busy ? "Bezig..." : "Actie Versturen"] })] })] }) })] }));
|
|
239
350
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActiePage.d.ts","sourceRoot":"","sources":["../../src/components/ActiePage.tsx"],"names":[],"mappings":"AAqCA,wBAAgB,SAAS,
|
|
1
|
+
{"version":3,"file":"ActiePage.d.ts","sourceRoot":"","sources":["../../src/components/ActiePage.tsx"],"names":[],"mappings":"AAqCA,wBAAgB,SAAS,gCAoexB"}
|
|
@@ -83,19 +83,46 @@ export function ActiePage() {
|
|
|
83
83
|
}
|
|
84
84
|
const safeProducts = Array.isArray(data?.products) ? data.products : [];
|
|
85
85
|
const lineFor = (p) => {
|
|
86
|
-
const stockPlants = Math.max(0, Number(p.live_stock ??
|
|
86
|
+
const stockPlants = Math.max(0, Number(p.live_stock ?? 0));
|
|
87
87
|
const ppc = Math.max(1, Math.floor(Number(p.plants_per_crate ?? 1) || 1));
|
|
88
88
|
const maxCrates = Math.floor(stockPlants / ppc);
|
|
89
89
|
const soldOut = maxCrates <= 0;
|
|
90
90
|
const crates = Math.max(0, Math.floor(qty[p.id] ?? 0));
|
|
91
91
|
const plants = crates * ppc;
|
|
92
|
-
|
|
92
|
+
// Prijsprioriteit: (1) tier-prijs uit actie-e-mail, (2) discount_price uit e-mail,
|
|
93
|
+
// (3) standaardprijs uit artikelbeheer. De e-mailprijs is ALTIJD leidend.
|
|
94
|
+
const tiers = Array.isArray(p.tiers)
|
|
95
|
+
? [...p.tiers].map((t) => ({ min_crates: Number(t.min_crates), price_per_crate: Number(t.price_per_crate) }))
|
|
96
|
+
.sort((a, b) => a.min_crates - b.min_crates)
|
|
97
|
+
: [];
|
|
98
|
+
let unit = 0;
|
|
99
|
+
let cratePrice = 0;
|
|
100
|
+
let priceSource = "normal";
|
|
101
|
+
if (tiers.length > 0) {
|
|
102
|
+
const applicable = [...tiers].reverse().find((t) => crates >= t.min_crates) ?? tiers[0];
|
|
103
|
+
cratePrice = applicable.price_per_crate;
|
|
104
|
+
unit = cratePrice / ppc;
|
|
105
|
+
priceSource = "tier";
|
|
106
|
+
}
|
|
107
|
+
else if (Number(p.discount_price) > 0) {
|
|
108
|
+
unit = Number(p.discount_price);
|
|
109
|
+
cratePrice = unit * ppc;
|
|
110
|
+
priceSource = "discount";
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
unit = Number(p.normal_price ?? 0);
|
|
114
|
+
cratePrice = unit * ppc;
|
|
115
|
+
priceSource = "normal";
|
|
116
|
+
}
|
|
117
|
+
const priceSourceLabel = priceSource === "tier" ? "Prijs uit actie-e-mail"
|
|
118
|
+
: priceSource === "discount" ? "Actieprijs uit e-mail"
|
|
119
|
+
: "Standaardprijs artikelbeheer";
|
|
93
120
|
const stickerCost = Number(p.sticker_cost ?? 0);
|
|
94
121
|
const stickerAvail = p.sticker_available !== false;
|
|
95
122
|
const stickerOn = stickerAvail && !!sticker[p.id];
|
|
96
123
|
const productSubtotal = plants * unit;
|
|
97
124
|
const stickerSubtotal = stickerOn ? plants * stickerCost : 0;
|
|
98
|
-
return { q: crates, plants, ppc, unit, stickerCost, stickerAvail, stickerOn, productSubtotal, stickerSubtotal, total: productSubtotal + stickerSubtotal, stock: stockPlants, maxCrates, soldOut };
|
|
125
|
+
return { q: crates, plants, ppc, unit, cratePrice, priceSource, priceSourceLabel, tiers, stickerCost, stickerAvail, stickerOn, productSubtotal, stickerSubtotal, total: productSubtotal + stickerSubtotal, stock: stockPlants, maxCrates, soldOut };
|
|
99
126
|
};
|
|
100
127
|
const totalAmount = safeProducts.reduce((s, p) => s + lineFor(p).total, 0);
|
|
101
128
|
const hasItems = safeProducts.some((p) => (qty[p.id] ?? 0) > 0);
|
|
@@ -108,7 +135,7 @@ export function ActiePage() {
|
|
|
108
135
|
return {
|
|
109
136
|
product_id: p.id,
|
|
110
137
|
product_name: p.product_name,
|
|
111
|
-
quantity: l.
|
|
138
|
+
quantity: l.plants,
|
|
112
139
|
unit_price: l.unit,
|
|
113
140
|
sticker: l.stickerOn,
|
|
114
141
|
sticker_unit_price: l.stickerOn ? l.stickerCost : 0,
|
|
@@ -157,12 +184,14 @@ export function ActiePage() {
|
|
|
157
184
|
safeProducts.forEach((p) => { next[p.id] = false; });
|
|
158
185
|
setSticker(next);
|
|
159
186
|
}, className: "text-xs font-semibold bg-white text-blue-700 border border-blue-300 rounded px-3 py-1.5 hover:bg-blue-50", children: "Alles uit" })] })] })), _jsx("div", { className: "space-y-4", children: safeProducts.map((p) => {
|
|
160
|
-
const normal = Number(p.normal_price ?? 0);
|
|
161
|
-
const price = Number(p.discount_price ?? 0);
|
|
162
|
-
const showStrike = normal > price;
|
|
163
187
|
const l = lineFor(p);
|
|
188
|
+
const normal = Number(p.normal_price ?? 0);
|
|
189
|
+
const price = l.cratePrice > 0 ? l.cratePrice : Number(p.discount_price ?? 0);
|
|
190
|
+
const showStrike = normal > 0 && normal > price && price > 0;
|
|
164
191
|
const currentQty = l.q;
|
|
165
|
-
return (_jsxs("div", { className: `bg-white rounded-xl border shadow-sm overflow-hidden ${l.soldOut ? "border-slate-200 opacity-75" : "border-slate-200"}`, children: [_jsxs("div", { className: "p-4 flex gap-4", children: [_jsxs("div", { className: "shrink-0 relative", children: [p.image_url ? (_jsx("img", { src: p.image_url, alt: p.product_name, className: `w-24 h-24 rounded-lg object-cover border border-slate-200 bg-slate-50 ${l.soldOut ? "grayscale" : ""}` })) : (_jsx("div", { className: `w-24 h-24 rounded-lg border border-slate-200 bg-green-50 grid place-items-center overflow-hidden ${l.soldOut ? "grayscale" : ""}`, children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 96 96", className: "w-full h-full", children: [_jsx("path", { d: "M48 60 Q46 75 44 86", stroke: "#16a34a", strokeWidth: "2.5", fill: "none", strokeLinecap: "round" }), _jsx("path", { d: "M48 72 Q40 70 36 64 Q42 66 48 72", fill: "#22c55e" }), _jsx("path", { d: "M48 78 Q56 76 60 70 Q54 72 48 78", fill: "#22c55e" }), _jsxs("g", { transform: "translate(48 40)", children: [_jsx("ellipse", { cx: "0", cy: "-14", rx: "9", ry: "14", fill: "#f9a8d4" }), _jsx("ellipse", { cx: "13.3", cy: "-4.3", rx: "9", ry: "14", fill: "#f472b6", transform: "rotate(72)" }), _jsx("ellipse", { cx: "8.2", cy: "11.3", rx: "9", ry: "14", fill: "#ec4899", transform: "rotate(144)" }), _jsx("ellipse", { cx: "-8.2", cy: "11.3", rx: "9", ry: "14", fill: "#f472b6", transform: "rotate(216)" }), _jsx("ellipse", { cx: "-13.3", cy: "-4.3", rx: "9", ry: "14", fill: "#f9a8d4", transform: "rotate(288)" }), _jsx("circle", { cx: "0", cy: "0", r: "6", fill: "#fbbf24" }), _jsx("circle", { cx: "0", cy: "0", r: "3", fill: "#f59e0b" })] })] }) })), l.soldOut && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: "bg-red-600 text-white text-xs font-bold px-2 py-1 rounded rotate-[-8deg] shadow", children: "UITVERKOCHT" }) }))] }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-bold text-slate-900 truncate", children: p.product_name }), p.plants_per_crate ? (_jsxs("div", { className: "text-sm text-slate-500", children: [p.plants_per_crate, " planten/fust"] })) : null, _jsxs("div", { className: "mt-2 flex items-baseline gap-2 flex-wrap", children: [showStrike && (_jsx("span", { className: "text-slate-400 line-through text-sm", children: fmtEuro(normal) })), _jsx("span", { className: "text-green-700 font-bold text-lg", children: fmtEuro(price) })
|
|
192
|
+
return (_jsxs("div", { className: `bg-white rounded-xl border shadow-sm overflow-hidden ${l.soldOut ? "border-slate-200 opacity-75" : "border-slate-200"}`, children: [_jsxs("div", { className: "p-4 flex gap-4", children: [_jsxs("div", { className: "shrink-0 relative", children: [p.image_url ? (_jsx("img", { src: p.image_url, alt: p.product_name, className: `w-24 h-24 rounded-lg object-cover border border-slate-200 bg-slate-50 ${l.soldOut ? "grayscale" : ""}` })) : (_jsx("div", { className: `w-24 h-24 rounded-lg border border-slate-200 bg-green-50 grid place-items-center overflow-hidden ${l.soldOut ? "grayscale" : ""}`, children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 96 96", className: "w-full h-full", children: [_jsx("path", { d: "M48 60 Q46 75 44 86", stroke: "#16a34a", strokeWidth: "2.5", fill: "none", strokeLinecap: "round" }), _jsx("path", { d: "M48 72 Q40 70 36 64 Q42 66 48 72", fill: "#22c55e" }), _jsx("path", { d: "M48 78 Q56 76 60 70 Q54 72 48 78", fill: "#22c55e" }), _jsxs("g", { transform: "translate(48 40)", children: [_jsx("ellipse", { cx: "0", cy: "-14", rx: "9", ry: "14", fill: "#f9a8d4" }), _jsx("ellipse", { cx: "13.3", cy: "-4.3", rx: "9", ry: "14", fill: "#f472b6", transform: "rotate(72)" }), _jsx("ellipse", { cx: "8.2", cy: "11.3", rx: "9", ry: "14", fill: "#ec4899", transform: "rotate(144)" }), _jsx("ellipse", { cx: "-8.2", cy: "11.3", rx: "9", ry: "14", fill: "#f472b6", transform: "rotate(216)" }), _jsx("ellipse", { cx: "-13.3", cy: "-4.3", rx: "9", ry: "14", fill: "#f9a8d4", transform: "rotate(288)" }), _jsx("circle", { cx: "0", cy: "0", r: "6", fill: "#fbbf24" }), _jsx("circle", { cx: "0", cy: "0", r: "3", fill: "#f59e0b" })] })] }) })), l.soldOut && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: "bg-red-600 text-white text-xs font-bold px-2 py-1 rounded rotate-[-8deg] shadow", children: "UITVERKOCHT" }) }))] }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-bold text-slate-900 truncate", children: p.product_name }), p.plants_per_crate ? (_jsxs("div", { className: "text-sm text-slate-500", children: [p.plants_per_crate, " planten/fust"] })) : null, _jsxs("div", { className: "mt-2 flex items-baseline gap-2 flex-wrap", children: [showStrike && (_jsx("span", { className: "text-slate-400 line-through text-sm", children: fmtEuro(normal) })), _jsx("span", { className: "text-green-700 font-bold text-lg", children: fmtEuro(price) }), _jsx("span", { className: "text-xs text-slate-500", children: "per fust" })] }), l.tiers.length > 0 && (_jsx("div", { className: "mt-1 flex flex-wrap gap-1", children: l.tiers.map((t) => (_jsxs("span", { className: `text-[11px] px-2 py-0.5 rounded border ${l.cratePrice === t.price_per_crate && l.priceSource === "tier"
|
|
193
|
+
? "bg-green-100 border-green-300 text-green-800 font-semibold"
|
|
194
|
+
: "bg-slate-50 border-slate-200 text-slate-600"}`, children: ["\u2265 ", t.min_crates, " fust: ", fmtEuro(t.price_per_crate)] }, t.min_crates))) })), _jsx("div", { className: "mt-2", children: l.soldOut ? (_jsx("span", { className: "inline-flex items-center gap-1 text-xs font-semibold bg-red-100 text-red-800 border border-red-200 rounded px-2 py-1", children: "\u25CF Uitverkocht" })) : l.stock <= 10 ? (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs font-semibold bg-amber-100 text-amber-800 border border-amber-200 rounded px-2 py-1", children: ["\u25CF Nog ", l.stock, " op voorraad"] })) : (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs font-semibold bg-green-100 text-green-800 border border-green-200 rounded px-2 py-1", children: ["\u25CF Op voorraad: ", l.stock, " stuks"] })) }), !l.soldOut && l.stickerAvail && (_jsxs("label", { className: "mt-2 flex items-start gap-2 text-xs text-blue-900 bg-blue-50 border-l-4 border-blue-400 rounded px-2 py-2 cursor-pointer select-none", children: [_jsx("input", { type: "checkbox", className: "mt-0.5", checked: l.stickerOn, onChange: (e) => setSticker({ ...sticker, [p.id]: e.target.checked }) }), _jsxs("span", { children: ["Stickeropdruk toevoegen", l.stickerCost > 0 ? _jsxs(_Fragment, { children: [" \u2014 ", _jsx("strong", { children: fmtEuro(l.stickerCost) }), " per stuk"] }) : _jsxs(_Fragment, { children: [" \u2014 ", _jsx("strong", { children: "geen meerprijs" })] })] })] })), !l.soldOut && !l.stickerAvail && (_jsx("div", { className: "mt-2 text-xs text-slate-500 bg-slate-50 border-l-4 border-slate-300 rounded px-2 py-2", children: "Stickeropdruk niet beschikbaar voor dit product" })), !l.soldOut && currentQty > 0 && (_jsxs("div", { className: "mt-3 text-xs text-slate-600 space-y-0.5 border-t border-slate-100 pt-2", children: [_jsxs("div", { className: "flex justify-between", children: [_jsxs("span", { children: ["Productprijs (", l.plants, " \u00D7 ", fmtEuro(l.unit), ")"] }), _jsx("span", { children: fmtEuro(l.productSubtotal) })] }), l.stickerOn && (_jsxs("div", { className: "flex justify-between", children: [_jsxs("span", { children: ["Stickeropdruk (", l.plants, " \u00D7 ", fmtEuro(l.stickerCost), ")"] }), _jsx("span", { children: fmtEuro(l.stickerSubtotal) })] })), _jsxs("div", { className: "flex justify-between font-bold text-slate-900 pt-0.5", children: [_jsx("span", { children: "Totaalprijs" }), _jsx("span", { className: "text-green-700", children: fmtEuro(l.total) })] }), _jsxs("div", { className: "pt-1 text-[11px] text-slate-500 italic", children: ["Herkomst prijs: ", l.priceSourceLabel] })] }))] })] }), l.soldOut ? (_jsx("div", { className: "border-t border-slate-100 px-4 py-3 text-center text-sm text-red-700 bg-red-50 font-medium", children: "Dit product is niet meer beschikbaar" })) : (_jsxs("div", { className: "border-t border-slate-100 px-4 py-3 flex flex-wrap items-center justify-between gap-2", children: [_jsxs("span", { className: "text-sm text-slate-600", children: ["Aantal fusten:", currentQty > 0 && (_jsxs("span", { className: "ml-1 text-slate-500", children: ["= ", l.plants.toLocaleString("nl-NL"), " planten"] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { type: "button", onClick: () => setQ(p.id, currentQty - 1, l.maxCrates), className: "h-9 w-9 rounded-md border border-slate-200 grid place-items-center text-slate-600 hover:bg-slate-50 disabled:opacity-40", disabled: currentQty <= 0, "aria-label": "Minder", children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx(Input, { type: "number", inputMode: "numeric", step: 1, min: 0, max: l.maxCrates, value: currentQty, onChange: (e) => setQ(p.id, parseInt(e.target.value, 10), l.maxCrates), onKeyDown: (e) => {
|
|
166
195
|
if (["e", "E", "+", "-", ".", ","].includes(e.key))
|
|
167
196
|
e.preventDefault();
|
|
168
197
|
}, className: "w-28 text-center" }), _jsx("button", { type: "button", onClick: () => setQ(p.id, currentQty + 1, l.maxCrates), className: "h-9 w-9 rounded-md border border-slate-200 grid place-items-center text-slate-600 hover:bg-slate-50 disabled:opacity-40", disabled: currentQty >= l.maxCrates, "aria-label": "Meer", children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }))] }, p.id));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CampagneDetail.d.ts","sourceRoot":"","sources":["../../src/components/CampagneDetail.tsx"],"names":[],"mappings":"AASA,wBAAgB,cAAc,
|
|
1
|
+
{"version":3,"file":"CampagneDetail.d.ts","sourceRoot":"","sources":["../../src/components/CampagneDetail.tsx"],"names":[],"mappings":"AASA,wBAAgB,cAAc,gCA0H7B"}
|
|
@@ -34,7 +34,16 @@ export function CampagneDetail() {
|
|
|
34
34
|
setBusy(true);
|
|
35
35
|
try {
|
|
36
36
|
const r = await sendFn({ data: { campaignId } });
|
|
37
|
-
|
|
37
|
+
const firstError = r.errors?.[0]?.error;
|
|
38
|
+
if (r.sent > 0 && r.failed === 0) {
|
|
39
|
+
toast.success(`Verzonden naar ${r.sent} ontvangers`);
|
|
40
|
+
}
|
|
41
|
+
else if (r.sent > 0 && r.failed > 0) {
|
|
42
|
+
toast.warning(`Verzonden naar ${r.sent}, ${r.failed} mislukt${firstError ? `: ${firstError}` : ""}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
toast.error(`Verzending mislukt voor alle ${r.failed} ontvangers${firstError ? `: ${firstError}` : ""}`);
|
|
46
|
+
}
|
|
38
47
|
await reload();
|
|
39
48
|
}
|
|
40
49
|
catch (e) {
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ export { CampagneOverzicht } from "./components/CampagneOverzicht";
|
|
|
5
5
|
export { CampagneDetail } from "./components/CampagneDetail";
|
|
6
6
|
export { RapportagePage } from "./components/RapportagePage";
|
|
7
7
|
export { ActiePage } from "./components/ActiePage";
|
|
8
|
+
export * from "./lib/voorraad-service";
|
|
8
9
|
export declare const actiemailKwekersErpMathot: FlowModule;
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist-lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,cAAc,wBAAwB,CAAC;AASvC,eAAO,MAAM,yBAAyB,EAAE,UAgBvC,CAAC"}
|
package/dist-lib/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { CampagneOverzicht } from "./components/CampagneOverzicht";
|
|
|
5
5
|
export { CampagneDetail } from "./components/CampagneDetail";
|
|
6
6
|
export { RapportagePage } from "./components/RapportagePage";
|
|
7
7
|
export { ActiePage } from "./components/ActiePage";
|
|
8
|
-
|
|
8
|
+
export * from "./lib/voorraad-service";
|
|
9
9
|
import { HuisstijlSettingsCard } from "./components/settings/HuisstijlSettingsCard";
|
|
10
10
|
import { TrackingSettingsCard } from "./components/settings/TrackingSettingsCard";
|
|
11
11
|
import { UitsluitingenSettingsCard } from "./components/settings/UitsluitingenSettingsCard";
|
|
@@ -21,7 +21,6 @@ export const actiemailKwekersErpMathot = {
|
|
|
21
21
|
icon: Mail,
|
|
22
22
|
},
|
|
23
23
|
settingsCards: [
|
|
24
|
-
{ component: AfzenderSettingsCard, order: 10 },
|
|
25
24
|
{ component: HuisstijlSettingsCard, order: 20 },
|
|
26
25
|
{ component: TrackingSettingsCard, order: 30 },
|
|
27
26
|
{ component: StickerSettingsCard, order: 35 },
|