@flowselections/floriday-afhandeling-module 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
  2. package/dist-lib/components/afhandeling/LeveringenPage.js +9 -67
  3. package/dist-lib/components/afhandeling/PickAgendaView.d.ts +6 -0
  4. package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -0
  5. package/dist-lib/components/afhandeling/PickAgendaView.js +31 -0
  6. package/dist-lib/components/afhandeling/PickingPage.d.ts +2 -0
  7. package/dist-lib/components/afhandeling/PickingPage.d.ts.map +1 -0
  8. package/dist-lib/components/afhandeling/PickingPage.js +5 -0
  9. package/dist-lib/components/afhandeling/PlanningAgendaPage.d.ts +9 -0
  10. package/dist-lib/components/afhandeling/PlanningAgendaPage.d.ts.map +1 -0
  11. package/dist-lib/components/afhandeling/PlanningAgendaPage.js +7 -0
  12. package/dist-lib/components/afhandeling/VervoerderForm.d.ts.map +1 -1
  13. package/dist-lib/components/afhandeling/VervoerderForm.js +24 -10
  14. package/dist-lib/components/afhandeling/WeekAgendaView.d.ts +12 -0
  15. package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -0
  16. package/dist-lib/components/afhandeling/WeekAgendaView.js +107 -0
  17. package/dist-lib/components/pickstation/LanguagePicker.d.ts +5 -0
  18. package/dist-lib/components/pickstation/LanguagePicker.d.ts.map +1 -0
  19. package/dist-lib/components/pickstation/LanguagePicker.js +5 -0
  20. package/dist-lib/components/pickstation/PakbonTemplate.d.ts +17 -0
  21. package/dist-lib/components/pickstation/PakbonTemplate.d.ts.map +1 -0
  22. package/dist-lib/components/pickstation/PakbonTemplate.js +74 -0
  23. package/dist-lib/components/pickstation/printDocuments.d.ts +3 -0
  24. package/dist-lib/components/pickstation/printDocuments.d.ts.map +1 -0
  25. package/dist-lib/components/pickstation/printDocuments.js +53 -0
  26. package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts +2 -0
  27. package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -0
  28. package/dist-lib/components/settings/AfhandelingSettingsCard.js +60 -0
  29. package/dist-lib/components/settings/VervoerdersSettingsCard.d.ts +2 -0
  30. package/dist-lib/components/settings/VervoerdersSettingsCard.d.ts.map +1 -0
  31. package/dist-lib/components/settings/VervoerdersSettingsCard.js +30 -0
  32. package/dist-lib/hooks/useOrderPlanning.d.ts +14 -0
  33. package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -0
  34. package/dist-lib/hooks/useOrderPlanning.js +90 -0
  35. package/dist-lib/index.d.ts +5 -0
  36. package/dist-lib/index.d.ts.map +1 -1
  37. package/dist-lib/index.js +16 -6
  38. package/dist-lib/integrations/supabase/auth-middleware.d.ts +531 -0
  39. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  40. package/dist-lib/integrations/supabase/client.d.ts +531 -0
  41. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  42. package/dist-lib/integrations/supabase/client.server.d.ts +531 -0
  43. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  44. package/dist-lib/integrations/supabase/types.d.ts +544 -0
  45. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  46. package/dist-lib/integrations/supabase/types.js +1 -0
  47. package/dist-lib/lib/afhandelingSettings.functions.d.ts +14338 -0
  48. package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -0
  49. package/dist-lib/lib/afhandelingSettings.functions.js +73 -0
  50. package/dist-lib/lib/carriers.functions.d.ts +2176 -44
  51. package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
  52. package/dist-lib/lib/carriers.functions.js +43 -6
  53. package/dist-lib/lib/floriday.functions.d.ts +532 -0
  54. package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
  55. package/dist-lib/lib/floriday.functions.js +6 -1
  56. package/dist-lib/lib/pickDate.d.ts +21 -0
  57. package/dist-lib/lib/pickDate.d.ts.map +1 -0
  58. package/dist-lib/lib/pickDate.js +71 -0
  59. package/dist-lib/lib/pickstationI18n.d.ts +31 -0
  60. package/dist-lib/lib/pickstationI18n.d.ts.map +1 -0
  61. package/dist-lib/lib/pickstationI18n.js +147 -0
  62. package/dist-lib/lib/pickstationOrders.server.d.ts +9 -0
  63. package/dist-lib/lib/pickstationOrders.server.d.ts.map +1 -0
  64. package/dist-lib/lib/pickstationOrders.server.js +244 -0
  65. package/dist-lib/lib/pickstationTypes.d.ts +17 -0
  66. package/dist-lib/lib/pickstationTypes.d.ts.map +1 -0
  67. package/dist-lib/lib/pickstationTypes.js +1 -0
  68. package/dist-lib/lib/planning.d.ts +66 -0
  69. package/dist-lib/lib/planning.d.ts.map +1 -0
  70. package/dist-lib/lib/planning.js +180 -0
  71. package/package.json +12 -6
@@ -1 +1 @@
1
- {"version":3,"file":"LeveringenPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/LeveringenPage.tsx"],"names":[],"mappings":"AA2DA,wBAAgB,cAAc,gCAuM7B"}
1
+ {"version":3,"file":"LeveringenPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/LeveringenPage.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,cAAc,gCA+F7B"}
@@ -1,79 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Link } from "@tanstack/react-router";
3
- import { useServerFn } from "@tanstack/react-start";
4
- import { useQuery } from "@tanstack/react-query";
5
3
  import { useMemo, useState } from "react";
6
- import { Button, Badge, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Tabs, TabsContent, TabsList, TabsTrigger, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@flowselections/core";
4
+ import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Tabs, TabsContent, TabsList, TabsTrigger, } from "@flowselections/core";
7
5
  import { Plus } from "lucide-react";
8
- import { getFloridayOrders } from "../../lib/floriday.functions";
6
+ import { WeekAgendaView } from "./WeekAgendaView";
7
+ import { useOrderPlanning } from "../../hooks/useOrderPlanning";
9
8
  const ALL = "__all__";
10
- function formatDate(iso) {
11
- if (!iso)
12
- return "—";
13
- const d = new Date(iso);
14
- if (Number.isNaN(d.getTime()))
15
- return iso;
16
- return d.toLocaleDateString("nl-NL", { day: "2-digit", month: "2-digit", year: "numeric" });
17
- }
18
- function formatMoney(amount, currency) {
19
- if (amount == null)
20
- return "—";
21
- try {
22
- return new Intl.NumberFormat("nl-NL", {
23
- style: "currency",
24
- currency: currency ?? "EUR",
25
- }).format(amount);
26
- }
27
- catch {
28
- return `${amount.toFixed(2)} ${currency ?? ""}`.trim();
29
- }
30
- }
31
- function statusVariant(status) {
32
- const s = status.toLowerCase();
33
- if (s.includes("delivered") || s.includes("completed") || s.includes("afgerond"))
34
- return "bg-green-500/10 text-green-600";
35
- if (s.includes("cancel") || s.includes("annul") || s.includes("reject"))
36
- return "bg-red-500/10 text-red-600";
37
- if (s.includes("pending") || s.includes("open") || s.includes("nieuw"))
38
- return "bg-blue-500/10 text-blue-600";
39
- return "bg-amber-500/10 text-amber-600";
40
- }
41
9
  export function LeveringenPage() {
42
- const fetchOrders = useServerFn(getFloridayOrders);
43
- const { data, isLoading, refetch, isFetching } = useQuery({
44
- queryKey: ["floriday", "orders"],
45
- queryFn: async () => {
46
- try {
47
- return await fetchOrders();
48
- }
49
- catch (e) {
50
- let message = "Onbekende fout";
51
- if (e instanceof Response) {
52
- const text = await e.clone().text().catch(() => "");
53
- message = `Floriday-aanvraag mislukt (${e.status}): ${text.slice(0, 200) || e.statusText}`;
54
- }
55
- else if (e instanceof Error) {
56
- message = e.message;
57
- }
58
- else {
59
- message = String(e);
60
- }
61
- console.error("[getFloridayOrders]", message);
62
- return { orders: [], error: message };
63
- }
64
- },
65
- retry: false,
66
- });
67
- const orders = data?.orders ?? [];
68
- const error = data?.error ? new Error(data.error) : null;
10
+ const { planned, isLoading, error, refetch } = useOrderPlanning();
69
11
  const [customer, setCustomer] = useState(ALL);
70
12
  const [deliveryType, setDeliveryType] = useState(ALL);
71
13
  const [dateFrom, setDateFrom] = useState("");
72
14
  const [dateTo, setDateTo] = useState("");
73
- const customers = useMemo(() => Array.from(new Set(orders.map((o) => o.customerName).filter(Boolean))).sort(), [orders]);
74
- const deliveryTypes = useMemo(() => Array.from(new Set(orders.map((o) => o.deliveryType).filter(Boolean))).sort(), [orders]);
15
+ const customers = useMemo(() => Array.from(new Set(planned.map((p) => p.order.customerName).filter(Boolean))).sort(), [planned]);
16
+ const deliveryTypes = useMemo(() => Array.from(new Set(planned.map((p) => p.order.deliveryType).filter(Boolean))).sort(), [planned]);
75
17
  const filtered = useMemo(() => {
76
- return orders.filter((o) => {
18
+ return planned.filter(({ order: o }) => {
77
19
  if (customer !== ALL && o.customerName !== customer)
78
20
  return false;
79
21
  if (deliveryType !== ALL && o.deliveryType !== deliveryType)
@@ -84,6 +26,6 @@ export function LeveringenPage() {
84
26
  return false;
85
27
  return true;
86
28
  });
87
- }, [orders, customer, deliveryType, dateFrom, dateTo]);
88
- return (_jsx("main", { className: "p-6 space-y-6", children: _jsxs(Tabs, { defaultValue: "overzicht", className: "space-y-6", children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "overzicht", children: "Overzicht" }), _jsx(TabsTrigger, { value: "veilbrieven", children: "Veilbrieven" })] }), _jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum vanaf" }), _jsx(Input, { type: "date", value: dateFrom, onChange: (e) => setDateFrom(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum t/m" }), _jsx(Input, { type: "date", value: dateTo, onChange: (e) => setDateTo(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Klant" }), _jsxs(Select, { value: customer, onValueChange: setCustomer, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle klanten" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle klanten" }), customers.map((c) => (_jsx(SelectItem, { value: c, children: c }, c)))] })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Type levering" }), _jsxs(Select, { value: deliveryType, onValueChange: setDeliveryType, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle types" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle types" }), deliveryTypes.map((t) => (_jsx(SelectItem, { value: t, children: t }, t)))] })] })] })] }), _jsx(Button, { asChild: true, children: _jsxs(Link, { to: "/afhandeling/leveringen/nieuw", children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Levering aanmaken"] }) })] }), _jsxs(TabsContent, { value: "overzicht", className: "space-y-3", children: [error ? (_jsxs("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive", children: [error.message, _jsx(Button, { size: "sm", variant: "outline", className: "ml-3", onClick: () => refetch(), children: "Opnieuw proberen" })] })) : (_jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Ordernummer" }), _jsx(TableHead, { children: "Klant" }), _jsx(TableHead, { children: "Leverdatum" }), _jsx(TableHead, { children: "Type" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { className: "text-right", children: "Regels" }), _jsx(TableHead, { className: "text-right", children: "Totaal" })] }) }), _jsx(TableBody, { children: isLoading ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 7, className: "text-center text-muted-foreground", children: "Leveringen laden\u2026" }) })) : filtered.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 7, className: "text-center text-muted-foreground", children: "Geen leveringen gevonden." }) })) : (filtered.map((o) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: o.orderNumber }), _jsx(TableCell, { children: o.customerName }), _jsx(TableCell, { children: formatDate(o.deliveryDate) }), _jsx(TableCell, { children: o.deliveryType }), _jsx(TableCell, { children: _jsx(Badge, { className: statusVariant(o.status), variant: "secondary", children: o.status }) }), _jsx(TableCell, { className: "text-right", children: o.lineCount }), _jsx(TableCell, { className: "text-right", children: formatMoney(o.totalAmount, o.currency) })] }, o.id)))) })] }) })), _jsx("div", { className: "text-xs text-muted-foreground", children: isFetching ? "Bijwerken…" : `${filtered.length} van ${orders.length} leveringen` })] }), _jsx(TabsContent, { value: "veilbrieven", children: _jsx("div", { className: "rounded-md border border-dashed p-10 text-center text-sm text-muted-foreground", children: "Veilbrieven volgen in een volgende iteratie." }) })] }) }));
29
+ }, [planned, customer, deliveryType, dateFrom, dateTo]);
30
+ return (_jsx("main", { className: "p-6 space-y-6", children: _jsxs(Tabs, { defaultValue: "overzicht", className: "space-y-6", children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "overzicht", children: "Overzicht" }), _jsx(TabsTrigger, { value: "veilbrieven", children: "Veilbrieven" })] }), _jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum vanaf" }), _jsx(Input, { type: "date", value: dateFrom, onChange: (e) => setDateFrom(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum t/m" }), _jsx(Input, { type: "date", value: dateTo, onChange: (e) => setDateTo(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Klant" }), _jsxs(Select, { value: customer, onValueChange: setCustomer, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle klanten" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle klanten" }), customers.map((c) => _jsx(SelectItem, { value: c, children: c }, c))] })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Type levering" }), _jsxs(Select, { value: deliveryType, onValueChange: setDeliveryType, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle types" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle types" }), deliveryTypes.map((t) => _jsx(SelectItem, { value: t, children: t }, t))] })] })] })] }), _jsx(Button, { asChild: true, children: _jsxs(Link, { to: "/afhandeling/leveringen/nieuw", children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Levering aanmaken"] }) })] }), _jsx(TabsContent, { value: "overzicht", className: "space-y-3", children: error ? (_jsxs("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive", children: [error, _jsx(Button, { size: "sm", variant: "outline", className: "ml-3", onClick: () => refetch(), children: "Opnieuw proberen" })] })) : (_jsx(WeekAgendaView, { planned: filtered, mode: "delivery", isLoading: isLoading })) }), _jsx(TabsContent, { value: "veilbrieven", children: _jsx("div", { className: "rounded-md border border-dashed p-10 text-center text-sm text-muted-foreground", children: "Veilbrieven volgen in een volgende iteratie." }) })] }) }));
89
31
  }
@@ -0,0 +1,6 @@
1
+ import type { FloridayOrder } from "../../lib/floriday.functions";
2
+ export interface PickAgendaViewProps {
3
+ onOrderClick?: (order: FloridayOrder) => void;
4
+ }
5
+ export declare function PickAgendaView({ onOrderClick }: PickAgendaViewProps): import("react").JSX.Element;
6
+ //# sourceMappingURL=PickAgendaView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PickAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/PickAgendaView.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAIlE,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,cAAc,CAAC,EAAE,YAAY,EAAE,EAAE,mBAAmB,+BA6FnE"}
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Link } from "@tanstack/react-router";
3
+ import { useMemo, useState } from "react";
4
+ import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Tabs, TabsContent, TabsList, TabsTrigger, } from "@flowselections/core";
5
+ import { Plus } from "lucide-react";
6
+ import { WeekAgendaView } from "./WeekAgendaView";
7
+ import { useOrderPlanning } from "../../hooks/useOrderPlanning";
8
+ const ALL = "__all__";
9
+ export function PickAgendaView({ onOrderClick }) {
10
+ const { planned, isLoading, error, refetch } = useOrderPlanning();
11
+ const [customer, setCustomer] = useState(ALL);
12
+ const [deliveryType, setDeliveryType] = useState(ALL);
13
+ const [dateFrom, setDateFrom] = useState("");
14
+ const [dateTo, setDateTo] = useState("");
15
+ const customers = useMemo(() => Array.from(new Set(planned.map((p) => p.order.customerName).filter(Boolean))).sort(), [planned]);
16
+ const deliveryTypes = useMemo(() => Array.from(new Set(planned.map((p) => p.order.deliveryType).filter(Boolean))).sort(), [planned]);
17
+ const filtered = useMemo(() => {
18
+ return planned.filter(({ order: o }) => {
19
+ if (customer !== ALL && o.customerName !== customer)
20
+ return false;
21
+ if (deliveryType !== ALL && o.deliveryType !== deliveryType)
22
+ return false;
23
+ if (dateFrom && (!o.deliveryDate || o.deliveryDate < dateFrom))
24
+ return false;
25
+ if (dateTo && (!o.deliveryDate || o.deliveryDate > dateTo + "T23:59:59"))
26
+ return false;
27
+ return true;
28
+ });
29
+ }, [planned, customer, deliveryType, dateFrom, dateTo]);
30
+ return (_jsxs(Tabs, { defaultValue: "overzicht", className: "space-y-6", children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "overzicht", children: "Overzicht" }), _jsx(TabsTrigger, { value: "veilbrieven", children: "Veilbrieven" })] }), _jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum vanaf" }), _jsx(Input, { type: "date", value: dateFrom, onChange: (e) => setDateFrom(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum t/m" }), _jsx(Input, { type: "date", value: dateTo, onChange: (e) => setDateTo(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Klant" }), _jsxs(Select, { value: customer, onValueChange: setCustomer, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle klanten" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle klanten" }), customers.map((c) => _jsx(SelectItem, { value: c, children: c }, c))] })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Type levering" }), _jsxs(Select, { value: deliveryType, onValueChange: setDeliveryType, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle types" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle types" }), deliveryTypes.map((t) => _jsx(SelectItem, { value: t, children: t }, t))] })] })] })] }), _jsx(Button, { asChild: true, children: _jsxs(Link, { to: "/afhandeling/leveringen/nieuw", children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Levering aanmaken"] }) })] }), _jsx(TabsContent, { value: "overzicht", className: "space-y-3", children: error ? (_jsxs("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive", children: [error, _jsx(Button, { size: "sm", variant: "outline", className: "ml-3", onClick: () => refetch(), children: "Opnieuw proberen" })] })) : (_jsx(WeekAgendaView, { planned: filtered, mode: "pick", isLoading: isLoading, onOrderClick: onOrderClick })) }), _jsx(TabsContent, { value: "veilbrieven", children: _jsx("div", { className: "rounded-md border border-dashed p-10 text-center text-sm text-muted-foreground", children: "Veilbrieven volgen in een volgende iteratie." }) })] }));
31
+ }
@@ -0,0 +1,2 @@
1
+ export declare function PickingPage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=PickingPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PickingPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/PickingPage.tsx"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,gCAY1B"}
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PickAgendaView } from "./PickAgendaView";
3
+ export function PickingPage() {
4
+ return (_jsxs("main", { className: "p-6 space-y-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Pick Agenda" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Overzicht van alle orders die gepickt moeten worden." })] }), _jsx(PickAgendaView, {})] }));
5
+ }
@@ -0,0 +1,9 @@
1
+ import { type WeekAgendaMode } from "./WeekAgendaView";
2
+ interface Props {
3
+ title: string;
4
+ description: string;
5
+ mode: WeekAgendaMode;
6
+ }
7
+ export declare function PlanningAgendaPage({ title, description, mode }: Props): import("react").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=PlanningAgendaPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlanningAgendaPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/PlanningAgendaPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvE,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,cAAc,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,KAAK,+BAgBrE"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { WeekAgendaView } from "./WeekAgendaView";
3
+ import { useOrderPlanning } from "../../hooks/useOrderPlanning";
4
+ export function PlanningAgendaPage({ title, description, mode }) {
5
+ const { planned, isLoading, error } = useOrderPlanning();
6
+ return (_jsxs("main", { className: "p-6 space-y-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), error && (_jsx("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive", children: error })), _jsx(WeekAgendaView, { planned: planned, mode: mode, isLoading: isLoading })] }));
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"VervoerderForm.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/VervoerderForm.tsx"],"names":[],"mappings":"AA4CA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAmHD,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,+BA+TlD"}
1
+ {"version":3,"file":"VervoerderForm.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/VervoerderForm.tsx"],"names":[],"mappings":"AA6CA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAiND,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,+BA0VlD"}
@@ -6,6 +6,7 @@ import { Link, useNavigate } from "@tanstack/react-router";
6
6
  import { useServerFn } from "@tanstack/react-start";
7
7
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
8
8
  import { getCarrier, upsertCarrier, } from "../../lib/carriers.functions";
9
+ import { DEFAULT_PICKUP_MOMENT } from "../../lib/planning";
9
10
  import { COUNTRIES, countryName } from "../../lib/countries";
10
11
  const EMPTY = {
11
12
  name: "",
@@ -13,10 +14,9 @@ const EMPTY = {
13
14
  email: "",
14
15
  phone: "",
15
16
  address: "",
16
- delivery_days: null,
17
- signup_time_1: "",
18
- signup_time_2: "",
19
17
  notes: "",
18
+ is_default: false,
19
+ pickup_moments: [DEFAULT_PICKUP_MOMENT],
20
20
  };
21
21
  function FieldIcon({ icon: Icon }) {
22
22
  return (_jsx("div", { className: "flex items-center justify-center w-10 h-10 rounded-md bg-primary/10 text-primary shrink-0", children: _jsx(Icon, { className: "w-4 h-4" }) }));
@@ -38,6 +38,12 @@ function CountryPicker({ value, onChange, excluded, }) {
38
38
  setQuery("");
39
39
  }, className: "flex items-center justify-between w-full px-3 py-2 text-sm text-left hover:bg-muted", children: [_jsx("span", { children: c.name }), _jsx("span", { className: "text-xs text-muted-foreground", children: c.code })] }, c.code)))) })] })] }));
40
40
  }
41
+ function PickupMomentRow({ label, days, time, onDaysChange, onTimeChange, }) {
42
+ return (_jsxs("div", { className: "grid grid-cols-[110px,1fr,1fr] items-center gap-3", children: [_jsx("div", { className: "text-sm font-medium", children: label }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: "Werkdagen v\u00F3\u00F3r levering" }), _jsx(IconInput, { icon: Calendar, type: "number", min: 0, value: days, onChange: (e) => onDaysChange(Number(e.target.value) || 0) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: "Tijdstip" }), _jsx(IconInput, { icon: Clock, type: "time", value: time, onChange: (e) => onTimeChange(e.target.value) })] })] }));
43
+ }
44
+ function PickupMomentEditor({ index, value, canDelete, onChange, onDelete, }) {
45
+ return (_jsxs("div", { className: "rounded-md border bg-background p-4 space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "text-sm font-semibold", children: ["Ophaalmoment ", index + 1] }), canDelete ? (_jsxs("button", { type: "button", onClick: onDelete, className: "text-xs text-muted-foreground hover:text-destructive inline-flex items-center gap-1", "aria-label": "Ophaalmoment verwijderen", children: [_jsx(Trash2, { className: "w-3.5 h-3.5" }), "Verwijderen"] })) : null] }), _jsxs("div", { className: "space-y-3", children: [_jsx(PickupMomentRow, { label: "Aanmelden", days: value.signup_days, time: value.signup_time, onDaysChange: (n) => onChange({ ...value, signup_days: n }), onTimeChange: (v) => onChange({ ...value, signup_time: v }) }), _jsx(PickupMomentRow, { label: "Ophalen", days: value.pickup_days, time: value.pickup_time, onDaysChange: (n) => onChange({ ...value, pickup_days: n }), onTimeChange: (v) => onChange({ ...value, pickup_time: v }) }), _jsx(PickupMomentRow, { label: "Bezorgen", days: value.delivery_days, time: value.delivery_time, onDaysChange: (n) => onChange({ ...value, delivery_days: n }), onTimeChange: (v) => onChange({ ...value, delivery_time: v }) })] })] }));
46
+ }
41
47
  export function VervoerderForm({ carrierId }) {
42
48
  const isEdit = !!carrierId;
43
49
  const navigate = useNavigate();
@@ -63,10 +69,11 @@ export function VervoerderForm({ carrierId }) {
63
69
  email: c.email ?? "",
64
70
  phone: c.phone ?? "",
65
71
  address: c.address ?? "",
66
- delivery_days: c.delivery_days,
67
- signup_time_1: c.signup_time_1 ?? "",
68
- signup_time_2: c.signup_time_2 ?? "",
69
72
  notes: c.notes ?? "",
73
+ is_default: c.is_default ?? false,
74
+ pickup_moments: c.pickup_moments && c.pickup_moments.length > 0
75
+ ? c.pickup_moments
76
+ : [DEFAULT_PICKUP_MOMENT],
70
77
  });
71
78
  setRates(c.rates);
72
79
  }
@@ -126,10 +133,17 @@ export function VervoerderForm({ carrierId }) {
126
133
  }
127
134
  return (_jsxs("main", { className: "p-6 space-y-6 max-w-4xl", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsxs(Link, { to: "/afhandeling/vervoerders", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Terug naar vervoerders"] }) }), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(FieldIcon, { icon: Truck }), _jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: isEdit ? "Vervoerder bewerken" : "Vervoerder aanmaken" }), _jsx("p", { className: "text-sm text-muted-foreground", children: isEdit
128
135
  ? "Wijzig de gegevens van de vervoerder."
129
- : "Voeg een nieuwe vervoerder toe en stel verzendtarieven in." })] })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base", children: "Algemene gegevens" }) }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { children: ["Bedrijfsnaam ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(IconInput, { icon: Truck, value: form.name, onChange: (e) => setForm({ ...form, name: e.target.value }), placeholder: "Bijv. DHL Freight", required: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Contactpersoon" }), _jsx(IconInput, { icon: User, value: form.contact_person ?? "", onChange: (e) => setForm({ ...form, contact_person: e.target.value }) })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "E-mail" }), _jsx(IconInput, { icon: Mail, type: "email", value: form.email ?? "", onChange: (e) => setForm({ ...form, email: e.target.value }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Telefoonnummer" }), _jsx(IconInput, { icon: Phone, value: form.phone ?? "", onChange: (e) => setForm({ ...form, phone: e.target.value }) })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Adres" }), _jsx(IconInput, { icon: MapPin, value: form.address ?? "", onChange: (e) => setForm({ ...form, address: e.target.value }), placeholder: "Straat, postcode, plaats" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Levertijd (dagen)" }), _jsx(IconInput, { icon: Calendar, type: "number", min: 0, value: form.delivery_days ?? "", onChange: (e) => setForm({
130
- ...form,
131
- delivery_days: e.target.value === "" ? null : Number(e.target.value),
132
- }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Aanmeldtijd 1" }), _jsx(IconInput, { icon: Clock, type: "time", value: form.signup_time_1 ?? "", onChange: (e) => setForm({ ...form, signup_time_1: e.target.value }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Aanmeldtijd 2" }), _jsx(IconInput, { icon: Clock, type: "time", value: form.signup_time_2 ?? "", onChange: (e) => setForm({ ...form, signup_time_2: e.target.value }) })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Opmerkingen" }), _jsxs("div", { className: "flex gap-2", children: [_jsx(FieldIcon, { icon: FileText }), _jsx(Textarea, { value: form.notes ?? "", onChange: (e) => setForm({ ...form, notes: e.target.value }), placeholder: "Extra informatie over deze vervoerder...", rows: 3, className: "flex-1" })] })] })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: "Verzendtarieven" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["Stel de verzendkosten ", _jsx("strong", { children: "per kwekerskar" }), " in voor elk land waar deze vervoerder naartoe verzendt."] })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-[1fr,160px,auto] gap-3", children: [_jsx(CountryPicker, { value: pendingCountry, onChange: setPendingCountry, excluded: rates.map((r) => r.country_code) }), _jsxs("div", { className: "flex items-stretch gap-2 rounded-md border bg-background h-10", children: [_jsx("div", { className: "flex items-center justify-center w-10 bg-primary/10 text-primary rounded-l-md text-sm font-medium", children: "\u20AC" }), _jsx("input", { type: "number", step: "0.01", min: 0, value: pendingPrice, onChange: (e) => setPendingPrice(e.target.value), placeholder: "Prijs", className: "flex-1 bg-transparent text-sm outline-none pr-3" })] }), _jsxs(Button, { type: "button", onClick: addRate, children: [_jsx(Plus, { className: "w-4 h-4 mr-1" }), "Toevoegen"] })] }), rates.length === 0 ? (_jsxs("div", { className: "border rounded-md py-10 text-center space-y-2", children: [_jsx(Globe, { className: "w-8 h-8 mx-auto text-muted-foreground" }), _jsx("div", { className: "font-medium", children: "Nog geen landen toegevoegd" }), _jsx("div", { className: "text-sm text-muted-foreground", children: "Voeg een land toe om verzendtarieven in te stellen." })] })) : (_jsx("div", { className: "border rounded-md divide-y", children: rates
136
+ : "Voeg een nieuwe vervoerder toe en stel verzendtarieven in." })] })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base", children: "Algemene gegevens" }) }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { children: ["Bedrijfsnaam ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(IconInput, { icon: Truck, value: form.name, onChange: (e) => setForm({ ...form, name: e.target.value }), placeholder: "Bijv. DHL Freight", required: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Contactpersoon" }), _jsx(IconInput, { icon: User, value: form.contact_person ?? "", onChange: (e) => setForm({ ...form, contact_person: e.target.value }) })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "E-mail" }), _jsx(IconInput, { icon: Mail, type: "email", value: form.email ?? "", onChange: (e) => setForm({ ...form, email: e.target.value }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Telefoonnummer" }), _jsx(IconInput, { icon: Phone, value: form.phone ?? "", onChange: (e) => setForm({ ...form, phone: e.target.value }) })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Adres" }), _jsx(IconInput, { icon: MapPin, value: form.address ?? "", onChange: (e) => setForm({ ...form, address: e.target.value }), placeholder: "Straat, postcode, plaats" })] }), _jsxs("div", { className: "rounded-md border bg-muted/30 p-4 space-y-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: "Ophaalmomenten (transportplanning)" }), _jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: ["De bezorgdag is ", _jsx("strong", { children: "dag 0" }), ". Per ophaalmoment stel je in op hoeveel werkdagen v\u00F3\u00F3r bezorging \u00E9n op welk tijdstip elke stap plaatsvindt. Bij een nieuwe order kiest het systeem automatisch het eerstvolgende moment waarvan de aanmelddeadline nog niet is verstreken."] })] }), _jsx("div", { className: "space-y-3", children: form.pickup_moments.map((moment, idx) => (_jsx(PickupMomentEditor, { index: idx, value: moment, canDelete: form.pickup_moments.length > 1, onChange: (next) => {
137
+ const copy = [...form.pickup_moments];
138
+ copy[idx] = next;
139
+ setForm({ ...form, pickup_moments: copy });
140
+ }, onDelete: () => {
141
+ const copy = form.pickup_moments.filter((_, i) => i !== idx);
142
+ setForm({ ...form, pickup_moments: copy });
143
+ } }, idx))) }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setForm({
144
+ ...form,
145
+ pickup_moments: [...form.pickup_moments, { ...DEFAULT_PICKUP_MOMENT }],
146
+ }), children: [_jsx(Plus, { className: "w-4 h-4 mr-1" }), "Ophaalmoment toevoegen"] })] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: form.is_default ?? false, onChange: (e) => setForm({ ...form, is_default: e.target.checked }), className: "h-4 w-4 rounded border" }), _jsxs("span", { children: ["Gebruik als ", _jsx("strong", { children: "standaard vervoerder" }), " voor de automatische planning (voor orders zonder eigen vervoerder)."] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Opmerkingen" }), _jsxs("div", { className: "flex gap-2", children: [_jsx(FieldIcon, { icon: FileText }), _jsx(Textarea, { value: form.notes ?? "", onChange: (e) => setForm({ ...form, notes: e.target.value }), placeholder: "Extra informatie over deze vervoerder...", rows: 3, className: "flex-1" })] })] })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: "Verzendtarieven" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["Stel de verzendkosten ", _jsx("strong", { children: "per kwekerskar" }), " in voor elk land waar deze vervoerder naartoe verzendt."] })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-[1fr,160px,auto] gap-3", children: [_jsx(CountryPicker, { value: pendingCountry, onChange: setPendingCountry, excluded: rates.map((r) => r.country_code) }), _jsxs("div", { className: "flex items-stretch gap-2 rounded-md border bg-background h-10", children: [_jsx("div", { className: "flex items-center justify-center w-10 bg-primary/10 text-primary rounded-l-md text-sm font-medium", children: "\u20AC" }), _jsx("input", { type: "number", step: "0.01", min: 0, value: pendingPrice, onChange: (e) => setPendingPrice(e.target.value), placeholder: "Prijs", className: "flex-1 bg-transparent text-sm outline-none pr-3" })] }), _jsxs(Button, { type: "button", onClick: addRate, children: [_jsx(Plus, { className: "w-4 h-4 mr-1" }), "Toevoegen"] })] }), rates.length === 0 ? (_jsxs("div", { className: "border rounded-md py-10 text-center space-y-2", children: [_jsx(Globe, { className: "w-8 h-8 mx-auto text-muted-foreground" }), _jsx("div", { className: "font-medium", children: "Nog geen landen toegevoegd" }), _jsx("div", { className: "text-sm text-muted-foreground", children: "Voeg een land toe om verzendtarieven in te stellen." })] })) : (_jsx("div", { className: "border rounded-md divide-y", children: rates
133
147
  .slice()
134
148
  .sort((a, b) => countryName(a.country_code).localeCompare(countryName(b.country_code), "nl"))
135
149
  .map((r) => (_jsxs("div", { className: "flex items-center gap-3 px-3 py-2", children: [_jsx(Globe, { className: "w-4 h-4 text-muted-foreground" }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-sm font-medium", children: countryName(r.country_code) }), _jsx("div", { className: "text-xs text-muted-foreground", children: r.country_code })] }), _jsxs("div", { className: "text-sm font-medium", children: ["\u20AC ", r.price_per_trolley.toFixed(2), " ", _jsx("span", { className: "text-muted-foreground font-normal", children: "/ kar" })] }), _jsx("button", { type: "button", onClick: () => removeRate(r.country_code), className: "text-muted-foreground hover:text-destructive", "aria-label": "Verwijderen", children: _jsx(Trash2, { className: "w-4 h-4" }) })] }, r.country_code))) })), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["De prijs per kwekerskar wordt automatisch berekend", " ", _jsx("strong", { children: "bij het aanmaken van een bestelling" }), "."] })] })] }), _jsxs("div", { className: "flex justify-end gap-2", children: [_jsxs(Button, { type: "button", variant: "outline", onClick: goBack, children: [_jsx(X, { className: "w-4 h-4 mr-1" }), "Annuleren"] }), _jsx(Button, { type: "submit", disabled: mutation.isPending, children: mutation.isPending ? "Opslaan..." : "Opslaan" })] })] })] }));
@@ -0,0 +1,12 @@
1
+ import type { FloridayOrder } from "../../lib/floriday.functions";
2
+ import type { PlannedOrder } from "../../hooks/useOrderPlanning";
3
+ export type WeekAgendaMode = "delivery" | "pickup" | "transport-register" | "pick";
4
+ export interface WeekAgendaViewProps {
5
+ planned: PlannedOrder[];
6
+ mode: WeekAgendaMode;
7
+ isLoading?: boolean;
8
+ onOrderClick?: (order: FloridayOrder) => void;
9
+ title?: string;
10
+ }
11
+ export declare function WeekAgendaView({ planned, mode, isLoading, onOrderClick, title, }: WeekAgendaViewProps): import("react").JSX.Element;
12
+ //# sourceMappingURL=WeekAgendaView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAEnF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmDD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,KAAK,GACN,EAAE,mBAAmB,+BA0FrB"}
@@ -0,0 +1,107 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from "react";
3
+ import { Button, Badge } from "@flowselections/core";
4
+ import { ChevronLeft, ChevronRight, Package, Truck, Sprout, Clock, CheckCircle2, Scale } from "lucide-react";
5
+ import { isSameDay, startOfWeek, addDays } from "../../lib/pickDate";
6
+ const WEEKDAY_LABELS = ["MAANDAG", "DINSDAG", "WOENSDAG", "DONDERDAG", "VRIJDAG", "ZATERDAG", "ZONDAG"];
7
+ const MONTHS_NL_SHORT = ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"];
8
+ function isOrderReady(o) {
9
+ const s = (o.status ?? "").toLowerCase();
10
+ return s.includes("ready") || s.includes("verzendklaar") || s.includes("completed") || s.includes("delivered") || s.includes("afgerond");
11
+ }
12
+ function getISOWeek(d) {
13
+ const date = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
14
+ const dayNum = date.getUTCDay() || 7;
15
+ date.setUTCDate(date.getUTCDate() + 4 - dayNum);
16
+ const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
17
+ return Math.ceil(((date.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
18
+ }
19
+ function dateForPlanned(p, mode) {
20
+ if (!p.planning)
21
+ return null;
22
+ switch (mode) {
23
+ case "delivery": return p.planning.deliveryDate;
24
+ case "pickup": return p.planning.pickupDate;
25
+ case "transport-register": return p.planning.transportRegisterDate;
26
+ case "pick": return p.planning.scheduledPickDate ?? p.planning.pickStartDate;
27
+ }
28
+ }
29
+ function isMovedEarlier(p, mode) {
30
+ if (mode !== "pick" || !p.planning)
31
+ return false;
32
+ return Boolean(p.planning.movedEarlier);
33
+ }
34
+ const MODE_LABELS = {
35
+ delivery: { summary: "Leveringen deze week" },
36
+ pickup: { summary: "Ophalingen deze week" },
37
+ "transport-register": { summary: "Aanmeldingen deze week" },
38
+ pick: { summary: "Te picken deze week" },
39
+ };
40
+ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, title, }) {
41
+ const [cursor, setCursor] = useState(() => {
42
+ const d = new Date();
43
+ d.setHours(0, 0, 0, 0);
44
+ return startOfWeek(d);
45
+ });
46
+ const weekStart = useMemo(() => startOfWeek(cursor), [cursor]);
47
+ const weekEnd = useMemo(() => addDays(weekStart, 6), [weekStart]);
48
+ const weekNumber = useMemo(() => getISOWeek(weekStart), [weekStart]);
49
+ const days = useMemo(() => {
50
+ return Array.from({ length: 7 }, (_, i) => {
51
+ const date = addDays(weekStart, i);
52
+ const dayPlanned = planned.filter((p) => {
53
+ const d = dateForPlanned(p, mode);
54
+ return d ? isSameDay(d, date) : false;
55
+ });
56
+ const dayOrders = dayPlanned.map((p) => p.order);
57
+ const karren = dayOrders.reduce((s, o) => s + (o.lineCount || 0), 0);
58
+ const planten = dayOrders.reduce((s, o) => s + (o.lineCount || 0) * 10, 0);
59
+ const verzendklaar = dayOrders.filter(isOrderReady).length;
60
+ const voorbereiding = dayOrders.length - verzendklaar;
61
+ const movedEarlierOrderIds = new Set(dayPlanned.filter((p) => isMovedEarlier(p, mode)).map((p) => p.order.id));
62
+ return {
63
+ date,
64
+ orders: dayOrders,
65
+ movedEarlierOrderIds,
66
+ bestellingen: dayOrders.length,
67
+ karren,
68
+ planten,
69
+ verzendklaar,
70
+ voorbereiding,
71
+ };
72
+ });
73
+ }, [planned, weekStart, mode]);
74
+ const totals = useMemo(() => {
75
+ const leveringen = days.reduce((s, d) => s + d.bestellingen, 0);
76
+ const verzendklaar = days.reduce((s, d) => s + d.verzendklaar, 0);
77
+ const voorbereiding = days.reduce((s, d) => s + d.voorbereiding, 0);
78
+ const totaalStuks = days.reduce((s, d) => s + d.planten, 0);
79
+ return { leveringen, verzendklaar, voorbereiding, totaalStuks };
80
+ }, [days]);
81
+ const headerLabel = `Week ${weekNumber} - ${weekStart.getDate()} ${MONTHS_NL_SHORT[weekStart.getMonth()]}. t/m ${weekEnd.getDate()} ${MONTHS_NL_SHORT[weekEnd.getMonth()]}. ${weekEnd.getFullYear()}`;
82
+ const goPrev = () => setCursor((c) => addDays(c, -7));
83
+ const goNext = () => setCursor((c) => addDays(c, 7));
84
+ const goToday = () => {
85
+ const d = new Date();
86
+ d.setHours(0, 0, 0, 0);
87
+ setCursor(startOfWeek(d));
88
+ };
89
+ return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h2", { className: "text-xl font-semibold tracking-tight", children: title ?? headerLabel }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: goPrev, children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), " Vorige week"] }), _jsx(Button, { variant: "outline", size: "sm", onClick: goToday, children: "Deze week" }), _jsxs(Button, { variant: "outline", size: "sm", onClick: goNext, children: ["Volgende week ", _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4", children: [_jsx(SummaryCard, { label: MODE_LABELS[mode].summary, value: totals.leveringen, tone: "default" }), _jsx(SummaryCard, { label: "Verzendklaar", value: totals.verzendklaar, tone: "success" }), _jsx(SummaryCard, { label: "In voorbereiding", value: totals.voorbereiding, tone: "muted" }), _jsx(SummaryCard, { label: "Totaal stuks", value: totals.totaalStuks, tone: "default" })] }), _jsx("div", { className: "space-y-2", children: isLoading ? (_jsx("div", { className: "rounded-lg border bg-card p-10 text-center text-sm text-muted-foreground", children: "Laden\u2026" })) : (days.map((day) => _jsx(DayRow, { day: day, onOrderClick: onOrderClick }, day.date.toISOString()))) })] }));
90
+ }
91
+ function SummaryCard({ label, value, tone, }) {
92
+ const valueClass = tone === "success" ? "text-green-600" : "text-foreground";
93
+ return (_jsxs("div", { className: "rounded-lg border bg-card p-4", children: [_jsx("div", { className: `text-3xl font-bold ${valueClass}`, children: value }), _jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: label })] }));
94
+ }
95
+ function DayRow({ day, onOrderClick }) {
96
+ const weekdayIdx = (day.date.getDay() + 6) % 7;
97
+ const today = new Date();
98
+ today.setHours(0, 0, 0, 0);
99
+ const isToday = isSameDay(day.date, today);
100
+ return (_jsxs("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""}`, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-6 px-4 py-4 sm:px-6", children: [_jsxs("div", { className: "w-20 shrink-0", children: [_jsx("div", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: WEEKDAY_LABELS[weekdayIdx] }), _jsx("div", { className: "mt-1 text-3xl font-bold leading-none", children: day.date.getDate() }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [MONTHS_NL_SHORT[day.date.getMonth()], "."] })] }), _jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-6", children: [_jsx(Stat, { icon: _jsx(Package, { className: "h-4 w-4 text-slate-500" }), bg: "bg-slate-100", value: day.bestellingen, label: "bestellingen" }), _jsx(Stat, { icon: _jsx(Truck, { className: "h-4 w-4 text-amber-600" }), bg: "bg-amber-100", value: day.karren, label: "karren" }), _jsx(Stat, { icon: _jsx(Sprout, { className: "h-4 w-4 text-green-600" }), bg: "bg-green-100", value: day.planten, label: "planten" })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [day.movedEarlierOrderIds.size > 0 && (_jsxs(Badge, { className: "bg-purple-500/10 text-purple-700 hover:bg-purple-500/10", variant: "secondary", title: "Aantal orders dat vervroegd is ingepland door Pickverdeling.", children: [_jsx(Scale, { className: "mr-1 h-3.5 w-3.5" }), day.movedEarlierOrderIds.size, " vervroegd"] })), day.verzendklaar > 0 && (_jsxs(Badge, { className: "bg-green-500/15 text-green-700 hover:bg-green-500/15", variant: "secondary", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), day.verzendklaar, " verzendklaar"] })), day.voorbereiding > 0 && (_jsxs(Badge, { className: "bg-blue-500/10 text-blue-700 hover:bg-blue-500/10", variant: "secondary", children: [_jsx(Clock, { className: "mr-1 h-3.5 w-3.5" }), day.voorbereiding, " in voorbereiding"] }))] })] }), onOrderClick && day.orders.length > 0 && (_jsx("div", { className: "border-t px-4 py-2 sm:px-6", children: _jsx("div", { className: "flex flex-wrap gap-2", children: day.orders.map((o) => {
101
+ const moved = day.movedEarlierOrderIds.has(o.id);
102
+ return (_jsxs("button", { onClick: () => onOrderClick(o), title: moved ? "Deze order is eerder ingepland vanwege Pickverdeling." : undefined, className: `flex items-center gap-1 rounded border px-2 py-1 text-xs hover:bg-muted ${moved ? "border-purple-300 bg-purple-50" : ""}`, children: [moved && _jsx(Scale, { className: "h-3 w-3 text-purple-600" }), _jsx("span", { className: "font-medium", children: o.orderNumber }), _jsxs("span", { className: "ml-1 text-muted-foreground", children: ["\u00B7 ", o.customerName] })] }, o.id));
103
+ }) }) }))] }));
104
+ }
105
+ function Stat({ icon, bg, value, label, }) {
106
+ return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: `grid h-8 w-8 place-items-center rounded-full ${bg}`, children: icon }), _jsxs("div", { children: [_jsx("div", { className: "text-lg font-bold leading-none", children: value }), _jsx("div", { className: "text-xs text-muted-foreground", children: label })] })] }));
107
+ }
@@ -0,0 +1,5 @@
1
+ import { type PickstationLang } from "../../lib/pickstationI18n";
2
+ export declare function LanguagePicker({ onPick }: {
3
+ onPick: (lang: PickstationLang) => void;
4
+ }): import("react").JSX.Element;
5
+ //# sourceMappingURL=LanguagePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguagePicker.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/LanguagePicker.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAExF,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;CAAE,+BAuBrF"}
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PICKSTATION_LANGUAGES } from "../../lib/pickstationI18n";
3
+ export function LanguagePicker({ onPick }) {
4
+ return (_jsx("div", { className: "fixed inset-0 z-50 bg-slate-900 text-white flex items-center justify-center p-6", children: _jsxs("div", { className: "w-full max-w-3xl", children: [_jsx("h1", { className: "text-4xl font-semibold mb-2 text-center", children: "Pickstation" }), _jsx("p", { className: "text-slate-400 text-center mb-10 text-lg", children: "Kies uw taal \u00B7 Wybierz j\u0119zyk \u00B7 Alege\u021Bi limba \u00B7 \u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0435\u0437\u0438\u043A \u00B7 \u041E\u0431\u0435\u0440\u0456\u0442\u044C \u043C\u043E\u0432\u0443 \u00B7 Choose your language" }), _jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: PICKSTATION_LANGUAGES.map((lang) => (_jsxs("button", { onClick: () => onPick(lang.code), className: "bg-white text-slate-900 hover:bg-emerald-500 hover:text-white transition rounded-2xl py-6 px-6 text-left text-2xl font-semibold flex items-center gap-4 shadow-lg", children: [_jsx("span", { className: "text-4xl", children: lang.flag }), _jsx("span", { children: lang.label })] }, lang.code))) })] }) }));
5
+ }
@@ -0,0 +1,17 @@
1
+ import type { PickstationOrder } from "../../lib/pickstationTypes";
2
+ /** Returns a fully self-contained printable HTML document for one packing slip. */
3
+ export declare function renderPakbonHtml(order: {
4
+ id: string;
5
+ orderNumber: string;
6
+ customerName: string;
7
+ country: string | null;
8
+ deliveryDate: string | null;
9
+ pickDate: string;
10
+ lines: {
11
+ description: string;
12
+ quantity: number | null;
13
+ unit: string | null;
14
+ }[];
15
+ }): string;
16
+ export type { PickstationOrder };
17
+ //# sourceMappingURL=PakbonTemplate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PakbonTemplate.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/PakbonTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CAChF,GAAG,MAAM,CAkET;AAYD,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,74 @@
1
+ /** Returns a fully self-contained printable HTML document for one packing slip. */
2
+ export function renderPakbonHtml(order) {
3
+ const fmt = (d) => {
4
+ if (!d)
5
+ return "—";
6
+ const dt = new Date(d);
7
+ if (Number.isNaN(dt.getTime()))
8
+ return d;
9
+ return dt.toLocaleDateString("nl-NL", { day: "2-digit", month: "2-digit", year: "numeric" });
10
+ };
11
+ const rows = order.lines.length
12
+ ? order.lines
13
+ .map((l) => `
14
+ <tr>
15
+ <td>${escapeHtml(l.description)}</td>
16
+ <td style="text-align:right">${l.quantity ?? ""}</td>
17
+ <td>${escapeHtml(l.unit ?? "")}</td>
18
+ </tr>`)
19
+ .join("")
20
+ : `<tr><td colspan="3" style="text-align:center;color:#666">Geen regels</td></tr>`;
21
+ return `<!doctype html>
22
+ <html lang="nl">
23
+ <head>
24
+ <meta charset="utf-8">
25
+ <title>Pakbon ${escapeHtml(order.orderNumber)}</title>
26
+ <style>
27
+ @page { size: A4; margin: 16mm; }
28
+ body { font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; color:#111; }
29
+ h1 { margin: 0 0 4px; font-size: 26px; }
30
+ .sub { color:#444; margin-bottom: 18px; }
31
+ .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 24px; margin: 18px 0 22px; }
32
+ .grid div { font-size: 14px; }
33
+ .label { color:#666; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
34
+ .value { font-size: 16px; font-weight: 600; }
35
+ table { width:100%; border-collapse: collapse; font-size: 14px; }
36
+ th, td { padding: 8px 6px; border-bottom: 1px solid #ddd; vertical-align: top; }
37
+ th { text-align: left; background:#f5f5f5; }
38
+ .barcode { margin-top: 24px; font-family: "Libre Barcode 128", monospace; font-size: 56px; line-height: 1; }
39
+ .barcode-fallback { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 18px; letter-spacing: 4px; padding: 8px 12px; border: 2px solid #111; display: inline-block; }
40
+ .footer { margin-top: 28px; font-size: 11px; color:#666; }
41
+ </style>
42
+ </head>
43
+ <body>
44
+ <h1>Pakbon</h1>
45
+ <div class="sub">Order ${escapeHtml(order.orderNumber)}</div>
46
+
47
+ <div class="grid">
48
+ <div><div class="label">Klant</div><div class="value">${escapeHtml(order.customerName)}</div></div>
49
+ <div><div class="label">Land</div><div class="value">${escapeHtml(order.country ?? "—")}</div></div>
50
+ <div><div class="label">Leverdatum</div><div class="value">${fmt(order.deliveryDate)}</div></div>
51
+ <div><div class="label">Pickdatum</div><div class="value">${fmt(order.pickDate)}</div></div>
52
+ </div>
53
+
54
+ <table>
55
+ <thead><tr><th>Omschrijving</th><th style="text-align:right;width:90px">Aantal</th><th style="width:90px">Eenheid</th></tr></thead>
56
+ <tbody>${rows}</tbody>
57
+ </table>
58
+
59
+ <div class="barcode-fallback">*${escapeHtml(order.orderNumber)}*</div>
60
+
61
+ <div class="footer">Geprint via Pickstation · ${new Date().toLocaleString("nl-NL")}</div>
62
+
63
+ <script>window.addEventListener("load", function(){ setTimeout(function(){ try{ window.focus(); window.print(); }catch(e){} }, 100); });</script>
64
+ </body>
65
+ </html>`;
66
+ }
67
+ function escapeHtml(s) {
68
+ return s
69
+ .replace(/&/g, "&amp;")
70
+ .replace(/</g, "&lt;")
71
+ .replace(/>/g, "&gt;")
72
+ .replace(/"/g, "&quot;")
73
+ .replace(/'/g, "&#39;");
74
+ }
@@ -0,0 +1,3 @@
1
+ export declare function printHtml(html: string): Promise<void>;
2
+ export declare function printPdfBase64(base64: string, mime?: string): Promise<void>;
3
+ //# sourceMappingURL=printDocuments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"printDocuments.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/printDocuments.ts"],"names":[],"mappings":"AAqCA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3D;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAS5F"}