@flowselections/floriday-verkoop-module 1.0.16 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CreateOrderPage.js +12 -12
- package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts +6 -0
- package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts.map +1 -0
- package/dist-lib/components/verkoop/EditLocalOrderDialog.js +102 -0
- package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderKarindelingCard.js +26 -28
- package/dist-lib/components/verkoop/OrderShipmentsCard.d.ts +5 -0
- package/dist-lib/components/verkoop/OrderShipmentsCard.d.ts.map +1 -0
- package/dist-lib/components/verkoop/OrderShipmentsCard.js +137 -0
- package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailPage.js +8 -2
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailView.js +2 -1
- package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersFilters.js +2 -8
- package/dist-lib/components/verkoop/SalesOrdersTable.d.ts +4 -1
- package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersTable.js +2 -2
- package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/VerkoopOrdersPage.js +43 -1
- package/dist-lib/index.js +2 -2
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +607 -169
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +607 -169
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +607 -169
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +623 -164
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/cart-lock.functions.d.ts +607 -169
- package/dist-lib/lib/cart-lock.functions.d.ts.map +1 -1
- package/dist-lib/lib/cart-replan.functions.d.ts +1221 -345
- package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
- package/dist-lib/lib/create-order.functions.d.ts +40700 -1397
- package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
- package/dist-lib/lib/create-order.functions.js +792 -52
- package/dist-lib/lib/expand-group-order-items.d.ts +13 -0
- package/dist-lib/lib/expand-group-order-items.d.ts.map +1 -0
- package/dist-lib/lib/expand-group-order-items.js +216 -0
- package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts +1767 -453
- package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-logistic-labels.functions.d.ts +607 -169
- package/dist-lib/lib/floriday-logistic-labels.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-public.functions.d.ts +4123 -1057
- package/dist-lib/lib/floriday-public.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-writes.functions.d.ts +2945 -755
- package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
- package/dist-lib/lib/order-shipments.functions.d.ts +47158 -0
- package/dist-lib/lib/order-shipments.functions.d.ts.map +1 -0
- package/dist-lib/lib/order-shipments.functions.js +178 -0
- package/dist-lib/lib/salesorders-mapping.d.ts +1 -0
- package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
- package/dist-lib/lib/salesorders.functions.d.ts +1767 -453
- package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
- package/dist-lib/lib/tradeitems.functions.d.ts +607 -169
- package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -1
- package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
- package/dist-lib/lib/useSalesOrdersQuery.js +39 -2
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateOrderPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/CreateOrderPage.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"CreateOrderPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/CreateOrderPage.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,eAAe,4CA6d9B"}
|
|
@@ -11,7 +11,6 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
|
11
11
|
import { ArrowLeft, Plus, Trash2 } from "lucide-react";
|
|
12
12
|
import { useServerFn } from "@tanstack/react-start";
|
|
13
13
|
import { SearchableSelect } from "./SearchableSelect";
|
|
14
|
-
import { CartAssignmentWizard } from "./CartAssignmentWizard";
|
|
15
14
|
import { listCustomersForCreateOrder, listProductsForCreateOrder, listDeliveryLocationsForCustomerCO, listPickupLocationsCO, listCarriersForCreateOrder, getOrderPickDaysCO, createManualOrder, } from "../../lib/create-order.functions";
|
|
16
15
|
function ReadOnlyField({ label, value }) {
|
|
17
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" }) })] }));
|
|
@@ -57,11 +56,11 @@ export function CreateOrderPage() {
|
|
|
57
56
|
const [pickupLocationId, setPickupLocationId] = useState(null);
|
|
58
57
|
const [carrierId, setCarrierId] = useState(null);
|
|
59
58
|
const [deliveryDate, setDeliveryDate] = useState("");
|
|
59
|
+
const [isReservation, setIsReservation] = useState(false);
|
|
60
60
|
const [notes, setNotes] = useState("");
|
|
61
61
|
const [lines, setLines] = useState([
|
|
62
62
|
{ product_id: null, product_name: "", quantity: null, unit: "stuks", unit_price: null },
|
|
63
63
|
]);
|
|
64
|
-
const [cartOrderId, setCartOrderId] = useState(null);
|
|
65
64
|
// Afleverlocaties van gekozen klant
|
|
66
65
|
const deliveryLocQ = useQuery({
|
|
67
66
|
queryKey: ["co-delivery-locations", customerId],
|
|
@@ -134,7 +133,7 @@ export function CreateOrderPage() {
|
|
|
134
133
|
throw new Error("Selecteer een afhaallocatie (tuin)");
|
|
135
134
|
if (!carrierId)
|
|
136
135
|
throw new Error("Selecteer een vervoerder");
|
|
137
|
-
if (!deliveryDate)
|
|
136
|
+
if (!isReservation && !deliveryDate)
|
|
138
137
|
throw new Error("Selecteer een leverdatum");
|
|
139
138
|
const validLines = lines.filter((l) => l.product_id && (l.quantity ?? 0) > 0);
|
|
140
139
|
if (validLines.length === 0)
|
|
@@ -154,7 +153,8 @@ export function CreateOrderPage() {
|
|
|
154
153
|
deliveryLocationId,
|
|
155
154
|
pickupLocationId,
|
|
156
155
|
carrierId,
|
|
157
|
-
deliveryDate,
|
|
156
|
+
deliveryDate: isReservation ? null : deliveryDate,
|
|
157
|
+
isReservation,
|
|
158
158
|
notes: notes.trim() ? notes.trim() : null,
|
|
159
159
|
lines: validLines.map((l) => {
|
|
160
160
|
const p = products.find((x) => x.id === l.product_id);
|
|
@@ -174,10 +174,13 @@ export function CreateOrderPage() {
|
|
|
174
174
|
return await fetchCreate({ data: payload });
|
|
175
175
|
},
|
|
176
176
|
onSuccess: (res) => {
|
|
177
|
-
toast.success("Bestelling aangemaakt —
|
|
177
|
+
toast.success("Bestelling aangemaakt — karindeling is automatisch berekend");
|
|
178
178
|
qc.invalidateQueries({ queryKey: ["floriday", "salesorders-cache"] });
|
|
179
179
|
if (res?.orderId) {
|
|
180
|
-
|
|
180
|
+
navigate({
|
|
181
|
+
to: "/floriday-verkoop/verkooporders/$salesOrderId",
|
|
182
|
+
params: { salesOrderId: `local:${res.orderId}` },
|
|
183
|
+
});
|
|
181
184
|
}
|
|
182
185
|
else {
|
|
183
186
|
navigate({ to: "/floriday-verkoop/verkooporders" });
|
|
@@ -202,7 +205,7 @@ export function CreateOrderPage() {
|
|
|
202
205
|
: "Kies vervoerder...", disabled: !deliveryLocationId, allowClear: false, options: carriers.map((c) => ({
|
|
203
206
|
value: c.id,
|
|
204
207
|
label: c.name + (c.is_default ? " (standaard)" : ""),
|
|
205
|
-
})), 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) => {
|
|
208
|
+
})), 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 ", !isReservation && _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(Input, { type: "date", value: !isReservation && canPickDate ? deliveryDate : "", min: canPickDate ? earliestISO : undefined, disabled: isReservation || !canPickDate, onChange: (e) => {
|
|
206
209
|
const v = e.target.value || "";
|
|
207
210
|
if (v && v < earliestISO) {
|
|
208
211
|
toast.error(`Eerst mogelijke leverdatum is ${earliestLabel}.`);
|
|
@@ -210,7 +213,7 @@ export function CreateOrderPage() {
|
|
|
210
213
|
return;
|
|
211
214
|
}
|
|
212
215
|
setDeliveryDate(v);
|
|
213
|
-
} }), !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) => {
|
|
216
|
+
} }), _jsxs("label", { className: "mt-1 flex items-center gap-2 text-sm text-foreground", children: [_jsx("input", { type: "checkbox", checked: isReservation, onChange: (e) => setIsReservation(e.target.checked), className: "h-4 w-4 rounded border-input" }), "Reservering (nog geen vaste leverdatum)"] }), isReservation ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "De bestelling wordt als reservering aangemaakt zonder leverdatumvalidatie." })) : !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) => {
|
|
214
217
|
const product = line.product_id ? products.find((p) => p.id === line.product_id) : null;
|
|
215
218
|
const ppc = Math.max(1, Number(product?.plants_per_crate ?? 1));
|
|
216
219
|
const plants = line.quantity ?? null;
|
|
@@ -263,8 +266,5 @@ export function CreateOrderPage() {
|
|
|
263
266
|
next[idx] = { ...next[idx], unit_price: v };
|
|
264
267
|
setLines(next);
|
|
265
268
|
}, 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));
|
|
266
|
-
}), _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" })] })] })] })
|
|
267
|
-
setCartOrderId(null);
|
|
268
|
-
navigate({ to: "/floriday-verkoop/verkooporders" });
|
|
269
|
-
} })] }));
|
|
269
|
+
}), _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" })] })] })] })] }));
|
|
270
270
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditLocalOrderDialog.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/EditLocalOrderDialog.tsx"],"names":[],"mappings":"AAoBA,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,IAAI,EACJ,YAAY,GACb,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,kDAyMA"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Button, Input, toast } from "@flowselections/core";
|
|
4
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
6
|
+
import { getLocalOrderForEdit, updateLocalOrder, } from "../../lib/create-order.functions";
|
|
7
|
+
export function EditLocalOrderDialog({ orderId, open, onOpenChange, }) {
|
|
8
|
+
const load = useServerFn(getLocalOrderForEdit);
|
|
9
|
+
const save = useServerFn(updateLocalOrder);
|
|
10
|
+
const queryClient = useQueryClient();
|
|
11
|
+
const [loading, setLoading] = useState(false);
|
|
12
|
+
const [saving, setSaving] = useState(false);
|
|
13
|
+
const [error, setError] = useState(null);
|
|
14
|
+
const [deliveryDate, setDeliveryDate] = useState("");
|
|
15
|
+
const [isReservation, setIsReservation] = useState(false);
|
|
16
|
+
const [items, setItems] = useState([]);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!open)
|
|
19
|
+
return;
|
|
20
|
+
let cancelled = false;
|
|
21
|
+
setLoading(true);
|
|
22
|
+
setError(null);
|
|
23
|
+
load({ data: { orderId } })
|
|
24
|
+
.then((r) => {
|
|
25
|
+
if (cancelled)
|
|
26
|
+
return;
|
|
27
|
+
setDeliveryDate((r.deliveryDate ?? "").slice(0, 10));
|
|
28
|
+
setIsReservation(!!r.isReservation);
|
|
29
|
+
setItems(r.items.map((it) => ({
|
|
30
|
+
id: it.id,
|
|
31
|
+
productName: it.productName,
|
|
32
|
+
quantity: it.quantity,
|
|
33
|
+
unit: it.unit,
|
|
34
|
+
plantsPerCrate: it.plantsPerCrate ?? 1,
|
|
35
|
+
minQuantity: Number(it.minQuantity ?? 0),
|
|
36
|
+
shippedQuantity: Number(it.shippedQuantity ?? 0),
|
|
37
|
+
plannedQuantity: Number(it.plannedQuantity ?? 0),
|
|
38
|
+
})));
|
|
39
|
+
})
|
|
40
|
+
.catch((e) => !cancelled && setError(e?.message ?? "Laden mislukt"))
|
|
41
|
+
.finally(() => !cancelled && setLoading(false));
|
|
42
|
+
return () => {
|
|
43
|
+
cancelled = true;
|
|
44
|
+
};
|
|
45
|
+
}, [open, orderId, load]);
|
|
46
|
+
if (!open)
|
|
47
|
+
return null;
|
|
48
|
+
const setPlants = (idx, plants) => {
|
|
49
|
+
setItems((prev) => prev.map((p, i) => (i === idx ? { ...p, quantity: Number.isFinite(plants) ? Math.max(0, plants) : 0 } : p)));
|
|
50
|
+
};
|
|
51
|
+
const setFusten = (idx, fusten) => {
|
|
52
|
+
setItems((prev) => prev.map((p, i) => {
|
|
53
|
+
if (i !== idx)
|
|
54
|
+
return p;
|
|
55
|
+
const ppc = Math.max(1, p.plantsPerCrate);
|
|
56
|
+
const f = Number.isFinite(fusten) ? Math.max(0, fusten) : 0;
|
|
57
|
+
return { ...p, quantity: f * ppc };
|
|
58
|
+
}));
|
|
59
|
+
};
|
|
60
|
+
const handleSave = async () => {
|
|
61
|
+
for (const it of items) {
|
|
62
|
+
const ppc = Math.max(1, it.plantsPerCrate);
|
|
63
|
+
if (it.quantity < ppc || it.quantity % ppc !== 0) {
|
|
64
|
+
toast.error(`"${it.productName}" moet per hele fust besteld worden (min. 1 fust = ${ppc} planten).`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (it.quantity < it.minQuantity) {
|
|
68
|
+
toast.error(`"${it.productName}" kan niet lager dan ${it.minQuantity} — er is al ${it.shippedQuantity} geleverd en ${it.plannedQuantity} gepland op bezorgmomenten.`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
setSaving(true);
|
|
74
|
+
await save({
|
|
75
|
+
data: {
|
|
76
|
+
orderId,
|
|
77
|
+
deliveryDate: !isReservation && deliveryDate ? deliveryDate : undefined,
|
|
78
|
+
items: items.map((i) => ({ itemId: i.id, quantity: Math.round(i.quantity) })),
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
toast.success("Bestelling bijgewerkt");
|
|
82
|
+
await Promise.all([
|
|
83
|
+
queryClient.invalidateQueries({ queryKey: ["floriday", "salesorders-cache"] }),
|
|
84
|
+
queryClient.invalidateQueries({ queryKey: ["order-shipments", orderId] }),
|
|
85
|
+
queryClient.invalidateQueries({ queryKey: ["order-carts", orderId] }),
|
|
86
|
+
queryClient.invalidateQueries({ queryKey: ["salesorder-detail", orderId] }),
|
|
87
|
+
]);
|
|
88
|
+
onOpenChange(false);
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
toast.error(e?.message ?? "Bijwerken mislukt");
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
setSaving(false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", onClick: () => !saving && onOpenChange(false), children: _jsxs("div", { className: "w-full max-w-xl rounded-lg border border-border bg-card p-6 shadow-lg", onClick: (e) => e.stopPropagation(), children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: "Bestelling bewerken" }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Pas de leverdatum en het aantal planten of fusten per regel aan. Voorraad en karindeling worden automatisch bijgewerkt." }), loading ? (_jsx("div", { className: "mt-6 text-sm text-muted-foreground", children: "Laden\u2026" })) : error ? (_jsx("div", { className: "mt-6 rounded border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive", children: error })) : (_jsxs("div", { className: "mt-5 space-y-4", children: [!isReservation && (_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-foreground", children: "Leverdatum" }), _jsx(Input, { type: "date", value: deliveryDate, onChange: (e) => setDeliveryDate(e.target.value) })] })), isReservation && (_jsx("div", { className: "rounded border border-border bg-muted/40 px-3 py-2 text-xs text-muted-foreground", children: "Dit is een reservering \u2014 er is nog geen leverdatum. Voeg een bezorgmoment toe om (deels) uit te leveren." })), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium text-foreground", children: "Regels" }), _jsxs("div", { className: "grid grid-cols-12 gap-2 px-1 text-xs text-muted-foreground", children: [_jsx("div", { className: "col-span-6", children: "Product" }), _jsx("div", { className: "col-span-3", children: "Planten" }), _jsx("div", { className: "col-span-3", children: "Fusten" })] }), _jsxs("div", { className: "mt-1 space-y-2", children: [items.map((it, idx) => {
|
|
98
|
+
const ppc = Math.max(1, it.plantsPerCrate);
|
|
99
|
+
const fusten = ppc > 0 ? Math.ceil(it.quantity / ppc) : 0;
|
|
100
|
+
return (_jsxs("div", { className: "grid grid-cols-12 items-start gap-2 rounded border border-border p-2", children: [_jsxs("div", { className: "col-span-6 min-w-0 text-sm", children: [_jsx("div", { className: "truncate font-medium text-foreground", children: it.productName }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [ppc, " planten per fust"] }), it.minQuantity > 0 && (_jsxs("div", { className: "text-xs text-primary", children: ["min. ", it.minQuantity, " (reeds ", it.shippedQuantity, " geleverd, ", it.plannedQuantity, " gepland)"] }))] }), _jsx("div", { className: "col-span-3", children: _jsx(Input, { type: "number", min: 0, step: ppc, value: it.quantity, onChange: (e) => setPlants(idx, Number(e.target.value)) }) }), _jsx("div", { className: "col-span-3", children: _jsx(Input, { type: "number", min: 0, step: 1, value: fusten, onChange: (e) => setFusten(idx, Number(e.target.value)) }) })] }, it.id));
|
|
101
|
+
}), items.length === 0 && (_jsx("div", { className: "text-sm text-muted-foreground", children: "Geen regels op deze bestelling." }))] })] })] })), _jsxs("div", { className: "mt-6 flex justify-end gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => onOpenChange(false), disabled: saving, children: "Annuleren" }), _jsx(Button, { size: "sm", onClick: handleSave, disabled: saving || loading || !!error, children: saving ? "Bezig…" : "Opslaan" })] })] }) }));
|
|
102
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrderKarindelingCard.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/OrderKarindelingCard.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"OrderKarindelingCard.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/OrderKarindelingCard.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AA8F/D,wBAAgB,oBAAoB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,2CAgLvE"}
|
|
@@ -9,6 +9,7 @@ import { Badge, Card, CardContent, CardHeader, CardTitle, Table, TableBody, Tabl
|
|
|
9
9
|
import { CheckCircle2, Lock } from "lucide-react";
|
|
10
10
|
import { supabase } from "../../integrations/supabase/client";
|
|
11
11
|
import { planCarts } from "../../lib/cart-planner";
|
|
12
|
+
import { expandOrderItemsForPlanner } from "../../lib/expand-group-order-items";
|
|
12
13
|
function deriveCartsFromFloriday(order) {
|
|
13
14
|
const o = order.raw.order ?? {};
|
|
14
15
|
const pack = o?.packingConfiguration ?? {};
|
|
@@ -74,6 +75,7 @@ export function OrderKarindelingCard({ order }) {
|
|
|
74
75
|
const orderId = typeof rawId === "string" ? rawId.replace(/^(local:|mailbox-proposal:)/, "") : rawId;
|
|
75
76
|
const [lockedAt, setLockedAt] = useState(null);
|
|
76
77
|
const [dbItems, setDbItems] = useState(null);
|
|
78
|
+
const [plannerInputs, setPlannerInputs] = useState(null);
|
|
77
79
|
// Laadt order_items + gekoppelde products (voorraad-belading) en
|
|
78
80
|
// ververst live bij mutaties op order_items, orders of products.
|
|
79
81
|
useEffect(() => {
|
|
@@ -90,8 +92,24 @@ export function OrderKarindelingCard({ order }) {
|
|
|
90
92
|
]);
|
|
91
93
|
if (!active)
|
|
92
94
|
return;
|
|
93
|
-
|
|
95
|
+
const items = itemRows ?? [];
|
|
96
|
+
setDbItems(items);
|
|
94
97
|
setLockedAt(orderRow?.plan_locked_at ?? null);
|
|
98
|
+
// Alle order_items doorgeven — expand-helper resolveert zelf groepen
|
|
99
|
+
// (via product_id óf via naamprefix "[Groep] ...") en losse artikelen.
|
|
100
|
+
const raws = items.map((it) => ({
|
|
101
|
+
id: it.id,
|
|
102
|
+
product_id: it.product_id,
|
|
103
|
+
product_name: it.product_name,
|
|
104
|
+
quantity: Number(it.quantity ?? 0),
|
|
105
|
+
plants_per_crate: Math.max(1, Number(it.products?.plants_per_crate ?? 1)),
|
|
106
|
+
crates_per_layer: Math.max(1, Number(it.products?.crates_per_layer ?? 1)),
|
|
107
|
+
layers_per_cart: Math.max(1, Number(it.products?.layers_per_cart ?? 1)),
|
|
108
|
+
}));
|
|
109
|
+
const expanded = await expandOrderItemsForPlanner(supabase, raws);
|
|
110
|
+
if (!active)
|
|
111
|
+
return;
|
|
112
|
+
setPlannerInputs(expanded);
|
|
95
113
|
};
|
|
96
114
|
void load();
|
|
97
115
|
const channel = supabase
|
|
@@ -105,36 +123,16 @@ export function OrderKarindelingCard({ order }) {
|
|
|
105
123
|
void supabase.removeChannel(channel);
|
|
106
124
|
};
|
|
107
125
|
}, [orderId]);
|
|
108
|
-
// Bouw plannerinput
|
|
109
|
-
//
|
|
126
|
+
// Bouw plannerinput. Bij een groep-order_item zijn de sub-items al
|
|
127
|
+
// opgesplitst met member-belading; anders is er één regel per item.
|
|
110
128
|
const plannerCarts = useMemo(() => {
|
|
111
|
-
if (!
|
|
129
|
+
if (!plannerInputs || plannerInputs.length === 0) {
|
|
130
|
+
if (dbItems && dbItems.length > 0)
|
|
131
|
+
return null;
|
|
112
132
|
return null;
|
|
113
|
-
const inputs = [];
|
|
114
|
-
for (const it of dbItems) {
|
|
115
|
-
const p = it.products;
|
|
116
|
-
if (!it.product_id || !p)
|
|
117
|
-
continue;
|
|
118
|
-
const ppc = Math.max(1, Number(p.plants_per_crate ?? 0));
|
|
119
|
-
const cpl = Math.max(1, Number(p.crates_per_layer ?? 0));
|
|
120
|
-
const lpc = Math.max(1, Number(p.layers_per_cart ?? 0));
|
|
121
|
-
const plants = Math.max(0, Number(it.quantity ?? 0));
|
|
122
|
-
if (plants <= 0)
|
|
123
|
-
continue;
|
|
124
|
-
inputs.push({
|
|
125
|
-
order_item_id: it.id,
|
|
126
|
-
product_id: it.product_id,
|
|
127
|
-
product_name: it.product_name,
|
|
128
|
-
plants,
|
|
129
|
-
plants_per_crate: ppc,
|
|
130
|
-
crates_per_layer: cpl,
|
|
131
|
-
layers_per_cart: lpc,
|
|
132
|
-
});
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return planCarts(inputs).carts;
|
|
137
|
-
}, [dbItems]);
|
|
134
|
+
return planCarts(plannerInputs).carts;
|
|
135
|
+
}, [plannerInputs, dbItems]);
|
|
138
136
|
const floridayCarts = useMemo(() => deriveCartsFromFloriday(order), [order]);
|
|
139
137
|
const usingVoorraad = plannerCarts !== null;
|
|
140
138
|
const carts = usingVoorraad
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OrderShipmentsCard.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/OrderShipmentsCard.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AA4C/D,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,kDASrE"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// Bezorgmomenten (deelleveringen) voor een bestelling.
|
|
3
|
+
// Toont totalen (besteld / gepland / geleverd / openstaand), lijst met shipments
|
|
4
|
+
// en knoppen om nieuwe bezorgmomenten aan te maken en te markeren als geleverd.
|
|
5
|
+
import { useMemo, useState } from "react";
|
|
6
|
+
import { Badge, Button, Card, CardContent, CardHeader, CardTitle, Input, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, toast, } from "@flowselections/core";
|
|
7
|
+
import { CalendarPlus, CheckCircle2, Trash2, Truck } from "lucide-react";
|
|
8
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
9
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
10
|
+
import { cancelShipment, createShipment, listOrderShipments, markShipmentShipped, } from "../../lib/order-shipments.functions";
|
|
11
|
+
function formatDate(iso) {
|
|
12
|
+
if (!iso)
|
|
13
|
+
return "—";
|
|
14
|
+
const d = new Date(iso);
|
|
15
|
+
if (Number.isNaN(d.getTime()))
|
|
16
|
+
return iso;
|
|
17
|
+
return d.toLocaleDateString("nl-NL", { day: "numeric", month: "short", year: "numeric" });
|
|
18
|
+
}
|
|
19
|
+
export function OrderShipmentsCard({ order }) {
|
|
20
|
+
// Alleen lokale (en dus reserveer-bare) orders ondersteunen deelleveringen.
|
|
21
|
+
const rawId = order.isLocal && order.id.startsWith("local:")
|
|
22
|
+
? order.id.slice("local:".length)
|
|
23
|
+
: null;
|
|
24
|
+
if (!rawId)
|
|
25
|
+
return null;
|
|
26
|
+
return _jsx(OrderShipmentsInner, { orderId: rawId });
|
|
27
|
+
}
|
|
28
|
+
function OrderShipmentsInner({ orderId }) {
|
|
29
|
+
const list = useServerFn(listOrderShipments);
|
|
30
|
+
const create = useServerFn(createShipment);
|
|
31
|
+
const markShipped = useServerFn(markShipmentShipped);
|
|
32
|
+
const cancel = useServerFn(cancelShipment);
|
|
33
|
+
const queryClient = useQueryClient();
|
|
34
|
+
const [openCreate, setOpenCreate] = useState(false);
|
|
35
|
+
const { data, isLoading } = useQuery({
|
|
36
|
+
queryKey: ["order-shipments", orderId],
|
|
37
|
+
queryFn: () => list({ data: { orderId } }),
|
|
38
|
+
});
|
|
39
|
+
const totals = data?.totals ?? [];
|
|
40
|
+
const shipments = data?.shipments ?? [];
|
|
41
|
+
const summed = useMemo(() => {
|
|
42
|
+
return totals.reduce((a, t) => ({
|
|
43
|
+
ordered: a.ordered + t.ordered,
|
|
44
|
+
shipped: a.shipped + t.shipped,
|
|
45
|
+
planned: a.planned + t.planned,
|
|
46
|
+
outstanding: a.outstanding + t.outstanding,
|
|
47
|
+
}), { ordered: 0, shipped: 0, planned: 0, outstanding: 0 });
|
|
48
|
+
}, [totals]);
|
|
49
|
+
const refresh = () => {
|
|
50
|
+
queryClient.invalidateQueries({ queryKey: ["order-shipments", orderId] });
|
|
51
|
+
queryClient.invalidateQueries({ queryKey: ["floriday", "salesorders-cache"] });
|
|
52
|
+
};
|
|
53
|
+
const hasOpen = totals.some((t) => t.remaining > 0);
|
|
54
|
+
const allShipped = totals.length > 0 && summed.outstanding === 0;
|
|
55
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsx(CardTitle, { className: "text-base", children: "Bezorgmomenten & deelleveringen" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Badge, { variant: allShipped ? "default" : "secondary", children: [summed.shipped, " / ", summed.ordered, " geleverd"] }), _jsxs(Button, { size: "sm", onClick: () => setOpenCreate(true), disabled: !hasOpen, title: hasOpen ? "" : "Er zijn geen openstaande aantallen meer.", children: [_jsx(CalendarPlus, { className: "mr-2 h-4 w-4" }), "Nieuw bezorgmoment"] })] })] }), _jsx(CardContent, { className: "space-y-6", children: isLoading ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Laden\u2026" })) : (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium", children: "Voortgang per artikel" }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Artikel" }), _jsx(TableHead, { className: "text-right", children: "Besteld" }), _jsx(TableHead, { className: "text-right", children: "Gepland" }), _jsx(TableHead, { className: "text-right", children: "Geleverd" }), _jsx(TableHead, { className: "text-right", children: "Nog te leveren" })] }) }), _jsx(TableBody, { children: totals.map((t) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: t.product_name }), _jsx(TableCell, { className: "text-right", children: t.ordered }), _jsx(TableCell, { className: "text-right", children: t.planned }), _jsx(TableCell, { className: "text-right", children: t.shipped }), _jsx(TableCell, { className: "text-right", children: _jsx("span", { className: t.outstanding > 0 ? "font-semibold text-primary" : "text-muted-foreground", children: t.outstanding }) })] }, t.order_item_id))) })] })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium", children: "Bezorgmomenten" }), shipments.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen bezorgmomenten aangemaakt. Maak er \u00E9\u00E9n aan om (deels) uit te leveren." })) : (_jsx("div", { className: "space-y-3", children: shipments.map((s) => (_jsxs("div", { className: "rounded-md border border-border", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 border-b border-border bg-muted/30 px-3 py-2 text-sm", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "font-mono font-medium", children: ["Levering #", s.shipment_number] }), _jsx("span", { className: "text-muted-foreground", children: formatDate(s.delivery_date) }), _jsxs(Badge, { variant: s.status === "shipped" ? "default" : "secondary", className: "gap-1", children: [s.status === "shipped" && _jsx(CheckCircle2, { className: "h-3 w-3" }), s.status === "shipped"
|
|
56
|
+
? "Geleverd"
|
|
57
|
+
: s.status === "cancelled"
|
|
58
|
+
? "Geannuleerd"
|
|
59
|
+
: "Gepland"] })] }), _jsx("div", { className: "flex gap-2", children: s.status === "planned" && (_jsxs(_Fragment, { children: [_jsxs(Button, { size: "sm", variant: "default", onClick: async () => {
|
|
60
|
+
try {
|
|
61
|
+
await markShipped({ data: { shipmentId: s.id } });
|
|
62
|
+
toast.success("Bezorgmoment geleverd");
|
|
63
|
+
refresh();
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
toast.error(e?.message ?? "Markeren mislukt");
|
|
67
|
+
}
|
|
68
|
+
}, children: [_jsx(Truck, { className: "mr-2 h-4 w-4" }), "Markeer geleverd"] }), _jsx(Button, { size: "sm", variant: "outline", onClick: async () => {
|
|
69
|
+
if (!confirm("Bezorgmoment verwijderen?"))
|
|
70
|
+
return;
|
|
71
|
+
try {
|
|
72
|
+
await cancel({ data: { shipmentId: s.id } });
|
|
73
|
+
toast.success("Bezorgmoment verwijderd");
|
|
74
|
+
refresh();
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
toast.error(e?.message ?? "Verwijderen mislukt");
|
|
78
|
+
}
|
|
79
|
+
}, children: _jsx(Trash2, { className: "h-4 w-4" }) })] })) })] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Artikel" }), _jsx(TableHead, { className: "text-right", children: "Aantal" })] }) }), _jsx(TableBody, { children: s.order_shipment_items.map((i) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: i.product_name }), _jsx(TableCell, { className: "text-right", children: i.quantity })] }, i.id))) })] })] }, s.id))) }))] })] })) })] }), openCreate && (_jsx(CreateShipmentDialog, { orderId: orderId, totals: totals.filter((t) => t.remaining > 0), onClose: () => setOpenCreate(false), onCreated: () => {
|
|
80
|
+
setOpenCreate(false);
|
|
81
|
+
refresh();
|
|
82
|
+
}, create: create }))] }));
|
|
83
|
+
}
|
|
84
|
+
function CreateShipmentDialog({ orderId, totals, onClose, onCreated, create, }) {
|
|
85
|
+
const [deliveryDate, setDeliveryDate] = useState(() => {
|
|
86
|
+
const d = new Date();
|
|
87
|
+
d.setDate(d.getDate() + 1);
|
|
88
|
+
return d.toISOString().slice(0, 10);
|
|
89
|
+
});
|
|
90
|
+
const [qtyByItem, setQtyByItem] = useState(() => {
|
|
91
|
+
const init = {};
|
|
92
|
+
for (const t of totals)
|
|
93
|
+
init[t.order_item_id] = 0;
|
|
94
|
+
return init;
|
|
95
|
+
});
|
|
96
|
+
const [saving, setSaving] = useState(false);
|
|
97
|
+
const items = totals.map((t) => ({
|
|
98
|
+
total: t,
|
|
99
|
+
qty: qtyByItem[t.order_item_id] ?? 0,
|
|
100
|
+
}));
|
|
101
|
+
const canSave = items.some((i) => i.qty > 0) && !!deliveryDate;
|
|
102
|
+
const handleSave = async () => {
|
|
103
|
+
setSaving(true);
|
|
104
|
+
try {
|
|
105
|
+
const selected = items.filter((i) => i.qty > 0);
|
|
106
|
+
await create({
|
|
107
|
+
data: {
|
|
108
|
+
orderId,
|
|
109
|
+
deliveryDate,
|
|
110
|
+
items: selected.map((i) => ({
|
|
111
|
+
orderItemId: i.total.order_item_id,
|
|
112
|
+
productId: i.total.product_id,
|
|
113
|
+
productName: i.total.product_name,
|
|
114
|
+
quantity: i.qty,
|
|
115
|
+
})),
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
toast.success("Bezorgmoment aangemaakt");
|
|
119
|
+
onCreated();
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
toast.error(e?.message ?? "Aanmaken mislukt");
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
setSaving(false);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", onClick: () => !saving && onClose(), children: _jsxs("div", { className: "w-full max-w-xl rounded-lg border border-border bg-card p-6 shadow-lg", onClick: (e) => e.stopPropagation(), children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: "Nieuw bezorgmoment" }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Geef aan wat er op deze datum wordt geleverd. Aantallen mogen niet hoger zijn dan het openstaande aantal." }), _jsxs("div", { className: "mt-5 space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium", children: "Bezorgdatum" }), _jsx(Input, { type: "date", value: deliveryDate, onChange: (e) => setDeliveryDate(e.target.value) })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-medium", children: "Regels" }), _jsxs("div", { className: "space-y-2", children: [items.map((i) => {
|
|
129
|
+
const ppc = Math.max(1, i.total.plants_per_crate ?? 1);
|
|
130
|
+
const remainingFusten = Math.floor(i.total.remaining / ppc);
|
|
131
|
+
const qtyFusten = Math.floor(i.qty / ppc);
|
|
132
|
+
return (_jsxs("div", { className: "grid grid-cols-12 items-center gap-2 rounded border border-border p-2", children: [_jsxs("div", { className: "col-span-6 min-w-0", children: [_jsx("div", { className: "truncate text-sm font-medium", children: i.total.product_name }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["openstaand: ", remainingFusten, " fusten (", i.total.remaining, " planten) \u00B7 ", ppc, "/fust"] })] }), _jsx("div", { className: "col-span-3", children: _jsx(Input, { type: "number", min: 0, max: remainingFusten, step: 1, value: qtyFusten, onChange: (e) => {
|
|
133
|
+
const f = Math.max(0, Math.min(remainingFusten, Number(e.target.value) || 0));
|
|
134
|
+
setQtyByItem((prev) => ({ ...prev, [i.total.order_item_id]: f * ppc }));
|
|
135
|
+
} }) }), _jsx("div", { className: "col-span-1 text-xs text-muted-foreground", children: "fusten" }), _jsx("div", { className: "col-span-2 flex gap-1", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setQtyByItem((prev) => ({ ...prev, [i.total.order_item_id]: remainingFusten * ppc })), children: "Alles" }) })] }, i.total.order_item_id));
|
|
136
|
+
}), items.length === 0 && (_jsx("div", { className: "text-sm text-muted-foreground", children: "Geen openstaande aantallen." }))] })] })] }), _jsxs("div", { className: "mt-6 flex justify-end gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: onClose, disabled: saving, children: "Annuleren" }), _jsx(Button, { size: "sm", onClick: handleSave, disabled: !canSave || saving, children: saving ? "Bezig…" : "Aanmaken" })] })] }) }));
|
|
137
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SalesOrderDetailPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SalesOrderDetailPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailPage.tsx"],"names":[],"mappings":"AAQA,wBAAgB,oBAAoB,4CA0DnC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
2
3
|
import { Link, useParams } from "@tanstack/react-router";
|
|
3
4
|
import { Button } from "@flowselections/core";
|
|
4
|
-
import { ArrowLeft } from "lucide-react";
|
|
5
|
+
import { ArrowLeft, Pencil } from "lucide-react";
|
|
5
6
|
import { SalesOrderDetailView } from "../../components/verkoop/SalesOrderDetailView";
|
|
7
|
+
import { EditLocalOrderDialog } from "../../components/verkoop/EditLocalOrderDialog";
|
|
6
8
|
import { useSalesOrdersQuery } from "../../lib/useSalesOrdersQuery";
|
|
7
9
|
export function SalesOrderDetailPage() {
|
|
8
10
|
const { salesOrderId } = useParams({
|
|
@@ -10,5 +12,9 @@ export function SalesOrderDetailPage() {
|
|
|
10
12
|
});
|
|
11
13
|
const { data, isLoading, error } = useSalesOrdersQuery();
|
|
12
14
|
const order = data?.orders.find((o) => o.id === salesOrderId) ?? null;
|
|
13
|
-
|
|
15
|
+
const [editOpen, setEditOpen] = useState(false);
|
|
16
|
+
const rawLocalId = order?.isLocal && order.id.startsWith("local:")
|
|
17
|
+
? order.id.slice("local:".length)
|
|
18
|
+
: null;
|
|
19
|
+
return (_jsxs("main", { className: "space-y-5 p-6", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", 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"] }) }), rawLocalId && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setEditOpen(true), children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), "Bestelling bewerken"] }))] }), isLoading && (_jsx("div", { className: "rounded-lg border border-border bg-card p-8 text-sm text-muted-foreground", children: "Laden\u2026" })), error && (_jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive", children: error.message })), !isLoading && !error && !order && (_jsx("div", { className: "rounded-lg border border-border bg-card p-8 text-sm text-muted-foreground", children: "Order niet gevonden." })), order && (_jsx(SalesOrderDetailView, { order: order, sellerFallback: data?.sellerFallback ?? null })), rawLocalId && (_jsx(EditLocalOrderDialog, { orderId: rawLocalId, open: editOpen, onOpenChange: setEditOpen }))] }));
|
|
14
20
|
}
|
|
@@ -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;
|
|
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;AAiInE,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,cAAc,GACf,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,2CAgSA"}
|
|
@@ -3,6 +3,7 @@ import { CheckCircle2, ImageIcon } from "lucide-react";
|
|
|
3
3
|
import { OrderKarindelingCard } from "./OrderKarindelingCard";
|
|
4
4
|
import { OrderAfleverbrievenCard } from "./OrderAfleverbrievenCard";
|
|
5
5
|
import { AutoFulfillmentStatusCard } from "./AutoFulfillmentStatusCard";
|
|
6
|
+
import { OrderShipmentsCard } from "./OrderShipmentsCard";
|
|
6
7
|
const eurFlex = new Intl.NumberFormat("nl-NL", {
|
|
7
8
|
style: "currency",
|
|
8
9
|
currency: "EUR",
|
|
@@ -212,5 +213,5 @@ export function SalesOrderDetailView({ order, sellerFallback, }) {
|
|
|
212
213
|
const bestellingLabel = order.status.isCancelled
|
|
213
214
|
? "Geannuleerd"
|
|
214
215
|
: STATUS_LABELS[statusKey] ?? (order.status.isShipped ? "Verzonden" : order.status.isConfirmed ? "Order bevestigd" : "Open");
|
|
215
|
-
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: order.orderNumber || order.sku || "—" })] })] }), _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: "Ordernummer", children: order.orderNumber || "—" }), _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"] })] }))] })] })] })] }), _jsx(OrderKarindelingCard, { order: order }), o?.salesOrderId ? (_jsxs(_Fragment, { children: [_jsx(AutoFulfillmentStatusCard, { salesOrderId: String(o.salesOrderId) }), _jsx(OrderAfleverbrievenCard, { salesOrderId: String(o.salesOrderId) })] })) : null] }));
|
|
216
|
+
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: order.orderNumber || order.sku || "—" })] })] }), _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: "Ordernummer", children: order.orderNumber || "—" }), _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"] })] }))] })] })] })] }), _jsx(OrderShipmentsCard, { order: order }), _jsx(OrderKarindelingCard, { order: order }), o?.salesOrderId ? (_jsxs(_Fragment, { children: [_jsx(AutoFulfillmentStatusCard, { salesOrderId: String(o.salesOrderId) }), _jsx(OrderAfleverbrievenCard, { salesOrderId: String(o.salesOrderId) })] })) : null] }));
|
|
216
217
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SalesOrdersFilters.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrdersFilters.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SalesOrdersFilters.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrdersFilters.tsx"],"names":[],"mappings":"AA4BA,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACnE;AAoCD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC,2CA0NA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, Input, Popover, PopoverContent, PopoverTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
|
|
4
|
-
import { ChevronDown, ChevronLeft, ChevronRight, MoreVertical,
|
|
4
|
+
import { ChevronDown, ChevronLeft, ChevronRight, MoreVertical, Search, } from "lucide-react";
|
|
5
5
|
import { WeekCalendar } from "./WeekCalendar";
|
|
6
6
|
function getCurrentWeek() {
|
|
7
7
|
const now = new Date();
|
|
@@ -127,13 +127,7 @@ export function SalesOrdersFilters({ value, onChange, }) {
|
|
|
127
127
|
return (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("div", { className: "flex h-9 items-center gap-1 rounded-md border border-border bg-card px-1", children: [showArrows && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: () => shiftPeriod(-1), className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", "aria-label": "Vorige", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: () => shiftPeriod(1), className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", "aria-label": "Volgende", children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] })), period === "month" ? (_jsxs(Select, { value: `${monthYear}-${month}`, onValueChange: (v) => {
|
|
128
128
|
const [y, m] = v.split("-").map(Number);
|
|
129
129
|
onChange({ ...value, month: m, monthYear: y });
|
|
130
|
-
}, children: [_jsx(SelectTrigger, { className: "h-7 w-36 border-0 bg-transparent px-2 text-sm font-medium text-foreground shadow-none focus:ring-0", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: monthOptions.map((opt) => (_jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value))) })] })) : period === "day" ? (_jsx(Input, { type: "date", value: day, onChange: (e) => onChange({ ...value, day: e.target.value }), className: "h-7 w-40 border-0 bg-transparent px-2 text-sm font-medium text-foreground shadow-none focus-visible:ring-0" })) : period === "custom" ? (_jsxs("div", { className: "flex items-center gap-1 px-2", children: [_jsx(Input, { type: "date", value: value.customFrom ?? todayYmd, onChange: (e) => onChange({ ...value, customFrom: e.target.value }), className: "h-7 w-36 border-0 bg-transparent px-1 text-sm font-medium text-foreground shadow-none focus-visible:ring-0" }), _jsx("span", { className: "text-muted-foreground", children: "\u2013" }), _jsx(Input, { type: "date", value: value.customTo ?? todayYmd, onChange: (e) => onChange({ ...value, customTo: e.target.value }), className: "h-7 w-36 border-0 bg-transparent px-1 text-sm font-medium text-foreground shadow-none focus-visible:ring-0" })] })) : period === "last7" || period === "last30" ? (_jsx("span", { className: "px-2 text-sm font-medium text-foreground whitespace-nowrap", children: period === "last7" ? "Afgelopen 7 dagen" : "Afgelopen 30 dagen" })) : (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "px-2 text-sm font-medium text-foreground whitespace-nowrap rounded hover:bg-accent h-7", "aria-label": "Kies week", children: ["Week ", week, " - ", year] }) }), _jsx(PopoverContent, { className: "w-auto p-0 pointer-events-auto", align: "start", children: _jsx(WeekCalendar, { week: week, year: year, onSelect: (w, y) => onChange({ ...value, week: w, year: y }) }) })] })), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", "aria-label": "Periode-opties", children: _jsx(MoreVertical, { className: "h-4 w-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsxs(DropdownMenuRadioGroup, { value: period, onValueChange: (v) => handlePeriodChange(v), children: [_jsx(DropdownMenuRadioItem, { value: "day", children: "Dag" }), _jsx(DropdownMenuRadioItem, { value: "week", children: "Week" }), _jsx(DropdownMenuRadioItem, { value: "month", children: "Maand" }), _jsx(DropdownMenuRadioItem, { value: "last7", children: "Afgelopen 7 dagen" }), _jsx(DropdownMenuRadioItem, { value: "last30", children: "Afgelopen 30 dagen" }), _jsx(DropdownMenuRadioItem, { value: "custom", children: "Aangepast tijdsbestek" })] }), _jsx(DropdownMenuSeparator, {}), _jsxs("div", { className: "px-2 py-1.5 text-sm text-muted-foreground inline-flex items-center gap-1", children: [periodLabel(), _jsx(ChevronDown, { className: "h-3.5 w-3.5" })] })] })] })] }), _jsxs("div", { className: "flex h-9 items-center rounded-md border border-border bg-card", children: [_jsx(
|
|
131
|
-
((value.dateField ?? "ordered") === "ordered"
|
|
132
|
-
? "bg-accent text-foreground"
|
|
133
|
-
: "text-muted-foreground hover:bg-accent hover:text-foreground"), "aria-label": "Filter op besteldatum", title: "Filter op besteldatum", "aria-pressed": (value.dateField ?? "ordered") === "ordered", children: _jsx(ShoppingCart, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: () => onChange({ ...value, dateField: "delivery" }), className: "inline-flex h-9 w-9 items-center justify-center rounded-r-md " +
|
|
134
|
-
(value.dateField === "delivery"
|
|
135
|
-
? "bg-accent text-foreground"
|
|
136
|
-
: "text-muted-foreground hover:bg-accent hover:text-foreground"), "aria-label": "Filter op transportdatum", title: "Filter op transportdatum", "aria-pressed": value.dateField === "delivery", children: _jsx(Truck, { className: "h-4 w-4" }) })] }), _jsxs("div", { className: "flex h-9 items-center overflow-hidden rounded-md border border-border bg-card", children: [_jsx(Input, { placeholder: "Op briefnummer zoeken", value: search, onChange: (e) => setSearch(e.target.value), onKeyDown: (e) => {
|
|
130
|
+
}, children: [_jsx(SelectTrigger, { className: "h-7 w-36 border-0 bg-transparent px-2 text-sm font-medium text-foreground shadow-none focus:ring-0", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: monthOptions.map((opt) => (_jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value))) })] })) : period === "day" ? (_jsx(Input, { type: "date", value: day, onChange: (e) => onChange({ ...value, day: e.target.value }), className: "h-7 w-40 border-0 bg-transparent px-2 text-sm font-medium text-foreground shadow-none focus-visible:ring-0" })) : period === "custom" ? (_jsxs("div", { className: "flex items-center gap-1 px-2", children: [_jsx(Input, { type: "date", value: value.customFrom ?? todayYmd, onChange: (e) => onChange({ ...value, customFrom: e.target.value }), className: "h-7 w-36 border-0 bg-transparent px-1 text-sm font-medium text-foreground shadow-none focus-visible:ring-0" }), _jsx("span", { className: "text-muted-foreground", children: "\u2013" }), _jsx(Input, { type: "date", value: value.customTo ?? todayYmd, onChange: (e) => onChange({ ...value, customTo: e.target.value }), className: "h-7 w-36 border-0 bg-transparent px-1 text-sm font-medium text-foreground shadow-none focus-visible:ring-0" })] })) : period === "last7" || period === "last30" ? (_jsx("span", { className: "px-2 text-sm font-medium text-foreground whitespace-nowrap", children: period === "last7" ? "Afgelopen 7 dagen" : "Afgelopen 30 dagen" })) : (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "px-2 text-sm font-medium text-foreground whitespace-nowrap rounded hover:bg-accent h-7", "aria-label": "Kies week", children: ["Week ", week, " - ", year] }) }), _jsx(PopoverContent, { className: "w-auto p-0 pointer-events-auto", align: "start", children: _jsx(WeekCalendar, { week: week, year: year, onSelect: (w, y) => onChange({ ...value, week: w, year: y }) }) })] })), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", "aria-label": "Periode-opties", children: _jsx(MoreVertical, { className: "h-4 w-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsxs(DropdownMenuRadioGroup, { value: period, onValueChange: (v) => handlePeriodChange(v), children: [_jsx(DropdownMenuRadioItem, { value: "day", children: "Dag" }), _jsx(DropdownMenuRadioItem, { value: "week", children: "Week" }), _jsx(DropdownMenuRadioItem, { value: "month", children: "Maand" }), _jsx(DropdownMenuRadioItem, { value: "last7", children: "Afgelopen 7 dagen" }), _jsx(DropdownMenuRadioItem, { value: "last30", children: "Afgelopen 30 dagen" }), _jsx(DropdownMenuRadioItem, { value: "custom", children: "Aangepast tijdsbestek" })] }), _jsx(DropdownMenuSeparator, {}), _jsxs("div", { className: "px-2 py-1.5 text-sm text-muted-foreground inline-flex items-center gap-1", children: [periodLabel(), _jsx(ChevronDown, { className: "h-3.5 w-3.5" })] })] })] })] }), _jsxs("div", { className: "flex h-9 items-center overflow-hidden rounded-md border border-border bg-card", children: [_jsx(Input, { placeholder: "Op briefnummer zoeken", value: search, onChange: (e) => setSearch(e.target.value), onKeyDown: (e) => {
|
|
137
131
|
if (e.key === "Enter")
|
|
138
132
|
onChange({ ...value, search });
|
|
139
133
|
}, onBlur: () => onChange({ ...value, search }), className: "h-9 w-56 border-0 shadow-none focus-visible:ring-0" }), _jsx("button", { type: "button", onClick: () => onChange({ ...value, search }), className: "inline-flex h-9 w-10 items-center justify-center bg-primary text-primary-foreground hover:opacity-90", "aria-label": "Zoeken", children: _jsx(Search, { className: "h-4 w-4" }) })] })] }));
|