@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.
@@ -1 +1 @@
1
- {"version":3,"file":"AanbiedingsmailtjePage.d.ts","sourceRoot":"","sources":["../../src/components/AanbiedingsmailtjePage.tsx"],"names":[],"mappings":"AAuCA,wBAAgB,sBAAsB,gCA4jBrC"}
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 [{ data: cacheRows }, { data: draftRows }, { data: cs }, { data: extCs }, { data: settings }] = await Promise.all([
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: Number(d.physicalStock ?? d.stock?.physical ?? 0),
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: 0,
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
- ...published.sort((a, b) => a.product.localeCompare(b.product)),
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 && (_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) => {
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
- updateProd(p.product_id, { tiers });
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
- updateProd(p.product_id, { tiers: [...p.tiers, { min_crates: nextMin, price_per_crate: p.normal_price }] });
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
- updateProd(p.product_id, { tiers: p.tiers.filter((_, i) => i !== idx) });
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) => 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) => {
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
- })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2 border-t pt-2", children: [_jsxs("div", { children: [_jsx(Label, { className: "text-xs", children: "Actieprijs \u20AC" }), _jsx(Input, { type: "number", step: "0.01", value: p.discount_price, onChange: (e) => updateProd(p.product_id, { discount_price: Number(e.target.value) }) })] }), _jsxs("div", { children: [_jsx(Label, { className: "text-xs", children: "Voorraad" }), _jsx(Input, { type: "number", value: p.available_stock, onChange: (e) => updateProd(p.product_id, { available_stock: Number(e.target.value) }) })] })] }), _jsx(Textarea, { placeholder: "Omschrijving (optioneel)", rows: 2, value: p.description, onChange: (e) => updateProd(p.product_id, { description: e.target.value }) })] }, p.product_id));
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":"AAqCA,wBAAgB,SAAS,gCAqbxB"}
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
- function addBusinessDays(start, days) {
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 < days) {
23
+ while (added < count) {
12
24
  d.setDate(d.getDate() + 1);
13
- const day = d.getDay();
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(() => toDateInput(addBusinessDays(new Date(), 3)));
75
+ const [deliveryDate, setDeliveryDate] = useState("");
52
76
  const [placed, setPlaced] = useState(null);
53
77
  const [busy, setBusy] = useState(false);
54
- const minDate = useMemo(() => toDateInput(addBusinessDays(new Date(), 3)), []);
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 ?? p.available_stock ?? 0));
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
- const unit = Number(p.discount_price ?? 0);
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.q,
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
- if (!deliveryDate) {
122
- toast.error("Kies een leverdatum");
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: `Gewenste leverdatum: ${formatDateNL(deliveryDate)}${notes ? `\n\n${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 #", 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." })] }) }));
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) })] }), _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) })] })] }))] })] }), 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) => {
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(Truck, { className: "h-4 w-4 text-green-700" }), "Gewenste leverdatum"] }), _jsx(Input, { type: "date", min: minDate, value: deliveryDate, onChange: (e) => setDeliveryDate(e.target.value) }), _jsx("p", { className: "text-xs text-slate-500", children: "Minimaal 3 werkdagen van tevoren" })] }), _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, 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"] })] }));
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
  }
@@ -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
@@ -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;AASnD,eAAO,MAAM,yBAAyB,EAAE,UAgBvC,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";