@flowselections/floriday-verkoop-module 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist-lib/components/verkoop/AnalyticsCards.d.ts +1 -1
  2. package/dist-lib/components/verkoop/AnalyticsCards.d.ts.map +1 -1
  3. package/dist-lib/components/verkoop/AnalyticsCards.js +1 -7
  4. package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
  5. package/dist-lib/components/verkoop/CreateOrderPage.js +217 -189
  6. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
  7. package/dist-lib/components/verkoop/SalesOrderDetailView.js +1 -1
  8. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
  9. package/dist-lib/components/verkoop/SalesOrdersTable.js +19 -40
  10. package/dist-lib/components/verkoop/SearchableSelect.d.ts +19 -0
  11. package/dist-lib/components/verkoop/SearchableSelect.d.ts.map +1 -0
  12. package/dist-lib/components/verkoop/SearchableSelect.js +21 -0
  13. package/dist-lib/integrations/supabase/auth-middleware.d.ts +1486 -35
  14. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  15. package/dist-lib/integrations/supabase/client.d.ts +1486 -35
  16. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  17. package/dist-lib/integrations/supabase/client.server.d.ts +1486 -35
  18. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  19. package/dist-lib/integrations/supabase/types.d.ts +1515 -34
  20. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  21. package/dist-lib/lib/create-order.functions.d.ts +75223 -0
  22. package/dist-lib/lib/create-order.functions.d.ts.map +1 -0
  23. package/dist-lib/lib/create-order.functions.js +188 -0
  24. package/dist-lib/lib/floriday-public.functions.d.ts +10157 -0
  25. package/dist-lib/lib/floriday-public.functions.d.ts.map +1 -1
  26. package/dist-lib/lib/floriday-writes.functions.d.ts +7255 -0
  27. package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
  28. package/dist-lib/lib/salesorders-mapping.d.ts +4 -0
  29. package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
  30. package/dist-lib/lib/salesorders-mapping.js +14 -3
  31. package/dist-lib/lib/salesorders.functions.d.ts +4614 -261
  32. package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
  33. package/dist-lib/lib/tradeitems.functions.d.ts +1486 -35
  34. package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -1
  35. package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
  36. package/dist-lib/lib/useSalesOrdersQuery.js +166 -26
  37. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  export declare function AnalyticsCards({ totals, loading, }: {
2
2
  totals?: {
3
3
  revenue: number;
4
- avgPrice: number;
5
4
  fustCount: number;
5
+ orderCount: number;
6
6
  };
7
7
  loading?: boolean;
8
8
  }): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"AnalyticsCards.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/AnalyticsCards.tsx"],"names":[],"mappings":"AAWA,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAO,GACR,EAAE;IACD,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,2CAwBA"}
1
+ {"version":3,"file":"AnalyticsCards.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/AnalyticsCards.tsx"],"names":[],"mappings":"AAKA,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAO,GACR,EAAE;IACD,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,2CAwBA"}
@@ -1,17 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Card, CardContent, Skeleton } from "@flowselections/core";
3
3
  const eur = new Intl.NumberFormat("nl-NL", { style: "currency", currency: "EUR" });
4
- const eurPrecise = new Intl.NumberFormat("nl-NL", {
5
- style: "currency",
6
- currency: "EUR",
7
- minimumFractionDigits: 2,
8
- maximumFractionDigits: 2,
9
- });
10
4
  const num = new Intl.NumberFormat("nl-NL");
11
5
  export function AnalyticsCards({ totals, loading, }) {
12
6
  const items = [
13
7
  { label: "Omzet", value: totals ? eur.format(totals.revenue) : null },
14
- { label: "Gemiddelde prijs", value: totals ? eurPrecise.format(totals.avgPrice) : null },
8
+ { label: "Aantal orders", value: totals ? num.format(totals.orderCount) : null },
15
9
  { label: "Aantal fusten", value: totals ? num.format(totals.fustCount) : null },
16
10
  ];
17
11
  return (_jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-3", children: items.map((it) => (_jsx(Card, { className: "border-border/60 shadow-none", children: _jsxs(CardContent, { className: "px-6 py-5", children: [_jsx("div", { className: "text-sm font-medium text-muted-foreground", children: it.label }), loading || !it.value ? (_jsx(Skeleton, { className: "mt-3 h-10 w-40" })) : (_jsx("div", { className: "mt-2 text-4xl font-bold tracking-tight text-primary", children: it.value }))] }) }, it.label))) }));
@@ -1 +1 @@
1
- {"version":3,"file":"CreateOrderPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/CreateOrderPage.tsx"],"names":[],"mappings":"AA4IA,wBAAgB,eAAe,4CAoX9B"}
1
+ {"version":3,"file":"CreateOrderPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/CreateOrderPage.tsx"],"names":[],"mappings":"AA4CA,wBAAgB,eAAe,4CAib9B"}
@@ -1,218 +1,246 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo, useState } from "react";
3
- import { Badge, Button, Input, Label, Popover, PopoverContent, PopoverTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "@flowselections/core";
2
+ // Handmatig aanmaken van een bestelling — gebruikt exact dezelfde workflow,
3
+ // server-fns en validaties als de Mailbox-module. Beide modules leunen op
4
+ // gedeelde queries (klanten, producten met voorraad, afleverlocaties,
5
+ // afhaallocaties, vervoerders, orderpicktijd) en dezelfde eerstmogelijke-
6
+ // leverdatum-berekening. Zie src/lib/create-order.functions.ts.
7
+ import { useEffect, useMemo, useRef, useState } from "react";
8
+ import { Button, Card, CardContent, CardHeader, CardTitle, Input, Label, Textarea, toast, } from "@flowselections/core";
4
9
  import { Link, useNavigate } from "@tanstack/react-router";
5
10
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
6
- import { ArrowLeft, ChevronDown, Plus, Search, Trash2, Truck, MapPin, } from "lucide-react";
7
- import { supabase } from "../../integrations/supabase/client";
11
+ import { ArrowLeft, Plus, Trash2 } from "lucide-react";
8
12
  import { useServerFn } from "@tanstack/react-start";
9
- import { getFlorydayCachedList } from "../../lib/floriday-public.functions";
10
- const eur = new Intl.NumberFormat("nl-NL", {
11
- style: "currency",
12
- currency: "EUR",
13
- });
14
- function pickStr(v) {
15
- if (v == null)
16
- return null;
17
- if (typeof v === "string")
18
- return v;
19
- if (typeof v === "number")
20
- return String(v);
21
- if (Array.isArray(v)) {
22
- for (const x of v) {
23
- const s = pickStr(x?.text ?? x?.value ?? x);
24
- if (s)
25
- return s;
26
- }
27
- return null;
28
- }
29
- if (typeof v === "object") {
30
- return (v.nl ?? v.NL ?? v.en ?? v.EN ?? v.text ?? v.value ??
31
- Object.values(v).find((x) => typeof x === "string") ??
32
- null);
33
- }
34
- return null;
13
+ import { SearchableSelect } from "./SearchableSelect";
14
+ import { listCustomersForCreateOrder, listProductsForCreateOrder, listDeliveryLocationsForCustomerCO, listPickupLocationsCO, listCarriersForCreateOrder, getOrderPickDaysCO, createManualOrder, } from "../../lib/create-order.functions";
15
+ function ReadOnlyField({ label, value }) {
16
+ return (_jsxs("div", { className: "space-y-0.5", children: [_jsx("div", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: label }), _jsx("div", { className: "text-sm", children: value && String(value).trim() !== "" ? value : _jsx("span", { className: "text-muted-foreground", children: "\u2014" }) })] }));
35
17
  }
36
- function useCustomersForOrder() {
37
- return useQuery({
38
- queryKey: ["create-order", "customers"],
39
- queryFn: async () => {
40
- const { data, error } = await supabase
41
- .from("customers")
42
- .select("id, company_name, city, is_active")
43
- .or("is_active.is.null,is_active.eq.true")
44
- .order("company_name", { ascending: true })
45
- .limit(2000);
46
- if (error)
47
- throw error;
48
- return (data ?? []);
49
- },
50
- staleTime: 60000,
18
+ export function CreateOrderPage() {
19
+ const navigate = useNavigate();
20
+ const qc = useQueryClient();
21
+ const fetchCustomers = useServerFn(listCustomersForCreateOrder);
22
+ const fetchProducts = useServerFn(listProductsForCreateOrder);
23
+ const fetchDeliveryLocations = useServerFn(listDeliveryLocationsForCustomerCO);
24
+ const fetchPickupLocations = useServerFn(listPickupLocationsCO);
25
+ const fetchCarriers = useServerFn(listCarriersForCreateOrder);
26
+ const fetchPickDays = useServerFn(getOrderPickDaysCO);
27
+ const fetchCreate = useServerFn(createManualOrder);
28
+ const safe = async (fn) => {
29
+ try {
30
+ return await fn();
31
+ }
32
+ catch {
33
+ return { items: [] };
34
+ }
35
+ };
36
+ const customersQ = useQuery({ queryKey: ["co-customers"], queryFn: () => safe(() => fetchCustomers()) });
37
+ const productsQ = useQuery({ queryKey: ["co-products"], queryFn: () => safe(() => fetchProducts()) });
38
+ const pickupQ = useQuery({ queryKey: ["co-pickup"], queryFn: () => safe(() => fetchPickupLocations()) });
39
+ const carriersQ = useQuery({ queryKey: ["co-carriers"], queryFn: () => safe(() => fetchCarriers()) });
40
+ const pickDaysQ = useQuery({
41
+ queryKey: ["co-pickdays"],
42
+ queryFn: async () => { try {
43
+ return await fetchPickDays();
44
+ }
45
+ catch {
46
+ return { pickDays: 0 };
47
+ } },
51
48
  });
52
- }
53
- function useProductsForOrder() {
54
- const fetchCachedList = useServerFn(getFlorydayCachedList);
55
- return useQuery({
56
- queryKey: ["create-order", "products"],
49
+ const customers = customersQ.data?.items ?? [];
50
+ const products = productsQ.data?.items ?? [];
51
+ const pickupLocations = pickupQ.data?.items ?? [];
52
+ const carriers = carriersQ.data?.items ?? [];
53
+ const pickDays = Math.max(0, Number(pickDaysQ.data?.pickDays ?? 0));
54
+ const [customerId, setCustomerId] = useState(null);
55
+ const [deliveryLocationId, setDeliveryLocationId] = useState(null);
56
+ const [pickupLocationId, setPickupLocationId] = useState(null);
57
+ const [carrierId, setCarrierId] = useState(null);
58
+ const [deliveryDate, setDeliveryDate] = useState("");
59
+ const [notes, setNotes] = useState("");
60
+ const [lines, setLines] = useState([
61
+ { product_id: null, product_name: "", quantity: null, unit: "stuks", unit_price: null },
62
+ ]);
63
+ // Afleverlocaties van gekozen klant
64
+ const deliveryLocQ = useQuery({
65
+ queryKey: ["co-delivery-locations", customerId],
66
+ enabled: !!customerId,
57
67
  queryFn: async () => {
58
- const [localRes, floridayList] = await Promise.all([
59
- supabase
60
- .from("products")
61
- .select("id, product, sale_price, unit")
62
- .order("product", { ascending: true })
63
- .limit(2000),
64
- fetchCachedList({ data: { environment: "staging", entity: "trade-items", limit: 5000 } }),
65
- ]);
66
- if (localRes.error)
67
- throw localRes.error;
68
- const out = [];
69
- for (const r of localRes.data ?? []) {
70
- out.push({
71
- id: `local:${r.id}`,
72
- name: r.product ?? "Onbekend product",
73
- source: "local",
74
- price: r.sale_price != null ? Number(r.sale_price) : null,
75
- unit: r.unit ?? null,
76
- });
68
+ try {
69
+ return await fetchDeliveryLocations({ data: { customerId: customerId } });
77
70
  }
78
- for (const r of floridayList.rows ?? []) {
79
- const d = r.data ?? {};
80
- const name = pickStr(d.name) ??
81
- pickStr(d.productName) ??
82
- pickStr(d.tradeItemName) ??
83
- pickStr(d.tradeItemTexts) ??
84
- "Onbekend artikel";
85
- out.push({
86
- id: `floriday:${r.floriday_id}`,
87
- name,
88
- source: "floriday",
89
- price: null,
90
- });
71
+ catch {
72
+ return { items: [] };
91
73
  }
92
- return out;
93
74
  },
94
- staleTime: 60000,
95
75
  });
96
- }
97
- export function CreateOrderPage() {
98
- const navigate = useNavigate();
99
- const queryClient = useQueryClient();
100
- const customersQ = useCustomersForOrder();
101
- const productsQ = useProductsForOrder();
102
- const [customerId, setCustomerId] = useState("");
103
- const [deliveryDate, setDeliveryDate] = useState("");
104
- const [carrier, setCarrier] = useState("");
105
- const [country, setCountry] = useState("");
106
- const [productPickerOpen, setProductPickerOpen] = useState(false);
107
- const [productQuery, setProductQuery] = useState("");
108
- const [selectedProduct, setSelectedProduct] = useState(null);
109
- const [quantity, setQuantity] = useState("");
110
- const [unitPrice, setUnitPrice] = useState("");
111
- const [lines, setLines] = useState([]);
112
- const filteredProducts = useMemo(() => {
113
- const list = productsQ.data ?? [];
114
- const q = productQuery.trim().toLowerCase();
115
- const base = q
116
- ? list.filter((p) => p.name.toLowerCase().includes(q))
117
- : list;
118
- return base.slice(0, 100);
119
- }, [productsQ.data, productQuery]);
120
- const total = lines.reduce((s, l) => s + l.quantity * l.unitPrice, 0);
121
- const addLine = () => {
122
- if (!selectedProduct)
123
- return;
124
- const qty = Number(quantity);
125
- const price = Number(unitPrice);
126
- if (!Number.isFinite(qty) || qty <= 0) {
127
- toast.error("Vul een geldig aantal in");
128
- return;
76
+ const deliveryLocations = deliveryLocQ.data?.items ?? [];
77
+ const selectedLocation = deliveryLocations.find((l) => l.id === deliveryLocationId) ?? null;
78
+ // Reset delivery_location bij klantwissel
79
+ useEffect(() => {
80
+ if (deliveryLocationId && !deliveryLocations.some((l) => l.id === deliveryLocationId)) {
81
+ setDeliveryLocationId(null);
82
+ }
83
+ // eslint-disable-next-line react-hooks/exhaustive-deps
84
+ }, [customerId, deliveryLocQ.data]);
85
+ // Auto-fill vervoerder op basis van gekozen afleverlocatie (één keer per wissel)
86
+ const lastLocRef = useRef(null);
87
+ useEffect(() => {
88
+ if (deliveryLocationId !== lastLocRef.current) {
89
+ lastLocRef.current = deliveryLocationId;
90
+ const loc = deliveryLocations.find((l) => l.id === deliveryLocationId);
91
+ if (loc?.carrier_id)
92
+ setCarrierId(loc.carrier_id);
93
+ else if (deliveryLocationId === null)
94
+ setCarrierId(null);
129
95
  }
130
- if (!Number.isFinite(price) || price < 0) {
131
- toast.error("Vul een geldige prijs in");
96
+ // eslint-disable-next-line react-hooks/exhaustive-deps
97
+ }, [deliveryLocationId, deliveryLocations.length]);
98
+ // Eerst mogelijke leverdatum
99
+ const selectedCarrier = carriers.find((c) => c.id === carrierId) ?? null;
100
+ const carrierDeliveryDays = Math.max(0, Number(selectedCarrier?.delivery_days ?? 0));
101
+ const canPickDate = !!customerId && !!deliveryLocationId && !!pickupLocationId && !!carrierId;
102
+ const fmtISO = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
103
+ const earliestDate = useMemo(() => {
104
+ const base = new Date();
105
+ base.setHours(0, 0, 0, 0);
106
+ base.setDate(base.getDate() + pickDays + carrierDeliveryDays);
107
+ return base;
108
+ }, [pickDays, carrierDeliveryDays]);
109
+ const earliestISO = fmtISO(earliestDate);
110
+ const earliestLabel = earliestDate.toLocaleDateString("nl-NL", {
111
+ day: "numeric", month: "long", year: "numeric",
112
+ });
113
+ useEffect(() => {
114
+ if (!canPickDate)
132
115
  return;
116
+ if (!deliveryDate || deliveryDate < earliestISO) {
117
+ setDeliveryDate(earliestISO);
133
118
  }
134
- setLines((prev) => [
135
- ...prev,
136
- {
137
- key: `${selectedProduct.id}-${Date.now()}`,
138
- product: selectedProduct,
139
- quantity: qty,
140
- unitPrice: price,
141
- },
142
- ]);
143
- setSelectedProduct(null);
144
- setQuantity("");
145
- setUnitPrice("");
146
- setProductQuery("");
119
+ // eslint-disable-next-line react-hooks/exhaustive-deps
120
+ }, [canPickDate, earliestISO]);
121
+ const blockDecimal = (e) => {
122
+ if ([".", ",", "e", "E", "+", "-"].includes(e.key))
123
+ e.preventDefault();
147
124
  };
148
- const removeLine = (key) => setLines((prev) => prev.filter((l) => l.key !== key));
149
- const createMutation = useMutation({
125
+ const createMut = useMutation({
150
126
  mutationFn: async () => {
151
127
  if (!customerId)
152
128
  throw new Error("Selecteer een klant");
129
+ if (!deliveryLocationId)
130
+ throw new Error("Selecteer een afleverlocatie");
131
+ if (!pickupLocationId)
132
+ throw new Error("Selecteer een afhaallocatie (tuin)");
133
+ if (!carrierId)
134
+ throw new Error("Selecteer een vervoerder");
153
135
  if (!deliveryDate)
154
136
  throw new Error("Selecteer een leverdatum");
155
- if (lines.length === 0)
137
+ const validLines = lines.filter((l) => l.product_id && (l.quantity ?? 0) > 0);
138
+ if (validLines.length === 0)
156
139
  throw new Error("Voeg minimaal één product toe");
157
- const customer = customersQ.data?.find((c) => c.id === customerId);
158
- const orderNumber = `LOC-${new Date()
159
- .toISOString()
160
- .slice(0, 10)
161
- .replace(/-/g, "")}-${Math.floor(Math.random() * 9000 + 1000)}`;
162
- const { data: orderRow, error: orderErr } = await supabase
163
- .from("orders")
164
- .insert({
165
- order_number: orderNumber,
166
- customer_id: customerId,
167
- customer_name: customer?.company_name ?? "Onbekende klant",
168
- order_date: new Date().toISOString(),
169
- delivery_date: deliveryDate,
170
- status: "open",
171
- total: String(total.toFixed(2)),
172
- custom_fields: {
173
- source: "local",
174
- transporteur: carrier || null,
175
- land: country || null,
176
- },
177
- })
178
- .select("id")
179
- .single();
180
- if (orderErr)
181
- throw orderErr;
182
- const itemsPayload = lines.map((l) => ({
183
- order_id: orderRow.id,
184
- product_id: l.product.source === "local"
185
- ? l.product.id.replace(/^local:/, "")
186
- : undefined,
187
- product_name: l.product.name,
188
- quantity: Math.round(l.quantity),
189
- unit: l.product.unit ?? undefined,
190
- unit_price: l.unitPrice,
191
- }));
192
- const { error: itemsErr } = await supabase
193
- .from("order_items")
194
- .insert(itemsPayload);
195
- if (itemsErr)
196
- throw itemsErr;
140
+ for (const l of validLines) {
141
+ const p = products.find((x) => x.id === l.product_id);
142
+ const ppc = Math.max(1, Number(p?.plants_per_crate ?? 1));
143
+ const q = l.quantity ?? 0;
144
+ if (q < ppc || q % ppc !== 0) {
145
+ throw new Error(`"${p?.product ?? l.product_name}" moet per hele fust besteld worden (min. 1 fust = ${ppc} planten).`);
146
+ }
147
+ }
148
+ const customer = customers.find((c) => c.id === customerId);
149
+ const payload = {
150
+ customerId,
151
+ customerName: customer?.company_name ?? "Onbekende klant",
152
+ deliveryLocationId,
153
+ pickupLocationId,
154
+ carrierId,
155
+ deliveryDate,
156
+ notes: notes.trim() ? notes.trim() : null,
157
+ lines: validLines.map((l) => {
158
+ const p = products.find((x) => x.id === l.product_id);
159
+ return {
160
+ product_id: l.product_id,
161
+ product_name: p?.product ?? l.product_name ?? "Onbekend product",
162
+ quantity: l.quantity,
163
+ unit: l.unit ?? p?.unit ?? "stuks",
164
+ unit_price: l.unit_price ?? undefined,
165
+ };
166
+ }),
167
+ };
168
+ return await fetchCreate({ data: payload });
197
169
  },
198
170
  onSuccess: () => {
199
171
  toast.success("Bestelling aangemaakt");
200
- queryClient.invalidateQueries({ queryKey: ["floriday", "salesorders-cache"] });
172
+ qc.invalidateQueries({ queryKey: ["floriday", "salesorders-cache"] });
201
173
  navigate({ to: "/floriday-verkoop/verkooporders" });
202
174
  },
203
175
  onError: (e) => toast.error(e?.message ?? "Aanmaken mislukt"),
204
176
  });
205
- return (_jsxs("main", { className: "space-y-5 p-6", children: [_jsx("div", { children: _jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsxs(Link, { to: "/floriday-verkoop/verkooporders", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Terug naar verkooporders"] }) }) }), _jsxs("div", { className: "rounded-lg border border-border bg-card p-6", children: [_jsx("h1", { className: "text-xl font-semibold text-foreground", children: "Nieuwe Bestelling" }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Maak een nieuwe bestelling aan door producten te zoeken en toe te voegen." }), _jsxs("div", { className: "mt-6 grid gap-5 md:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsxs(Label, { children: ["Klant ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsxs(Select, { value: customerId, onValueChange: setCustomerId, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Selecteer klant" }) }), _jsxs(SelectContent, { children: [(customersQ.data ?? []).map((c) => (_jsxs(SelectItem, { value: c.id, children: [c.company_name ?? "Onbekend", c.city ? ` — ${c.city}` : ""] }, c.id))), customersQ.data?.length === 0 && (_jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: "Geen klanten gevonden" }))] })] })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsxs(Label, { htmlFor: "delivery", children: ["Leverdatum ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(Input, { id: "delivery", type: "date", value: deliveryDate, onChange: (e) => setDeliveryDate(e.target.value) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "carrier", children: "Transporteur" }), _jsxs("div", { className: "relative", children: [_jsx(Truck, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { id: "carrier", className: "pl-9", placeholder: "Bv. DHL, PostNL", value: carrier, onChange: (e) => setCarrier(e.target.value) })] })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "country", children: "Land" }), _jsxs("div", { className: "relative", children: [_jsx(MapPin, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { id: "country", className: "pl-9", placeholder: "Bv. Nederland", value: country, onChange: (e) => setCountry(e.target.value) })] })] })] }), _jsxs("div", { className: "mt-8", children: [_jsx(Label, { children: "Producten toevoegen" }), _jsxs("div", { className: "mt-2 flex flex-wrap items-stretch gap-2", children: [_jsx("div", { className: "min-w-[260px] flex-1", children: _jsxs(Popover, { open: productPickerOpen, onOpenChange: setProductPickerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "outline", className: "w-full justify-between font-normal", children: [_jsx("span", { className: selectedProduct ? "" : "text-muted-foreground", children: selectedProduct ? selectedProduct.name : "Zoek product..." }), _jsx(ChevronDown, { className: "h-4 w-4 opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", className: "w-[--radix-popover-trigger-width] p-0", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [_jsx(Search, { className: "h-4 w-4 text-muted-foreground" }), _jsx("input", { autoFocus: true, placeholder: "Zoek product...", value: productQuery, onChange: (e) => setProductQuery(e.target.value), className: "h-8 w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground" })] }), _jsxs("div", { className: "max-h-72 overflow-y-auto py-1", children: [productsQ.isLoading && (_jsx("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: "Laden\u2026" })), !productsQ.isLoading && filteredProducts.length === 0 && (_jsx("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: "Geen producten gevonden." })), filteredProducts.map((p) => (_jsxs("button", { type: "button", onClick: () => {
206
- setSelectedProduct(p);
207
- if (p.price != null && unitPrice === "")
208
- setUnitPrice(p.price);
209
- if (quantity === "")
210
- setQuantity(1);
211
- setProductPickerOpen(false);
212
- }, className: "flex w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm hover:bg-accent", children: [_jsx("span", { className: "truncate", children: p.name }), _jsx(Badge, { variant: "outline", className: p.source === "local"
213
- ? "border-primary/30 text-primary"
214
- : "border-emerald-500/30 text-emerald-600", children: p.source === "local" ? "Lokaal" : "Floriday" })] }, p.id)))] })] })] }) }), _jsx(Input, { type: "number", min: 1, placeholder: "Aantal", className: "w-28", value: quantity, onChange: (e) => setQuantity(e.target.value === "" ? "" : Number(e.target.value)) }), _jsx(Input, { type: "number", min: 0, step: "0.01", placeholder: "\u20AC Prijs", className: "w-32", value: unitPrice, onChange: (e) => setUnitPrice(e.target.value === "" ? "" : Number(e.target.value)) }), _jsx(Button, { type: "button", onClick: addLine, disabled: !selectedProduct, "aria-label": "Toevoegen", children: _jsx(Plus, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "mt-3 rounded-lg border border-dashed border-border bg-muted/30", children: lines.length === 0 ? (_jsx("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Voeg producten toe aan de bestelling" })) : (_jsxs("div", { className: "divide-y divide-border", children: [lines.map((l) => (_jsxs("div", { className: "flex items-center gap-3 px-4 py-3 text-sm", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "truncate font-medium text-foreground", children: l.product.name }), _jsx("div", { className: "text-xs text-muted-foreground", children: l.product.source === "local" ? "Lokaal" : "Floriday" })] }), _jsxs("div", { className: "w-20 text-right", children: [l.quantity, " st."] }), _jsx("div", { className: "w-24 text-right", children: eur.format(l.unitPrice) }), _jsx("div", { className: "w-28 text-right font-medium", children: eur.format(l.quantity * l.unitPrice) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => removeLine(l.key), "aria-label": "Regel verwijderen", children: _jsx(Trash2, { className: "h-4 w-4 text-muted-foreground" }) })] }, l.key))), _jsxs("div", { className: "flex items-center justify-end gap-3 px-4 py-3 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: "Totaal" }), _jsx("span", { className: "text-base font-semibold text-foreground", children: eur.format(total) })] })] })) })] }), _jsxs("div", { className: "mt-8 flex items-center justify-end gap-2", children: [_jsx(Button, { variant: "outline", onClick: () => navigate({ to: "/floriday-verkoop/verkooporders" }), disabled: createMutation.isPending, children: "Annuleren" }), _jsx(Button, { onClick: () => createMutation.mutate(), disabled: createMutation.isPending ||
215
- !customerId ||
216
- !deliveryDate ||
217
- lines.length === 0, children: createMutation.isPending ? "Aanmaken…" : "Bestelling Aanmaken" })] })] })] }));
177
+ return (_jsxs("main", { className: "space-y-5 p-6", children: [_jsx("div", { children: _jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsxs(Link, { to: "/floriday-verkoop/verkooporders", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Terug naar verkooporders"] }) }) }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Nieuwe Bestelling" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Doorloop de stappen: klant \u2192 afleverlocatie \u2192 afhaallocatie \u2192 vervoerder \u2192 leverdatum \u2192 producten." })] }), _jsxs(CardContent, { className: "space-y-5", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs(Label, { className: "flex items-center gap-2", children: ["Klant ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(SearchableSelect, { value: customerId, placeholder: customersQ.isLoading ? "Laden..." : "Kies klant...", options: customers.map((c) => ({ value: c.id, label: c.company_name ?? "Onbekend", hint: c.email ?? undefined })), onChange: (v) => { setCustomerId(v); setDeliveryLocationId(null); }, allowClear: false })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs(Label, { className: "flex items-center gap-2", children: ["Afleverlocatie ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(SearchableSelect, { value: deliveryLocationId, placeholder: !customerId ? "Selecteer eerst een klant"
178
+ : deliveryLocations.length ? "Kies locatie..."
179
+ : "Geen locaties bekend voor deze klant", disabled: !customerId || deliveryLocations.length === 0, allowClear: false, options: deliveryLocations.map((l) => {
180
+ const addr = [
181
+ l.address_line || [l.street, l.house_number].filter(Boolean).join(" "),
182
+ l.postal_code, l.city,
183
+ ].filter(Boolean).join(", ");
184
+ return {
185
+ value: l.id,
186
+ label: (l.name || addr || "Locatie") + (l.is_primary ? " ★" : ""),
187
+ hint: l.name && addr ? addr : undefined,
188
+ };
189
+ }), onChange: setDeliveryLocationId })] }), selectedLocation && (_jsxs("div", { className: "rounded-md border bg-muted/30 p-3 space-y-2", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground", children: "Adresgegevens" }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(ReadOnlyField, { label: "Straat", value: selectedLocation.street }), _jsx(ReadOnlyField, { label: "Huisnummer", value: selectedLocation.house_number }), _jsx(ReadOnlyField, { label: "Postcode", value: selectedLocation.postal_code }), _jsx(ReadOnlyField, { label: "Plaats", value: selectedLocation.city }), _jsx(ReadOnlyField, { label: "Provincie", value: selectedLocation.province }), _jsx(ReadOnlyField, { label: "Land", value: selectedLocation.country })] })] })), _jsxs("div", { className: "space-y-1", children: [_jsxs(Label, { className: "flex items-center gap-2", children: ["Afhaallocatie / Tuin ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(SearchableSelect, { value: pickupLocationId, placeholder: pickupLocations.length ? "Kies eigen locatie..." : "Geen eigen locaties bekend", disabled: pickupLocations.length === 0, allowClear: false, options: pickupLocations.map((l) => ({ value: l.id, label: l.name })), onChange: setPickupLocationId }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Eigen locatie (tuin) van waaruit de bestelling wordt geleverd of opgehaald." })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs(Label, { children: ["Vervoerder ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(SearchableSelect, { value: carrierId, placeholder: !customerId ? "Selecteer eerst een klant"
190
+ : !deliveryLocationId ? "Selecteer eerst een afleverlocatie"
191
+ : "Kies vervoerder...", disabled: !deliveryLocationId, allowClear: false, options: carriers.map((c) => ({
192
+ value: c.id,
193
+ label: c.name + (c.is_default ? " (standaard)" : ""),
194
+ })), onChange: setCarrierId }), selectedLocation?.carrier_id && carrierId && carrierId !== selectedLocation.carrier_id && (_jsx("div", { className: "text-xs text-muted-foreground", children: "Wijkt af van standaard vervoerder van deze locatie \u2014 geldt alleen voor deze bestelling." }))] }), _jsxs("div", { className: "space-y-1", children: [_jsxs(Label, { className: "flex items-center gap-2", children: ["Leverdatum ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(Input, { type: "date", value: canPickDate ? deliveryDate : "", min: canPickDate ? earliestISO : undefined, disabled: !canPickDate, onChange: (e) => {
195
+ const v = e.target.value || "";
196
+ if (v && v < earliestISO) {
197
+ toast.error(`Eerst mogelijke leverdatum is ${earliestLabel}.`);
198
+ setDeliveryDate(earliestISO);
199
+ return;
200
+ }
201
+ setDeliveryDate(v);
202
+ } }), !canPickDate ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "Selecteer eerst klant, afleverlocatie, afhaallocatie en vervoerder." })) : (_jsxs("div", { className: "text-xs text-muted-foreground", children: ["Eerst beschikbare leverdatum is ", earliestLabel, ", o.b.v. orderpicktijd (", pickDays, "d) en levertijd vervoerder (", carrierDeliveryDays, "d)."] }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Bestelregels" }), _jsxs("div", { className: "grid grid-cols-12 gap-2 text-xs text-muted-foreground px-1", children: [_jsx("div", { className: "col-span-5", children: "Product" }), _jsx("div", { className: "col-span-2", children: "Planten" }), _jsx("div", { className: "col-span-2", children: "Fusten" }), _jsx("div", { className: "col-span-2", children: "Prijs" }), _jsx("div", { className: "col-span-1" })] }), lines.map((line, idx) => {
203
+ const product = line.product_id ? products.find((p) => p.id === line.product_id) : null;
204
+ const ppc = Math.max(1, Number(product?.plants_per_crate ?? 1));
205
+ const plants = line.quantity ?? null;
206
+ const cratesDisplay = plants === null ? "" : String(Math.ceil(plants / ppc));
207
+ return (_jsxs("div", { className: "grid grid-cols-12 gap-2 items-start", children: [_jsx("div", { className: "col-span-5", children: _jsx(SearchableSelect, { value: line.product_id, placeholder: "Kies product...", clearLabel: "\u2014 Handmatig \u2014", options: products.map((p) => ({ value: p.id, label: p.product, hint: p.unit })), onChange: (v) => {
208
+ const next = [...lines];
209
+ if (v === null)
210
+ next[idx] = { ...next[idx], product_id: null };
211
+ else {
212
+ const p = products.find((x) => x.id === v);
213
+ const newPpc = Math.max(1, Number(p?.plants_per_crate ?? 1));
214
+ const currentQ = Number(next[idx].quantity ?? 0);
215
+ const normalizedQ = currentQ > 0 ? Math.ceil(currentQ / newPpc) * newPpc : newPpc;
216
+ next[idx] = {
217
+ ...next[idx],
218
+ product_id: v,
219
+ product_name: p?.product ?? "",
220
+ unit: next[idx].unit ?? p?.unit ?? "stuks",
221
+ quantity: normalizedQ,
222
+ unit_price: next[idx].unit_price ?? (p?.sale_price != null ? Number(p.sale_price) : null),
223
+ };
224
+ }
225
+ setLines(next);
226
+ } }) }), _jsx(Input, { className: "col-span-2", type: "number", min: ppc, step: ppc, inputMode: "numeric", onKeyDown: blockDecimal, value: plants ?? "", onChange: (e) => {
227
+ const next = [...lines];
228
+ const raw = e.target.value.replace(/[.,]/g, "");
229
+ const v = raw ? Number(raw) : null;
230
+ const rounded = v === null ? null : Math.max(1, Math.ceil(v / ppc)) * ppc;
231
+ next[idx] = { ...next[idx], quantity: rounded };
232
+ setLines(next);
233
+ }, placeholder: "Planten", title: `Verkoop per hele fust van ${ppc} planten` }), _jsx(Input, { className: "col-span-2", type: "number", min: 1, step: 1, inputMode: "numeric", onKeyDown: blockDecimal, value: cratesDisplay, onChange: (e) => {
234
+ const next = [...lines];
235
+ const raw = e.target.value.replace(/[.,]/g, "");
236
+ const cr = raw ? Math.max(1, Math.floor(Number(raw))) : null;
237
+ next[idx] = { ...next[idx], quantity: cr === null ? null : cr * ppc };
238
+ setLines(next);
239
+ }, placeholder: "Fusten", title: `${ppc} planten per fust` }), _jsx(Input, { className: "col-span-2", type: "number", min: 0, step: "0.01", value: line.unit_price ?? "", onChange: (e) => {
240
+ const next = [...lines];
241
+ const v = e.target.value === "" ? null : Number(e.target.value);
242
+ next[idx] = { ...next[idx], unit_price: v };
243
+ setLines(next);
244
+ }, placeholder: "\u20AC prijs" }), _jsx(Button, { variant: "ghost", size: "icon", className: "col-span-1", onClick: () => setLines(lines.filter((_, i) => i !== idx)), "aria-label": "Regel verwijderen", children: _jsx(Trash2, { className: "h-4 w-4" }) })] }, idx));
245
+ }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setLines([...lines, { product_id: null, product_name: "", quantity: null, unit: "stuks", unit_price: null }]), children: [_jsx(Plus, { className: "h-3 w-3 mr-1" }), " Regel toevoegen"] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Opmerkingen" }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: "Optionele notities bij deze bestelling", rows: 3 })] }), _jsxs("div", { className: "flex items-center justify-end gap-2 pt-2", children: [_jsx(Button, { variant: "outline", onClick: () => navigate({ to: "/floriday-verkoop/verkooporders" }), disabled: createMut.isPending, children: "Annuleren" }), _jsx(Button, { onClick: () => createMut.mutate(), disabled: createMut.isPending, children: createMut.isPending ? "Bezig..." : "Bestelling Aanmaken" })] })] })] })] }));
218
246
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SalesOrderDetailView.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AA4HnE,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,cAAc,GACf,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,2CAiRA"}
1
+ {"version":3,"file":"SalesOrderDetailView.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AA4HnE,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,cAAc,GACf,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,2CAoRA"}
@@ -209,5 +209,5 @@ export function SalesOrderDetailView({ order, sellerFallback, }) {
209
209
  const bestellingLabel = order.status.isCancelled
210
210
  ? "Geannuleerd"
211
211
  : STATUS_LABELS[statusKey] ?? (order.status.isShipped ? "Verzonden" : order.status.isConfirmed ? "Order bevestigd" : "Open");
212
- return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center gap-3 rounded-md border border-border bg-muted/30 p-3", children: [_jsx("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-md bg-muted", children: order.imageUrl ? (_jsx("img", { src: order.imageUrl, alt: "", className: "h-full w-full object-cover" })) : (_jsx(ImageIcon, { className: "h-6 w-6 text-muted-foreground" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "truncate text-base font-semibold text-foreground", children: [order.productName, o.tradeItemVersion ? (_jsxs("span", { className: "ml-2 text-xs font-normal text-muted-foreground", children: ["\u00B7 v", o.tradeItemVersion] })) : null] }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: pickStr(o.customerOrderId) ?? order.sku ?? order.orderNumber })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-6 lg:grid-cols-[1fr_360px]", children: [_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx(SectionTitle, { children: "Verkooporder" }), _jsx(Row, { label: "Handelsvorm", children: tradingType }), _jsx(Row, { label: "Bestelmoment", children: fmtDateTime(order.orderedAt) }), _jsxs(Row, { label: "Aantal", children: [packages, " fusten (", piecesPerPackage, " st/f)"] }), _jsx(Row, { label: "Belading", children: belading }), _jsx(Row, { label: "Klant referentie", children: klantReferentie }), _jsx(Row, { label: "Floriday-referentie", children: floridayRef }), _jsx(Row, { label: "Verkoopkanaal", children: verkoopkanaal }), _jsx(Row, { label: "Financi\u00EBle afhandeling", children: financial }), _jsx(Row, { label: "Verkoper", children: sellerName ? (_jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx("span", { className: "inline-flex h-6 w-6 items-center justify-center rounded-full bg-muted text-[10px] font-semibold text-muted-foreground", children: initials(sellerName) }), sellerName] })) : ("—") })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Levering" }), _jsx(Row, { label: "Afleverdatum", children: fmtDateTime(order.deliveryAt) }), _jsx(Row, { label: "Incoterm", children: incoterm }), _jsx(Row, { label: "Levering", children: _jsxs("div", { className: "inline-flex max-w-xs items-start gap-3 rounded-md border border-border bg-card p-3", children: [_jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-primary/10 text-primary", children: _jsxs("svg", { viewBox: "0 0 24 24", className: "h-5 w-5", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M3 11l9-8 9 8" }), _jsx("path", { d: "M5 10v10h14V10" }), _jsx("path", { d: "M10 20v-6h4v6" })] }) }), _jsxs("div", { className: "text-sm", children: [_jsx("div", { children: addr.line || "—" }), _jsx("div", { children: [addr.postal, addr.city].filter(Boolean).join(" ") || "—" }), _jsx("div", { children: countryLabel ?? "" }), addr.gln && (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: addr.gln }))] })] }) })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Klant" }), _jsx(Row, { label: "Naam", children: _jsx("span", { className: "font-medium", children: customerName }) }), _jsx(Row, { label: "GLN", children: customerGln }), _jsx(Row, { label: "Administratienummer", children: customerAdmin }), _jsx(Row, { label: "Telefoonnummer", children: customerPhone })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Prijs per stuk" }), _jsxs("div", { className: "space-y-2 text-sm", children: [_jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Product" }), _jsxs("span", { children: [oldProductPrice !== null && (_jsx("span", { className: "mr-2 text-destructive line-through", children: eurFlex.format(oldProductPrice) })), eurFlex.format(productUnit)] })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Transportkosten" }), _jsx("span", { children: eurFlex.format(transportPerPiece) })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Inkoopprijs" }), _jsx("span", { children: eurFlex.format(purchaseUnit) })] }), _jsxs("div", { className: "mt-2 flex justify-between border-t border-border pt-2 font-semibold", children: [_jsx("span", { children: "Totaal" }), _jsxs("span", { children: [_jsxs("span", { className: "mr-2 text-xs font-normal text-muted-foreground", children: ["(", packages, " \u00D7 ", piecesPerPackage, " \u00D7 ", eurFlex.format(productUnit), ")"] }), eurFlex.format(totalAmount)] })] })] })] }), _jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Status" }), _jsxs("div", { className: "space-y-3 text-sm", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Bestelling" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), bestellingLabel] })] }), hasCorrection && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Correctie" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), "Correctie is verwerkt"] })] }))] })] })] })] })] }));
212
+ return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center gap-3 rounded-md border border-border bg-muted/30 p-3", children: [_jsx("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-md bg-muted", children: order.imageUrl ? (_jsx("img", { src: order.imageUrl, alt: "", className: "h-full w-full object-cover" })) : (_jsx(ImageIcon, { className: "h-6 w-6 text-muted-foreground" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "truncate text-base font-semibold text-foreground", children: [order.productName, o.tradeItemVersion ? (_jsxs("span", { className: "ml-2 text-xs font-normal text-muted-foreground", children: ["\u00B7 v", o.tradeItemVersion] })) : null] }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: pickStr(o.customerOrderId) ?? order.sku ?? order.orderNumber })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-6 lg:grid-cols-[1fr_360px]", children: [_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx(SectionTitle, { children: "Verkooporder" }), _jsx(Row, { label: "Handelsvorm", children: tradingType }), _jsx(Row, { label: "Bestelmoment", children: fmtDateTime(order.orderedAt) }), _jsx(Row, { label: "Aantal", children: _jsxs("div", { className: "flex flex-wrap gap-4", children: [_jsxs("div", { children: [order.fustCount, " fusten"] }), _jsxs("div", { children: [order.karCount, " karren"] })] }) }), _jsx(Row, { label: "Belading", children: belading }), _jsx(Row, { label: "Klant referentie", children: klantReferentie }), _jsx(Row, { label: "Floriday-referentie", children: floridayRef }), _jsx(Row, { label: "Verkoopkanaal", children: verkoopkanaal }), _jsx(Row, { label: "Financi\u00EBle afhandeling", children: financial }), _jsx(Row, { label: "Verkoper", children: sellerName ? (_jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx("span", { className: "inline-flex h-6 w-6 items-center justify-center rounded-full bg-muted text-[10px] font-semibold text-muted-foreground", children: initials(sellerName) }), sellerName] })) : ("—") })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Levering" }), _jsx(Row, { label: "Afleverdatum", children: fmtDateTime(order.deliveryAt) }), _jsx(Row, { label: "Incoterm", children: incoterm }), _jsx(Row, { label: "Levering", children: _jsxs("div", { className: "inline-flex max-w-xs items-start gap-3 rounded-md border border-border bg-card p-3", children: [_jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-primary/10 text-primary", children: _jsxs("svg", { viewBox: "0 0 24 24", className: "h-5 w-5", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M3 11l9-8 9 8" }), _jsx("path", { d: "M5 10v10h14V10" }), _jsx("path", { d: "M10 20v-6h4v6" })] }) }), _jsxs("div", { className: "text-sm", children: [_jsx("div", { children: addr.line || "—" }), _jsx("div", { children: [addr.postal, addr.city].filter(Boolean).join(" ") || "—" }), _jsx("div", { children: countryLabel ?? "" }), addr.gln && (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: addr.gln }))] })] }) })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Klant" }), _jsx(Row, { label: "Naam", children: _jsx("span", { className: "font-medium", children: customerName }) }), _jsx(Row, { label: "GLN", children: customerGln }), _jsx(Row, { label: "Administratienummer", children: customerAdmin }), _jsx(Row, { label: "Telefoonnummer", children: customerPhone })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Prijs per stuk" }), _jsxs("div", { className: "space-y-2 text-sm", children: [_jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Product" }), _jsxs("span", { children: [oldProductPrice !== null && (_jsx("span", { className: "mr-2 text-destructive line-through", children: eurFlex.format(oldProductPrice) })), eurFlex.format(productUnit)] })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Transportkosten" }), _jsx("span", { children: eurFlex.format(transportPerPiece) })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Inkoopprijs" }), _jsx("span", { children: eurFlex.format(purchaseUnit) })] }), _jsxs("div", { className: "mt-2 flex justify-between border-t border-border pt-2 font-semibold", children: [_jsx("span", { children: "Totaal" }), _jsxs("span", { children: [_jsxs("span", { className: "mr-2 text-xs font-normal text-muted-foreground", children: ["(", packages, " \u00D7 ", piecesPerPackage, " \u00D7 ", eurFlex.format(productUnit), ")"] }), eurFlex.format(totalAmount)] })] })] })] }), _jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Status" }), _jsxs("div", { className: "space-y-3 text-sm", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Bestelling" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), bestellingLabel] })] }), hasCorrection && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Correctie" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), "Correctie is verwerkt"] })] }))] })] })] })] })] }));
213
213
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SalesOrdersTable.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrdersTable.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AA6EnE,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,OAAO,EACP,aAAa,GACd,EAAE;IACD,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,2CA6JA"}
1
+ {"version":3,"file":"SalesOrdersTable.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrdersTable.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAsEnE,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,OAAO,EACP,aAAa,GACd,EAAE;IACD,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,2CAyIA"}