@flowselections/actie-mail-kwekers-erp-mathot 1.0.8 → 1.0.10
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 +93 -13
- package/dist-lib/components/ActiePage.d.ts.map +1 -1
- package/dist-lib/components/ActiePage.js +159 -22
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +1 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +2050 -40
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +2050 -40
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +2050 -40
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +2169 -121
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/campaigns.functions.d.ts +10050 -0
- package/dist-lib/lib/campaigns.functions.d.ts.map +1 -1
- package/dist-lib/lib/campaigns.functions.js +23 -2
- package/dist-lib/lib/public-offer.functions.d.ts +36 -0
- package/dist-lib/lib/public-offer.functions.d.ts.map +1 -1
- package/dist-lib/lib/public-offer.functions.js +61 -24
- package/dist-lib/lib/stats.functions.d.ts +4294 -273
- 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 +2 -2
|
@@ -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,gCA8oBrC"}
|
|
@@ -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();
|
|
@@ -23,6 +24,7 @@ export function AanbiedingsmailtjePage() {
|
|
|
23
24
|
const [selCustomers, setSelCustomers] = useState(new Set());
|
|
24
25
|
const [showCustomerClasses, setShowCustomerClasses] = useState(true);
|
|
25
26
|
const [productSearch, setProductSearch] = useState("");
|
|
27
|
+
const [productSearchFocused, setProductSearchFocused] = useState(false);
|
|
26
28
|
const [customerSearch, setCustomerSearch] = useState("");
|
|
27
29
|
const [bulkPrice, setBulkPrice] = useState("");
|
|
28
30
|
const BULK_STICKER_PREF_KEY = "aanbiedingsmailtje:bulkStickerOn";
|
|
@@ -69,13 +71,26 @@ export function AanbiedingsmailtjePage() {
|
|
|
69
71
|
.order("updated_at", { ascending: false })
|
|
70
72
|
.limit(1000)
|
|
71
73
|
: Promise.resolve({ data: [] });
|
|
72
|
-
const
|
|
74
|
+
const stockPromise = activeId
|
|
75
|
+
? sb.from("trade_item_stock")
|
|
76
|
+
.select("trade_item_key, physical_stock, reserved_stock, updated_at")
|
|
77
|
+
.eq("connection_id", activeId)
|
|
78
|
+
.limit(5000)
|
|
79
|
+
: Promise.resolve({ data: [] });
|
|
80
|
+
const [{ data: cacheRows }, { data: draftRows }, { data: stockRows }, { data: localProdRows }, { data: cs }, { data: extCs }, { data: settings }] = await Promise.all([
|
|
73
81
|
cachePromise,
|
|
74
82
|
draftPromise,
|
|
83
|
+
stockPromise,
|
|
84
|
+
sb.from("products").select("id, product, sale_price, quantity, image_url, barcode, plants_per_crate, crates_per_layer, layers_per_cart, trade_item_key").order("product").limit(5000),
|
|
75
85
|
sb.from("customers").select("id, company_name, email, customer_class, country").not("email", "is", null).order("company_name").limit(1000),
|
|
76
86
|
sb.from("external_customers_grouped").select("group_key, display_name, email, country, is_active").not("email", "is", null).eq("is_active", true).limit(2000),
|
|
77
87
|
sb.from("offer_settings").select("default_subject, default_intro, default_sticker_cost, show_customer_classes").maybeSingle(),
|
|
78
88
|
]);
|
|
89
|
+
const stockMap = createVoorraadStockMap((Array.isArray(stockRows) ? stockRows : []));
|
|
90
|
+
const stockFor = (key) => {
|
|
91
|
+
const s = stockMap.get(key);
|
|
92
|
+
return voorraadAvailableStock(s);
|
|
93
|
+
};
|
|
79
94
|
const pickName = (n) => {
|
|
80
95
|
if (!n)
|
|
81
96
|
return "";
|
|
@@ -94,35 +109,89 @@ export function AanbiedingsmailtjePage() {
|
|
|
94
109
|
return d.imageUrls[0];
|
|
95
110
|
return null;
|
|
96
111
|
};
|
|
112
|
+
const pickPacking = (d) => {
|
|
113
|
+
const cfgs = Array.isArray(d?.packingConfigurations) ? d.packingConfigurations : [];
|
|
114
|
+
const primary = cfgs.find((c) => c?.primary) ?? cfgs[0];
|
|
115
|
+
if (!primary)
|
|
116
|
+
return { plants_per_crate: null, belading: null };
|
|
117
|
+
const ppc = Number(primary.piecesPerPackage);
|
|
118
|
+
const perLayer = Number(primary.packagesPerLayer);
|
|
119
|
+
const layers = Number(primary.layersPerLoadCarrier);
|
|
120
|
+
const parts = [ppc, perLayer, layers].filter((n) => Number.isFinite(n) && n > 0);
|
|
121
|
+
return {
|
|
122
|
+
plants_per_crate: Number.isFinite(ppc) && ppc > 0 ? ppc : null,
|
|
123
|
+
belading: parts.length === 3 ? `${ppc}x${perLayer}x${layers}` : null,
|
|
124
|
+
};
|
|
125
|
+
};
|
|
97
126
|
const published = (cacheRows ?? []).map((r) => {
|
|
98
127
|
const d = r.data ?? {};
|
|
128
|
+
const packing = pickPacking(d);
|
|
99
129
|
return {
|
|
100
130
|
id: r.floriday_id,
|
|
101
131
|
product: pickName(d.tradeItemName) || pickName(d.name) || pickName(d.vbnName) || (d.botanicalNames?.[0] ?? "(naamloos)"),
|
|
102
132
|
sale_price: null,
|
|
103
|
-
quantity:
|
|
133
|
+
quantity: stockFor(r.floriday_id),
|
|
104
134
|
image_url: pickImage(d),
|
|
105
135
|
barcode: d.supplierArticleCode ?? d.articleCode ?? d.gtin ?? d.articleGtin ?? d.tradeItemReference ?? "",
|
|
136
|
+
plants_per_crate: packing.plants_per_crate,
|
|
137
|
+
belading: packing.belading,
|
|
106
138
|
is_draft: false,
|
|
107
139
|
};
|
|
108
140
|
});
|
|
109
141
|
const drafts = (draftRows ?? []).map((r) => {
|
|
110
142
|
const d = r.data ?? {};
|
|
111
143
|
const firstImage = Array.isArray(d.images) && d.images[0] ? d.images[0] : null;
|
|
144
|
+
const packing = pickPacking(d);
|
|
112
145
|
return {
|
|
113
146
|
id: `local:${r.id}`,
|
|
114
147
|
product: d.name || d.vbnName || "(naamloos)",
|
|
115
148
|
sale_price: null,
|
|
116
|
-
quantity:
|
|
149
|
+
quantity: stockFor(`draft:${r.id}`),
|
|
117
150
|
image_url: firstImage?.url ?? firstImage?.previewUrl ?? null,
|
|
118
151
|
barcode: d.articleCode ?? d.gtin ?? "",
|
|
152
|
+
plants_per_crate: packing.plants_per_crate,
|
|
153
|
+
belading: packing.belading,
|
|
119
154
|
is_draft: true,
|
|
120
155
|
};
|
|
121
156
|
});
|
|
157
|
+
const localProducts = (Array.isArray(localProdRows) ? localProdRows : []).map((r) => {
|
|
158
|
+
const ppc = Number(r.plants_per_crate);
|
|
159
|
+
const cpl = Number(r.crates_per_layer);
|
|
160
|
+
const lpc = Number(r.layers_per_cart);
|
|
161
|
+
const parts = [ppc, cpl, lpc].filter((n) => Number.isFinite(n) && n > 0);
|
|
162
|
+
const key = r.trade_item_key ?? `erp:${r.id}`;
|
|
163
|
+
return {
|
|
164
|
+
id: key,
|
|
165
|
+
product: r.product ?? "(naamloos)",
|
|
166
|
+
sale_price: r.sale_price ?? null,
|
|
167
|
+
quantity: stockFor(key) || Number(r.quantity ?? 0),
|
|
168
|
+
image_url: r.image_url ?? null,
|
|
169
|
+
barcode: r.barcode ?? "",
|
|
170
|
+
plants_per_crate: Number.isFinite(ppc) && ppc > 0 ? ppc : null,
|
|
171
|
+
belading: parts.length === 3 ? `${ppc}x${cpl}x${lpc}` : null,
|
|
172
|
+
is_draft: false,
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
// Overlay lokale ERP-packing/barcode over Floriday-publicaties met dezelfde key
|
|
176
|
+
const localByKey = new Map(localProducts.map((p) => [p.id, p]));
|
|
177
|
+
const publishedMerged = published.map((p) => {
|
|
178
|
+
const local = localByKey.get(p.id);
|
|
179
|
+
if (!local)
|
|
180
|
+
return p;
|
|
181
|
+
return {
|
|
182
|
+
...p,
|
|
183
|
+
plants_per_crate: local.plants_per_crate ?? p.plants_per_crate,
|
|
184
|
+
belading: local.belading ?? p.belading,
|
|
185
|
+
barcode: local.barcode || p.barcode,
|
|
186
|
+
image_url: p.image_url ?? local.image_url,
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
const seenIds = new Set();
|
|
122
190
|
const merged = [
|
|
123
191
|
...drafts,
|
|
124
|
-
...
|
|
125
|
-
|
|
192
|
+
...publishedMerged.sort((a, b) => a.product.localeCompare(b.product)),
|
|
193
|
+
...localProducts.sort((a, b) => a.product.localeCompare(b.product)),
|
|
194
|
+
].filter((p) => (seenIds.has(p.id) ? false : (seenIds.add(p.id), true)));
|
|
126
195
|
setProducts(merged);
|
|
127
196
|
const localList = (cs ?? []).map((c) => ({
|
|
128
197
|
id: c.id, company_name: c.company_name, email: c.email, customer_class: c.customer_class, country: c.country, source: "local",
|
|
@@ -168,8 +237,8 @@ export function AanbiedingsmailtjePage() {
|
|
|
168
237
|
normal_price: 0,
|
|
169
238
|
discount_price: 0,
|
|
170
239
|
available_stock: p.quantity ?? 0,
|
|
171
|
-
plants_per_crate: 10,
|
|
172
|
-
belading: "",
|
|
240
|
+
plants_per_crate: p.plants_per_crate ?? 10,
|
|
241
|
+
belading: p.belading ?? "",
|
|
173
242
|
barcode: p.barcode ?? "",
|
|
174
243
|
crate_price: 0,
|
|
175
244
|
sticker_cost: null,
|
|
@@ -278,7 +347,7 @@ export function AanbiedingsmailtjePage() {
|
|
|
278
347
|
const filteredProducts = products.filter((p) => p.product.toLowerCase().includes(productSearch.toLowerCase()));
|
|
279
348
|
if (loading)
|
|
280
349
|
return _jsxs("div", { className: "p-6 space-y-4", children: [_jsx(Skeleton, { className: "h-32 w-full" }), _jsx(Skeleton, { className: "h-64 w-full" })] });
|
|
281
|
-
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 && (
|
|
350
|
+
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), onFocus: () => setProductSearchFocused(true), onBlur: () => setTimeout(() => setProductSearchFocused(false), 200) })] }), (productSearchFocused || productSearch) && (_jsxs("div", { className: "max-h-80 overflow-y-auto border rounded-md", children: [filteredProducts.map((p) => (_jsxs("button", { onMouseDown: () => 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))), filteredProducts.length === 0 && (_jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: "Geen producten gevonden" }))] })), _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) => {
|
|
282
351
|
setBulkStickerOn(checked);
|
|
283
352
|
if (!checked) {
|
|
284
353
|
setSelProducts((prev) => prev.map((p) => ({ ...p, sticker_cost: null })));
|
|
@@ -293,20 +362,31 @@ export function AanbiedingsmailtjePage() {
|
|
|
293
362
|
const updateTier = (idx, patch) => {
|
|
294
363
|
const tiers = [...p.tiers];
|
|
295
364
|
tiers[idx] = { ...tiers[idx], ...patch };
|
|
296
|
-
|
|
365
|
+
const maxPrice = Math.max(p.crate_price, ...tiers.map((t) => t.price_per_crate));
|
|
366
|
+
updateProd(p.product_id, { tiers, normal_price: Math.max(p.normal_price, maxPrice) });
|
|
297
367
|
};
|
|
298
368
|
const addTier = () => {
|
|
299
369
|
const last = p.tiers[p.tiers.length - 1];
|
|
300
370
|
const nextMin = last ? last.min_crates + 5 : 1;
|
|
301
|
-
|
|
371
|
+
const basePrice = Math.max(p.crate_price, p.normal_price);
|
|
372
|
+
const newTiers = [...p.tiers, { min_crates: nextMin, price_per_crate: basePrice }];
|
|
373
|
+
updateProd(p.product_id, { tiers: newTiers, normal_price: Math.max(p.normal_price, basePrice) });
|
|
302
374
|
};
|
|
303
375
|
const removeTier = (idx) => {
|
|
304
|
-
|
|
376
|
+
const tiers = p.tiers.filter((_, i) => i !== idx);
|
|
377
|
+
const maxPrice = Math.max(p.crate_price, ...tiers.map((t) => t.price_per_crate));
|
|
378
|
+
updateProd(p.product_id, { tiers, normal_price: Math.max(p.normal_price, maxPrice) });
|
|
305
379
|
};
|
|
306
|
-
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) =>
|
|
380
|
+
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) => {
|
|
381
|
+
const newPrice = Number(e.target.value);
|
|
382
|
+
const oldPrice = p.crate_price;
|
|
383
|
+
const tiers = p.tiers.map((t) => t.price_per_crate === oldPrice ? { ...t, price_per_crate: newPrice } : t);
|
|
384
|
+
const normalPrice = Math.max(p.normal_price, newPrice, ...tiers.map((t) => t.price_per_crate));
|
|
385
|
+
updateProd(p.product_id, { crate_price: newPrice, tiers, normal_price: normalPrice });
|
|
386
|
+
} })] })] }), _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) => {
|
|
307
387
|
const pct = p.normal_price > 0 ? Math.round((1 - t.price_per_crate / p.normal_price) * 100) : 0;
|
|
308
388
|
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));
|
|
309
|
-
})] }),
|
|
389
|
+
})] }), _jsx(Textarea, { placeholder: "Omschrijving (optioneel)", rows: 2, value: p.description, onChange: (e) => updateProd(p.product_id, { description: e.target.value }) })] }, p.product_id));
|
|
310
390
|
}) })] }))] })] }), _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) => {
|
|
311
391
|
const allSel = g.customers.length > 0 && g.customers.every((c) => selCustomers.has(c.id));
|
|
312
392
|
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));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActiePage.d.ts","sourceRoot":"","sources":["../../src/components/ActiePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ActiePage.d.ts","sourceRoot":"","sources":["../../src/components/ActiePage.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,SAAS,gCAooBxB"}
|
|
@@ -3,19 +3,41 @@ import { useEffect, useMemo, useState } from "react";
|
|
|
3
3
|
import { useParams } from "@tanstack/react-router";
|
|
4
4
|
import { useServerFn } from "@tanstack/react-start";
|
|
5
5
|
import { Button, Input, Label, Textarea, Skeleton, toast } from "@flowselections/core";
|
|
6
|
-
import { getOfferByLinkCode, trackOfferClick, placeOfferOrder } from "../lib/public-offer.functions";
|
|
7
|
-
import { ShoppingCart, Check, User, Package, Truck, Minus, Plus, Send, Leaf } from "lucide-react";
|
|
8
|
-
|
|
6
|
+
import { getOfferByLinkCode, trackOfferClick, placeOfferOrder, getOfferDeliveryOptions, } from "../lib/public-offer.functions";
|
|
7
|
+
import { ShoppingCart, Check, User, Package, Truck, Minus, Plus, Send, Leaf, MapPin } from "lucide-react";
|
|
8
|
+
// ISO weekday: Ma=1 .. Zo=7
|
|
9
|
+
function isoWeekday(d) {
|
|
10
|
+
const js = d.getDay(); // 0..6, 0=Sun
|
|
11
|
+
return js === 0 ? 7 : js;
|
|
12
|
+
}
|
|
13
|
+
function addDays(start, days) {
|
|
14
|
+
const d = new Date(start);
|
|
15
|
+
d.setDate(d.getDate() + days);
|
|
16
|
+
return d;
|
|
17
|
+
}
|
|
18
|
+
// Voeg N werkdagen toe, waarbij "werkdag" = weekdag in allowedWeekdays (ISO 1..7)
|
|
19
|
+
function addWorkingDays(start, count, allowedWeekdays) {
|
|
20
|
+
const set = new Set(allowedWeekdays.length > 0 ? allowedWeekdays : [1, 2, 3, 4, 5]);
|
|
9
21
|
const d = new Date(start);
|
|
10
22
|
let added = 0;
|
|
11
|
-
while (added <
|
|
23
|
+
while (added < count) {
|
|
12
24
|
d.setDate(d.getDate() + 1);
|
|
13
|
-
|
|
14
|
-
if (day !== 0 && day !== 6)
|
|
25
|
+
if (set.has(isoWeekday(d)))
|
|
15
26
|
added++;
|
|
16
27
|
}
|
|
17
28
|
return d;
|
|
18
29
|
}
|
|
30
|
+
// Verschuif door totdat de dag in allowedWeekdays valt
|
|
31
|
+
function snapToWeekday(start, allowedWeekdays) {
|
|
32
|
+
const set = new Set(allowedWeekdays.length > 0 ? allowedWeekdays : [1, 2, 3, 4, 5]);
|
|
33
|
+
const d = new Date(start);
|
|
34
|
+
for (let i = 0; i < 14; i++) {
|
|
35
|
+
if (set.has(isoWeekday(d)))
|
|
36
|
+
return d;
|
|
37
|
+
d.setDate(d.getDate() + 1);
|
|
38
|
+
}
|
|
39
|
+
return d;
|
|
40
|
+
}
|
|
19
41
|
function toDateInput(d) {
|
|
20
42
|
const y = d.getFullYear();
|
|
21
43
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
@@ -34,12 +56,14 @@ function formatDateNL(iso) {
|
|
|
34
56
|
return iso;
|
|
35
57
|
}
|
|
36
58
|
}
|
|
59
|
+
const WEEKDAY_LABELS = { 1: "ma", 2: "di", 3: "wo", 4: "do", 5: "vr", 6: "za", 7: "zo" };
|
|
37
60
|
const fmtEuro = (n) => `€ ${Number(n ?? 0).toLocaleString("nl-NL", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
38
61
|
export function ActiePage() {
|
|
39
62
|
const { linkCode } = useParams({ strict: false });
|
|
40
63
|
const getFn = useServerFn(getOfferByLinkCode);
|
|
41
64
|
const trackFn = useServerFn(trackOfferClick);
|
|
42
65
|
const orderFn = useServerFn(placeOfferOrder);
|
|
66
|
+
const optionsFn = useServerFn(getOfferDeliveryOptions);
|
|
43
67
|
const [data, setData] = useState(null);
|
|
44
68
|
const [loading, setLoading] = useState(true);
|
|
45
69
|
const [qty, setQty] = useState({});
|
|
@@ -48,10 +72,43 @@ export function ActiePage() {
|
|
|
48
72
|
const [email, setEmail] = useState("");
|
|
49
73
|
const [phone, setPhone] = useState("");
|
|
50
74
|
const [notes, setNotes] = useState("");
|
|
51
|
-
const [deliveryDate, setDeliveryDate] = useState(
|
|
75
|
+
const [deliveryDate, setDeliveryDate] = useState("");
|
|
52
76
|
const [placed, setPlaced] = useState(null);
|
|
53
77
|
const [busy, setBusy] = useState(false);
|
|
54
|
-
|
|
78
|
+
// Logistiek
|
|
79
|
+
const [options, setOptions] = useState(null);
|
|
80
|
+
// afhaallocatie verwijderd uit het bestelformulier
|
|
81
|
+
const [deliveryGardenId, setDeliveryGardenId] = useState("");
|
|
82
|
+
// Auto-carrier: eerste voorkeur (is_default → sort_order → naam) uit de carriers van de aanbieder
|
|
83
|
+
const carrier = useMemo(() => {
|
|
84
|
+
const list = Array.isArray(options?.carriers) ? options.carriers : [];
|
|
85
|
+
return list[0] ?? null;
|
|
86
|
+
}, [options]);
|
|
87
|
+
// Eerst mogelijke leverdatum: alleen berekenen als afhaallocatie + aflevertuin bekend zijn
|
|
88
|
+
const minDeliveryDate = useMemo(() => {
|
|
89
|
+
if (!options || !deliveryGardenId || !carrier)
|
|
90
|
+
return "";
|
|
91
|
+
const pickDays = Math.max(0, Number(options.pick_days_before_transport ?? 1));
|
|
92
|
+
const pickWeekdays = Array.isArray(options.pick_weekdays) && options.pick_weekdays.length > 0
|
|
93
|
+
? options.pick_weekdays.map((n) => Number(n))
|
|
94
|
+
: [1, 2, 3, 4, 5];
|
|
95
|
+
const deliveryWeekdays = Array.isArray(carrier.delivery_weekdays) && carrier.delivery_weekdays.length > 0
|
|
96
|
+
? carrier.delivery_weekdays.map((n) => Number(n))
|
|
97
|
+
: [1, 2, 3, 4, 5];
|
|
98
|
+
const readyForTransport = addWorkingDays(new Date(), pickDays, pickWeekdays);
|
|
99
|
+
const afterTransport = addWorkingDays(readyForTransport, Math.max(0, Number(carrier.delivery_days ?? 0)), deliveryWeekdays);
|
|
100
|
+
const snapped = snapToWeekday(afterTransport, deliveryWeekdays);
|
|
101
|
+
return toDateInput(snapped);
|
|
102
|
+
}, [options, deliveryGardenId, carrier]);
|
|
103
|
+
const allowedDeliveryWeekdays = useMemo(() => (carrier?.delivery_weekdays ?? []).map((n) => Number(n)), [carrier]);
|
|
104
|
+
// Reset / preselect leverdatum bij logistieke wijziging
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (!minDeliveryDate) {
|
|
107
|
+
setDeliveryDate("");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
setDeliveryDate(minDeliveryDate);
|
|
111
|
+
}, [minDeliveryDate]);
|
|
55
112
|
useEffect(() => {
|
|
56
113
|
let cancelled = false;
|
|
57
114
|
const load = async (initial) => {
|
|
@@ -64,6 +121,10 @@ export function ActiePage() {
|
|
|
64
121
|
setName(result.recipient.recipient_name);
|
|
65
122
|
setEmail(result.recipient.recipient_email);
|
|
66
123
|
trackFn({ data: { code: linkCode } }).catch(() => { });
|
|
124
|
+
optionsFn({ data: { code: linkCode } })
|
|
125
|
+
.then((opts) => { if (!cancelled)
|
|
126
|
+
setOptions(opts); })
|
|
127
|
+
.catch(() => { });
|
|
67
128
|
}
|
|
68
129
|
}
|
|
69
130
|
finally {
|
|
@@ -83,23 +144,52 @@ export function ActiePage() {
|
|
|
83
144
|
}
|
|
84
145
|
const safeProducts = Array.isArray(data?.products) ? data.products : [];
|
|
85
146
|
const lineFor = (p) => {
|
|
86
|
-
const stockPlants = Math.max(0, Number(p.live_stock ??
|
|
147
|
+
const stockPlants = Math.max(0, Number(p.live_stock ?? 0));
|
|
87
148
|
const ppc = Math.max(1, Math.floor(Number(p.plants_per_crate ?? 1) || 1));
|
|
88
149
|
const maxCrates = Math.floor(stockPlants / ppc);
|
|
89
150
|
const soldOut = maxCrates <= 0;
|
|
90
151
|
const crates = Math.max(0, Math.floor(qty[p.id] ?? 0));
|
|
91
152
|
const plants = crates * ppc;
|
|
92
|
-
|
|
153
|
+
// Prijsprioriteit: (1) tier-prijs uit actie-e-mail, (2) discount_price uit e-mail,
|
|
154
|
+
// (3) standaardprijs uit artikelbeheer. De e-mailprijs is ALTIJD leidend.
|
|
155
|
+
const tiers = Array.isArray(p.tiers)
|
|
156
|
+
? [...p.tiers].map((t) => ({ min_crates: Number(t.min_crates), price_per_crate: Number(t.price_per_crate) }))
|
|
157
|
+
.sort((a, b) => a.min_crates - b.min_crates)
|
|
158
|
+
: [];
|
|
159
|
+
let unit = 0;
|
|
160
|
+
let cratePrice = 0;
|
|
161
|
+
let priceSource = "normal";
|
|
162
|
+
if (tiers.length > 0) {
|
|
163
|
+
const applicable = [...tiers].reverse().find((t) => crates >= t.min_crates) ?? tiers[0];
|
|
164
|
+
cratePrice = applicable.price_per_crate;
|
|
165
|
+
unit = cratePrice / ppc;
|
|
166
|
+
priceSource = "tier";
|
|
167
|
+
}
|
|
168
|
+
else if (Number(p.discount_price) > 0) {
|
|
169
|
+
unit = Number(p.discount_price);
|
|
170
|
+
cratePrice = unit * ppc;
|
|
171
|
+
priceSource = "discount";
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
unit = Number(p.normal_price ?? 0);
|
|
175
|
+
cratePrice = unit * ppc;
|
|
176
|
+
priceSource = "normal";
|
|
177
|
+
}
|
|
178
|
+
const priceSourceLabel = priceSource === "tier" ? "Prijs uit actie-e-mail"
|
|
179
|
+
: priceSource === "discount" ? "Actieprijs uit e-mail"
|
|
180
|
+
: "Standaardprijs artikelbeheer";
|
|
93
181
|
const stickerCost = Number(p.sticker_cost ?? 0);
|
|
94
182
|
const stickerAvail = p.sticker_available !== false;
|
|
95
183
|
const stickerOn = stickerAvail && !!sticker[p.id];
|
|
96
184
|
const productSubtotal = plants * unit;
|
|
97
185
|
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 };
|
|
186
|
+
return { q: crates, plants, ppc, unit, cratePrice, priceSource, priceSourceLabel, tiers, stickerCost, stickerAvail, stickerOn, productSubtotal, stickerSubtotal, total: productSubtotal + stickerSubtotal, stock: stockPlants, maxCrates, soldOut };
|
|
99
187
|
};
|
|
100
188
|
const totalAmount = safeProducts.reduce((s, p) => s + lineFor(p).total, 0);
|
|
101
189
|
const hasItems = safeProducts.some((p) => (qty[p.id] ?? 0) > 0);
|
|
102
190
|
const setQ = (id, value, maxCrates) => setQty({ ...qty, [id]: Math.max(0, Math.min(maxCrates, Math.floor(Number.isFinite(value) ? value : 0))) });
|
|
191
|
+
// pickupLocation verwijderd
|
|
192
|
+
const deliveryGarden = (options?.delivery_gardens ?? []).find((g) => g.id === deliveryGardenId) ?? null;
|
|
103
193
|
const submit = async () => {
|
|
104
194
|
const items = safeProducts
|
|
105
195
|
.filter((p) => (qty[p.id] ?? 0) > 0)
|
|
@@ -108,7 +198,7 @@ export function ActiePage() {
|
|
|
108
198
|
return {
|
|
109
199
|
product_id: p.id,
|
|
110
200
|
product_name: p.product_name,
|
|
111
|
-
quantity: l.
|
|
201
|
+
quantity: l.plants,
|
|
112
202
|
unit_price: l.unit,
|
|
113
203
|
sticker: l.stickerOn,
|
|
114
204
|
sticker_unit_price: l.stickerOn ? l.stickerCost : 0,
|
|
@@ -118,23 +208,49 @@ export function ActiePage() {
|
|
|
118
208
|
toast.error("Voeg minimaal één product toe");
|
|
119
209
|
return;
|
|
120
210
|
}
|
|
121
|
-
|
|
122
|
-
|
|
211
|
+
// afhaallocatie niet vereist
|
|
212
|
+
if (!deliveryGardenId) {
|
|
213
|
+
toast.error("Kies een aflevertuin");
|
|
123
214
|
return;
|
|
124
215
|
}
|
|
216
|
+
if (!deliveryDate || !minDeliveryDate) {
|
|
217
|
+
toast.error("Er kon geen leverdatum worden berekend");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (deliveryDate < minDeliveryDate) {
|
|
221
|
+
toast.error(`Eerst mogelijke leverdatum is ${formatDateNL(minDeliveryDate)}`);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (allowedDeliveryWeekdays.length > 0) {
|
|
225
|
+
const wd = isoWeekday(new Date(deliveryDate + "T00:00:00"));
|
|
226
|
+
if (!allowedDeliveryWeekdays.includes(wd)) {
|
|
227
|
+
toast.error("De vervoerder levert niet op deze dag");
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
125
231
|
setBusy(true);
|
|
126
232
|
try {
|
|
233
|
+
const logisticsNote = [
|
|
234
|
+
`Aflevertuin: ${deliveryGarden ? `${deliveryGarden.name}${deliveryGarden.gln_code ? ` (${deliveryGarden.gln_code})` : ""}` : "-"}`,
|
|
235
|
+
`Vervoerder: ${carrier?.name ?? "-"}`,
|
|
236
|
+
`Gewenste leverdatum: ${formatDateNL(deliveryDate)}`,
|
|
237
|
+
].join("\n");
|
|
127
238
|
const r = await orderFn({
|
|
128
239
|
data: {
|
|
129
240
|
code: linkCode,
|
|
130
241
|
customer_name: name,
|
|
131
242
|
customer_email: email,
|
|
132
243
|
customer_phone: phone,
|
|
133
|
-
notes:
|
|
244
|
+
notes: `${logisticsNote}${notes ? `\n\n${notes}` : ""}`,
|
|
245
|
+
delivery_garden_id: deliveryGardenId || undefined,
|
|
246
|
+
delivery_garden_name: deliveryGarden?.name,
|
|
247
|
+
carrier_id: carrier?.id,
|
|
248
|
+
carrier_name: carrier?.name,
|
|
249
|
+
delivery_date: deliveryDate,
|
|
134
250
|
items,
|
|
135
251
|
},
|
|
136
252
|
});
|
|
137
|
-
setPlaced({ id: r.orderId, total: r.total });
|
|
253
|
+
setPlaced({ id: r.orderId, total: r.total, orderNumber: r.orderNumber ?? null });
|
|
138
254
|
}
|
|
139
255
|
catch (e) {
|
|
140
256
|
toast.error(e?.message ?? "Fout");
|
|
@@ -144,7 +260,7 @@ export function ActiePage() {
|
|
|
144
260
|
}
|
|
145
261
|
};
|
|
146
262
|
if (placed) {
|
|
147
|
-
return (_jsx("div", { className: "min-h-screen bg-[#f0fdf4] flex items-center justify-center p-6", children: _jsxs("div", { className: "max-w-md w-full bg-white rounded-2xl shadow-lg border border-green-100 p-8 text-center", children: [_jsx("div", { className: "mx-auto rounded-full bg-green-100 p-3 w-fit", children: _jsx(Check, { className: "h-8 w-8 text-green-600" }) }), _jsx("h2", { className: "mt-4 text-2xl font-bold text-slate-900", children: "Bedankt voor uw bestelling!" }), _jsxs("p", { className: "mt-2 text-slate-600", children: ["Bestelling
|
|
263
|
+
return (_jsx("div", { className: "min-h-screen bg-[#f0fdf4] flex items-center justify-center p-6", children: _jsxs("div", { className: "max-w-md w-full bg-white rounded-2xl shadow-lg border border-green-100 p-8 text-center", children: [_jsx("div", { className: "mx-auto rounded-full bg-green-100 p-3 w-fit", children: _jsx(Check, { className: "h-8 w-8 text-green-600" }) }), _jsx("h2", { className: "mt-4 text-2xl font-bold text-slate-900", children: "Bedankt voor uw bestelling!" }), _jsxs("p", { className: "mt-2 text-slate-600", children: ["Bestelling ", placed.orderNumber ? placed.orderNumber : `#${placed.id.slice(0, 8)}`] }), _jsxs("p", { className: "mt-1 text-lg font-semibold text-green-700", children: ["Totaal: ", fmtEuro(placed.total)] }), _jsx("p", { className: "mt-4 text-sm text-slate-500", children: "We nemen zo spoedig mogelijk contact met u op." })] }) }));
|
|
148
264
|
}
|
|
149
265
|
const fromName = data?.campaign?.from_name ?? "";
|
|
150
266
|
return (_jsxs("div", { className: "min-h-screen bg-[#f0fdf4] flex flex-col", children: [_jsx("header", { className: "bg-gradient-to-r from-green-600 to-green-700 text-white", children: _jsxs("div", { className: "max-w-6xl mx-auto px-6 py-10 text-center", children: [_jsxs("div", { className: "mx-auto mb-4 inline-flex items-center justify-center bg-white rounded-md px-4 py-2 shadow-sm", children: [_jsx(Leaf, { className: "h-5 w-5 text-green-700 mr-2" }), _jsx("span", { className: "font-bold text-slate-900 tracking-tight", children: "Flow Selections" })] }), _jsxs("h1", { className: "text-3xl md:text-4xl font-extrabold tracking-tight", children: ["\uD83C\uDF31 ", data?.campaign?.subject ?? "Speciale Aanbieding"] }), data?.campaign?.intro_message ? (_jsx("p", { className: "mt-3 text-green-50 whitespace-pre-line max-w-2xl mx-auto", children: data.campaign.intro_message })) : (_jsx("p", { className: "mt-3 text-green-50", children: "Wij hebben een mooie aanbieding voor u!" }))] }) }), _jsxs("main", { className: "flex-1 max-w-6xl w-full mx-auto px-4 md:px-6 py-8 space-y-6", children: [_jsxs("div", { className: "bg-green-50 border border-green-200 rounded-xl p-5 flex items-center gap-4", children: [_jsx("div", { className: "rounded-full bg-green-600 p-3 text-white shrink-0", children: _jsx(User, { className: "h-5 w-5" }) }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "font-bold text-slate-900", children: ["Welkom, ", data?.recipient?.recipient_name, "!"] }), _jsx("div", { className: "text-green-700 text-sm truncate", children: data?.recipient?.recipient_email })] })] }), _jsxs("div", { className: "grid gap-6 lg:grid-cols-[minmax(0,1fr)_360px]", children: [_jsxs("section", { children: [_jsxs("h2", { className: "flex items-center gap-2 text-xl font-bold text-slate-900 mb-4", children: [_jsx(Package, { className: "h-5 w-5 text-green-700" }), "Selecteer uw producten"] }), safeProducts.some((p) => p.sticker_available !== false) && (_jsxs("div", { className: "mb-4 flex items-center justify-between gap-3 bg-blue-50 border border-blue-200 rounded-xl px-4 py-3", children: [_jsxs("div", { className: "text-sm text-blue-900", children: [_jsx("strong", { children: "Stickeropdruk voor alle planten" }), _jsx("div", { className: "text-xs text-blue-700", children: "Schakel met \u00E9\u00E9n klik in/uit voor alle producten waar het beschikbaar is." })] }), _jsxs("div", { className: "flex gap-2 shrink-0", children: [_jsx("button", { type: "button", onClick: () => {
|
|
@@ -157,17 +273,38 @@ export function ActiePage() {
|
|
|
157
273
|
safeProducts.forEach((p) => { next[p.id] = false; });
|
|
158
274
|
setSticker(next);
|
|
159
275
|
}, 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
276
|
const l = lineFor(p);
|
|
277
|
+
const normal = Number(p.normal_price ?? 0);
|
|
278
|
+
const price = l.cratePrice > 0 ? l.cratePrice : Number(p.discount_price ?? 0);
|
|
279
|
+
const showStrike = normal > 0 && normal > price && price > 0;
|
|
164
280
|
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) })
|
|
281
|
+
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"
|
|
282
|
+
? "bg-green-100 border-green-300 text-green-800 font-semibold"
|
|
283
|
+
: "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
284
|
if (["e", "E", "+", "-", ".", ","].includes(e.key))
|
|
167
285
|
e.preventDefault();
|
|
168
286
|
}, 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));
|
|
169
287
|
}) })] }), _jsx("aside", { className: "lg:sticky lg:top-6 self-start", children: _jsxs("div", { className: "bg-white rounded-xl border border-slate-200 shadow-sm p-5 space-y-5", children: [_jsxs("h3", { className: "flex items-center gap-2 text-lg font-bold text-slate-900", children: [_jsx(ShoppingCart, { className: "h-5 w-5 text-green-700" }), "Uw bestelling"] }), hasItems ? (_jsxs("div", { className: "space-y-2 text-sm", children: [safeProducts.filter((p) => (qty[p.id] ?? 0) > 0).map((p) => {
|
|
170
288
|
const l = lineFor(p);
|
|
171
289
|
return (_jsxs("div", { className: "space-y-0.5", children: [_jsxs("div", { className: "flex justify-between gap-2", children: [_jsxs("span", { className: "text-slate-700 truncate", children: [p.product_name, " \u00D7 ", l.q, " fust", l.q === 1 ? "" : "en", " (", l.plants.toLocaleString("nl-NL"), " planten)"] }), _jsx("span", { className: "font-medium text-slate-900 shrink-0", children: fmtEuro(l.productSubtotal) })] }), l.stickerOn && (_jsxs("div", { className: "flex justify-between gap-2 text-xs text-blue-800", children: [_jsxs("span", { className: "truncate", children: ["\u21B3 Stickeropdruk \u00D7 ", l.plants.toLocaleString("nl-NL")] }), _jsx("span", { className: "shrink-0", children: fmtEuro(l.stickerSubtotal) })] }))] }, p.id));
|
|
172
|
-
}), _jsxs("div", { className: "border-t border-slate-200 pt-2 flex justify-between font-bold text-slate-900", children: [_jsx("span", { children: "Totaal" }), _jsx("span", { className: "text-green-700", children: fmtEuro(totalAmount) })] })] })) : (_jsx("p", { className: "text-sm text-slate-500 text-center py-2", children: "Selecteer producten om te bestellen" })), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-2 text-slate-800", children: [_jsx(
|
|
290
|
+
}), _jsxs("div", { className: "border-t border-slate-200 pt-2 flex justify-between font-bold text-slate-900", children: [_jsx("span", { children: "Totaal" }), _jsx("span", { className: "text-green-700", children: fmtEuro(totalAmount) })] })] })) : (_jsx("p", { className: "text-sm text-slate-500 text-center py-2", children: "Selecteer producten om te bestellen" })), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-2 text-slate-800", children: [_jsx(MapPin, { className: "h-4 w-4 text-green-700" }), "Aflevertuin"] }), _jsx("div", { className: "rounded-md border border-slate-200 bg-white max-h-64 overflow-auto divide-y divide-slate-100", children: (options?.delivery_gardens ?? []).length === 0 ? (_jsx("div", { className: "px-3 py-3 text-sm text-slate-500", children: "Geen aflevertuinen bekend voor deze klant." })) : ((options?.delivery_gardens ?? []).map((g) => {
|
|
291
|
+
const checked = deliveryGardenId === g.id;
|
|
292
|
+
return (_jsxs("label", { className: `flex items-start gap-2 px-3 py-2 text-sm cursor-pointer hover:bg-green-50 ${checked ? "bg-green-50" : ""}`, children: [_jsx("input", { type: "radio", name: "delivery-garden", className: "mt-0.5", checked: checked, onChange: () => setDeliveryGardenId(g.id) }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "truncate font-medium text-slate-800", children: [g.name, g.is_primary ? (_jsx("span", { className: "ml-2 text-[10px] uppercase tracking-wide text-green-700", children: "standaard" })) : null] }), _jsxs("div", { className: "text-[11px] text-slate-500", children: [g.city ? _jsx("span", { children: g.city }) : null, g.gln_code ? _jsxs("span", { children: [g.city ? " · " : "", "GLN ", g.gln_code] }) : null] })] })] }, g.id));
|
|
293
|
+
})) }), deliveryGarden && (_jsxs("p", { className: "text-xs text-slate-600", children: ["Gekozen: ", _jsx("strong", { children: deliveryGarden.name })] }))] }), carrier && (_jsxs("div", { className: "rounded-md bg-slate-50 border border-slate-200 px-3 py-2 text-xs text-slate-700", children: [_jsxs("div", { className: "flex items-center gap-2 font-semibold text-slate-800", children: [_jsx(Truck, { className: "h-4 w-4 text-green-700" }), "Vervoerder: ", carrier.name] }), _jsxs("div", { className: "mt-0.5", children: ["Transporttijd: ", carrier.delivery_days, " werkdag", carrier.delivery_days === 1 ? "" : "en", allowedDeliveryWeekdays.length > 0 && (_jsxs(_Fragment, { children: [" \u00B7 Levert op ", allowedDeliveryWeekdays.sort((a, b) => a - b).map((n) => WEEKDAY_LABELS[n]).join(", ")] }))] })] })), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-2 text-slate-800", children: [_jsx(Truck, { className: "h-4 w-4 text-green-700" }), "Gewenste leverdatum"] }), _jsx(Input, { type: "date", min: minDeliveryDate || undefined, value: deliveryDate, disabled: !minDeliveryDate, onChange: (e) => {
|
|
294
|
+
const v = e.target.value;
|
|
295
|
+
if (!v) {
|
|
296
|
+
setDeliveryDate("");
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (allowedDeliveryWeekdays.length > 0) {
|
|
300
|
+
const wd = isoWeekday(new Date(v + "T00:00:00"));
|
|
301
|
+
if (!allowedDeliveryWeekdays.includes(wd)) {
|
|
302
|
+
const snapped = snapToWeekday(new Date(v + "T00:00:00"), allowedDeliveryWeekdays);
|
|
303
|
+
setDeliveryDate(toDateInput(snapped));
|
|
304
|
+
toast.message(`Vervoerder levert niet op deze dag — verzet naar ${formatDateNL(toDateInput(snapped))}`);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
setDeliveryDate(v);
|
|
309
|
+
} }), !deliveryGardenId ? (_jsx("p", { className: "text-xs text-amber-700", children: "Kies eerst een aflevertuin om de eerst mogelijke leverdatum te berekenen." })) : minDeliveryDate ? (_jsxs("p", { className: "text-xs text-slate-600", children: ["Eerst mogelijk: ", _jsx("strong", { children: formatDateNL(minDeliveryDate) })] })) : (_jsx("p", { className: "text-xs text-red-700", children: "Er kon geen leverdatum worden berekend \u2014 controleer de vervoerdersinstellingen." }))] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { className: "text-slate-800", children: "Opmerkingen (optioneel)" }), _jsx(Textarea, { placeholder: "Speciale wensen of vragen...", value: notes, onChange: (e) => setNotes(e.target.value), rows: 3 })] }), _jsxs(Button, { onClick: submit, disabled: busy || !hasItems || !name || !email || !deliveryGardenId || !deliveryDate, className: "w-full bg-green-600 hover:bg-green-700 text-white", size: "lg", children: [_jsx(Send, { className: "h-4 w-4 mr-2" }), busy ? "Bezig..." : "Bestelling plaatsen"] })] }) })] })] }), _jsxs("footer", { className: "bg-slate-900 text-slate-300 text-center py-5 text-sm", children: ["\u00A9 ", new Date().getFullYear(), " ", fromName || "Flow Selections"] })] }));
|
|
173
310
|
}
|
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,6 +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
|
+
export * from "./lib/voorraad-service";
|
|
8
9
|
import { HuisstijlSettingsCard } from "./components/settings/HuisstijlSettingsCard";
|
|
9
10
|
import { TrackingSettingsCard } from "./components/settings/TrackingSettingsCard";
|
|
10
11
|
import { UitsluitingenSettingsCard } from "./components/settings/UitsluitingenSettingsCard";
|