@flowselections/floriday-voorraad 1.0.13 → 1.0.15
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/assets/floriday-logo.png.asset.json +11 -0
- package/dist-lib/components/voorraad/ArtikelWizard.d.ts +5 -0
- package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/ArtikelWizard.js +1229 -0
- package/dist-lib/components/voorraad/EditArtikelPage.d.ts +4 -0
- package/dist-lib/components/voorraad/EditArtikelPage.d.ts.map +1 -0
- package/dist-lib/components/voorraad/EditArtikelPage.js +51 -0
- package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts +2 -0
- package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts.map +1 -0
- package/dist-lib/components/voorraad/NieuwArtikelPage.js +5 -0
- package/dist-lib/components/voorraad/StockBulkButtons.d.ts +7 -0
- package/dist-lib/components/voorraad/StockBulkButtons.d.ts.map +1 -0
- package/dist-lib/components/voorraad/StockBulkButtons.js +356 -0
- package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts +7 -0
- package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts.map +1 -0
- package/dist-lib/components/voorraad/ValidationOverviewTable.js +87 -0
- package/dist-lib/components/voorraad/ValidationPage.d.ts +2 -0
- package/dist-lib/components/voorraad/ValidationPage.d.ts.map +1 -0
- package/dist-lib/components/voorraad/ValidationPage.js +12 -0
- package/dist-lib/components/voorraad/VoorraadDashboard.d.ts +6 -0
- package/dist-lib/components/voorraad/VoorraadDashboard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/VoorraadDashboard.js +42 -0
- package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadPage.js +70 -11
- package/dist-lib/components/voorraad/VoorraadPagination.d.ts +10 -0
- package/dist-lib/components/voorraad/VoorraadPagination.d.ts.map +1 -0
- package/dist-lib/components/voorraad/VoorraadPagination.js +12 -0
- package/dist-lib/components/voorraad/VoorraadStockCard.d.ts +8 -0
- package/dist-lib/components/voorraad/VoorraadStockCard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/VoorraadStockCard.js +33 -0
- package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadTable.js +16 -5
- package/dist-lib/hooks/useFloriday.d.ts +55 -0
- package/dist-lib/hooks/useFloriday.d.ts.map +1 -0
- package/dist-lib/hooks/useFloriday.js +298 -0
- package/dist-lib/hooks/useLocalTradeItems.d.ts +17 -1
- package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
- package/dist-lib/hooks/useLocalTradeItems.js +54 -10
- package/dist-lib/hooks/useTradeItemSpec.d.ts +42 -0
- package/dist-lib/hooks/useTradeItemSpec.d.ts.map +1 -0
- package/dist-lib/hooks/useTradeItemSpec.js +448 -0
- package/dist-lib/hooks/useTradeItemStock.d.ts +19 -0
- package/dist-lib/hooks/useTradeItemStock.d.ts.map +1 -0
- package/dist-lib/hooks/useTradeItemStock.js +78 -0
- package/dist-lib/hooks/useVbnRegulatoryFeatures.d.ts +3 -0
- package/dist-lib/hooks/useVbnRegulatoryFeatures.d.ts.map +1 -0
- package/dist-lib/hooks/useVbnRegulatoryFeatures.js +19 -0
- package/dist-lib/hooks/useVoorraadData.d.ts +2 -1
- package/dist-lib/hooks/useVoorraadData.d.ts.map +1 -1
- package/dist-lib/hooks/useVoorraadData.js +39 -11
- package/dist-lib/index.d.ts +4 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +6 -5
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +8346 -3367
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +8346 -3367
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +8346 -3367
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +8460 -3341
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +10 -1
- package/dist-lib/lib/__tests__/floricode-required-features.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/floricode-required-features.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/floricode-required-features.test.js +186 -0
- package/dist-lib/lib/floricode-client.d.ts +15 -1
- package/dist-lib/lib/floricode-client.d.ts.map +1 -1
- package/dist-lib/lib/floricode-client.js +42 -4
- package/dist-lib/lib/floricode-required-features.functions.d.ts +10026 -0
- package/dist-lib/lib/floricode-required-features.functions.d.ts.map +1 -0
- package/dist-lib/lib/floricode-required-features.functions.js +170 -0
- package/dist-lib/lib/floriday-client.d.ts +36 -8
- package/dist-lib/lib/floriday-client.d.ts.map +1 -1
- package/dist-lib/lib/floriday-client.js +206 -25
- package/dist-lib/lib/floriday-env.d.ts +29 -0
- package/dist-lib/lib/floriday-env.d.ts.map +1 -0
- package/dist-lib/lib/floriday-env.js +42 -0
- package/dist-lib/lib/floriday-env.server.d.ts +15 -0
- package/dist-lib/lib/floriday-env.server.d.ts.map +1 -0
- package/dist-lib/lib/floriday-env.server.js +13 -0
- package/dist-lib/lib/floriday-field-sources.d.ts +18 -0
- package/dist-lib/lib/floriday-field-sources.d.ts.map +1 -0
- package/dist-lib/lib/floriday-field-sources.js +45 -0
- package/dist-lib/lib/floriday-gateway-entities.d.ts +44 -0
- package/dist-lib/lib/floriday-gateway-entities.d.ts.map +1 -0
- package/dist-lib/lib/floriday-gateway-entities.js +51 -0
- package/dist-lib/lib/floriday-gateway.functions.d.ts +39999 -0
- package/dist-lib/lib/floriday-gateway.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-gateway.functions.js +68 -0
- package/dist-lib/lib/floriday-gateway.server.d.ts +122 -0
- package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -0
- package/dist-lib/lib/floriday-gateway.server.js +230 -0
- package/dist-lib/lib/floriday-import-validator.d.ts +26 -0
- package/dist-lib/lib/floriday-import-validator.d.ts.map +1 -0
- package/dist-lib/lib/floriday-import-validator.js +41 -0
- package/dist-lib/lib/floriday-payload.d.ts +47 -3
- package/dist-lib/lib/floriday-payload.d.ts.map +1 -1
- package/dist-lib/lib/floriday-payload.js +179 -7
- package/dist-lib/lib/floriday-schema-to-zod.d.ts +9 -0
- package/dist-lib/lib/floriday-schema-to-zod.d.ts.map +1 -0
- package/dist-lib/lib/floriday-schema-to-zod.js +53 -0
- package/dist-lib/lib/floriday-writes.functions.d.ts +19998 -0
- package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-writes.functions.js +74 -0
- package/dist-lib/lib/image-resize.d.ts +43 -0
- package/dist-lib/lib/image-resize.d.ts.map +1 -0
- package/dist-lib/lib/image-resize.js +212 -0
- package/dist-lib/lib/normalize-errors-middleware.d.ts +2 -0
- package/dist-lib/lib/normalize-errors-middleware.d.ts.map +1 -0
- package/dist-lib/lib/normalize-errors-middleware.js +24 -0
- package/dist-lib/lib/wizard-step-fields.d.ts +15 -0
- package/dist-lib/lib/wizard-step-fields.d.ts.map +1 -0
- package/dist-lib/lib/wizard-step-fields.js +51 -0
- package/package.json +35 -14
|
@@ -1,31 +1,90 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
2
|
+
import { useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { Link } from "@tanstack/react-router";
|
|
4
|
-
import { Button, Card, Input
|
|
5
|
-
import {
|
|
4
|
+
import { Button, Card, Input } from "@flowselections/core";
|
|
5
|
+
import { AlertTriangle, CheckCircle2, FileText, PackageX, Plus, Search, } from "lucide-react";
|
|
6
6
|
import { useFloridayConnection } from "../../hooks/useFloridayConnection";
|
|
7
7
|
import { useVoorraadData } from "../../hooks/useVoorraadData";
|
|
8
|
-
import { ConnectionBadge } from "./ConnectionBadge";
|
|
9
8
|
import { ExcelExportButton } from "./ExcelExportButton";
|
|
9
|
+
import { StockBulkButtons } from "./StockBulkButtons";
|
|
10
10
|
import { VoorraadTable } from "./VoorraadTable";
|
|
11
|
+
import { VoorraadPagination } from "./VoorraadPagination";
|
|
12
|
+
function toneClasses(tone) {
|
|
13
|
+
switch (tone) {
|
|
14
|
+
case "emerald":
|
|
15
|
+
return { icon: "bg-emerald-100 text-emerald-700", value: "text-foreground" };
|
|
16
|
+
case "rose":
|
|
17
|
+
return { icon: "bg-rose-100 text-rose-700", value: "text-foreground" };
|
|
18
|
+
case "amber":
|
|
19
|
+
return { icon: "bg-amber-100 text-amber-700", value: "text-foreground" };
|
|
20
|
+
case "primary":
|
|
21
|
+
default:
|
|
22
|
+
return { icon: "bg-primary/10 text-primary", value: "text-foreground" };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function KpiCard({ icon, label, count, tone, active, onClick, }) {
|
|
26
|
+
const cls = toneClasses(tone);
|
|
27
|
+
return (_jsxs("button", { type: "button", onClick: onClick, className: `text-left rounded-lg border bg-card p-4 transition-colors hover:border-primary/50 ${active ? "border-primary ring-1 ring-primary" : "border-border"}`, children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: `inline-flex h-8 w-8 items-center justify-center rounded-md ${cls.icon}`, children: icon }), _jsx("span", { className: "text-sm font-medium text-foreground", children: label })] }), _jsx("div", { className: `mt-3 text-3xl font-bold tabular-nums ${cls.value}`, children: count })] }));
|
|
28
|
+
}
|
|
29
|
+
function availableOf(i) {
|
|
30
|
+
return i.availableQuantity ?? i.quantity ?? 0;
|
|
31
|
+
}
|
|
11
32
|
export function VoorraadPage() {
|
|
12
|
-
const {
|
|
33
|
+
const { activeId, error: connError } = useFloridayConnection();
|
|
13
34
|
const { items, loading, error, reload } = useVoorraadData(activeId);
|
|
14
35
|
const [search, setSearch] = useState("");
|
|
15
|
-
const [
|
|
36
|
+
const [stockFilter, setStockFilter] = useState("all");
|
|
37
|
+
const [page, setPage] = useState(1);
|
|
38
|
+
const [pageSize, setPageSize] = useState(25);
|
|
39
|
+
const counts = useMemo(() => {
|
|
40
|
+
let inStock = 0;
|
|
41
|
+
let outOfStock = 0;
|
|
42
|
+
let belowMin = 0;
|
|
43
|
+
for (const i of items) {
|
|
44
|
+
const avail = availableOf(i);
|
|
45
|
+
if (avail > 0)
|
|
46
|
+
inStock++;
|
|
47
|
+
else
|
|
48
|
+
outOfStock++;
|
|
49
|
+
if ((i.minQuantity ?? 0) > 0 && avail < i.minQuantity)
|
|
50
|
+
belowMin++;
|
|
51
|
+
}
|
|
52
|
+
return { total: items.length, inStock, outOfStock, belowMin };
|
|
53
|
+
}, [items]);
|
|
16
54
|
const filtered = useMemo(() => {
|
|
17
55
|
const q = search.trim().toLowerCase();
|
|
18
56
|
return items.filter((i) => {
|
|
19
|
-
|
|
57
|
+
const avail = availableOf(i);
|
|
58
|
+
if (stockFilter === "in_stock" && avail <= 0)
|
|
59
|
+
return false;
|
|
60
|
+
if (stockFilter === "out_of_stock" && avail > 0)
|
|
20
61
|
return false;
|
|
21
|
-
if (
|
|
62
|
+
if (stockFilter === "below_min" &&
|
|
63
|
+
!((i.minQuantity ?? 0) > 0 && avail < i.minQuantity))
|
|
22
64
|
return false;
|
|
23
65
|
if (!q)
|
|
24
66
|
return true;
|
|
25
67
|
return (i.name.toLowerCase().includes(q) ||
|
|
26
68
|
(i.articleNumber ?? "").toLowerCase().includes(q));
|
|
27
69
|
});
|
|
28
|
-
}, [items, search,
|
|
29
|
-
const
|
|
30
|
-
|
|
70
|
+
}, [items, search, stockFilter]);
|
|
71
|
+
const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (page > totalPages)
|
|
74
|
+
setPage(1);
|
|
75
|
+
}, [page, totalPages]);
|
|
76
|
+
const paged = useMemo(() => filtered.slice((page - 1) * pageSize, page * pageSize), [filtered, page, pageSize]);
|
|
77
|
+
const toggle = (id) => setStockFilter((cur) => (cur === id && id !== "all" ? "all" : id));
|
|
78
|
+
const TABS = [
|
|
79
|
+
{ id: "all", label: "Alle", count: counts.total },
|
|
80
|
+
{ id: "in_stock", label: "Op voorraad", count: counts.inStock },
|
|
81
|
+
{ id: "out_of_stock", label: "Niet op voorraad", count: counts.outOfStock },
|
|
82
|
+
{ id: "below_min", label: "Onder minimum", count: counts.belowMin },
|
|
83
|
+
];
|
|
84
|
+
return (_jsxs("main", { className: "p-6 space-y-6", children: [_jsxs("header", { className: "grid grid-cols-[minmax(0,1fr)_auto] items-start gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h1", { className: "text-2xl font-bold tracking-tight truncate", children: "Voorraad" }), _jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Beheer je artikelen en voorraadniveaus." })] }), _jsx(Button, { asChild: true, disabled: !activeId, size: "sm", className: "shrink-0", children: _jsxs(Link, { to: "/voorraad/nieuw", children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Artikel toevoegen"] }) })] }), connError && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 text-destructive p-3 text-sm", children: ["Floriday-connectie laden mislukt: ", connError] })), error && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 text-destructive p-3 text-sm", children: ["Voorraad laden mislukt: ", error] })), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4", children: [_jsx(KpiCard, { icon: _jsx(FileText, { className: "h-4 w-4" }), tone: "primary", label: "Artikelen", count: counts.total, active: stockFilter === "all", onClick: () => toggle("all") }), _jsx(KpiCard, { icon: _jsx(CheckCircle2, { className: "h-4 w-4" }), tone: "emerald", label: "Op voorraad", count: counts.inStock, active: stockFilter === "in_stock", onClick: () => toggle("in_stock") }), _jsx(KpiCard, { icon: _jsx(PackageX, { className: "h-4 w-4" }), tone: "rose", label: "Niet op voorraad", count: counts.outOfStock, active: stockFilter === "out_of_stock", onClick: () => toggle("out_of_stock") }), _jsx(KpiCard, { icon: _jsx(AlertTriangle, { className: "h-4 w-4" }), tone: "amber", label: "Onder minimum", count: counts.belowMin, active: stockFilter === "below_min", onClick: () => toggle("below_min") })] }), _jsxs(Card, { className: "overflow-hidden p-0", children: [_jsx("div", { className: "flex flex-wrap items-center gap-1 border-b px-4", children: TABS.map((t) => {
|
|
85
|
+
const active = stockFilter === t.id;
|
|
86
|
+
return (_jsxs("button", { type: "button", onClick: () => setStockFilter(t.id), className: `relative py-3 px-3 text-sm font-medium whitespace-nowrap transition-colors ${active
|
|
87
|
+
? "text-foreground"
|
|
88
|
+
: "text-muted-foreground hover:text-foreground"}`, children: [t.label, _jsx("span", { className: `ml-2 text-xs ${active ? "text-primary" : "text-muted-foreground/70"}`, children: t.count }), active && (_jsx("span", { className: "absolute left-2 right-2 -bottom-px h-0.5 bg-primary rounded-full" }))] }, t.id));
|
|
89
|
+
}) }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 p-4 border-b", children: [_jsxs("div", { className: "relative flex-1 min-w-[220px] max-w-md", children: [_jsx(Search, { className: "w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { placeholder: "Zoek op product of artikelnummer...", className: "pl-9", value: search, onChange: (e) => setSearch(e.target.value) })] }), _jsxs("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: [_jsx(ExcelExportButton, { items: filtered }), _jsx(StockBulkButtons, { items: items, activeConnectionId: activeId, onImported: reload })] })] }), _jsx("div", { className: "overflow-x-auto", children: _jsx(VoorraadTable, { items: paged, loading: loading }) }), _jsx(VoorraadPagination, { total: filtered.length, page: page, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize })] })] }));
|
|
31
90
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface VoorraadPaginationProps {
|
|
2
|
+
total: number;
|
|
3
|
+
page: number;
|
|
4
|
+
pageSize: number;
|
|
5
|
+
pageSizeOptions?: number[];
|
|
6
|
+
onPageChange: (page: number) => void;
|
|
7
|
+
onPageSizeChange: (size: number) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function VoorraadPagination({ total, page, pageSize, pageSizeOptions, onPageChange, onPageSizeChange, }: VoorraadPaginationProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=VoorraadPagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoorraadPagination.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPagination.tsx"],"names":[],"mappings":"AASA,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C;AAED,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,eAAmC,EACnC,YAAY,EACZ,gBAAgB,GACjB,EAAE,uBAAuB,2CAuDzB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
|
|
3
|
+
export function VoorraadPagination({ total, page, pageSize, pageSizeOptions = [10, 25, 50, 100], onPageChange, onPageSizeChange, }) {
|
|
4
|
+
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
5
|
+
const safePage = Math.min(Math.max(1, page), totalPages);
|
|
6
|
+
const from = total === 0 ? 0 : (safePage - 1) * pageSize + 1;
|
|
7
|
+
const to = Math.min(total, safePage * pageSize);
|
|
8
|
+
return (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t px-4 py-2 text-sm text-muted-foreground", children: [_jsx("div", { children: total === 0 ? "0 van 0" : `${from}–${to} van ${total}` }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { children: "Per pagina" }), _jsxs(Select, { value: String(pageSize), onValueChange: (v) => {
|
|
9
|
+
onPageSizeChange(Number(v));
|
|
10
|
+
onPageChange(1);
|
|
11
|
+
}, children: [_jsx(SelectTrigger, { className: "h-8 w-[72px]", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: pageSizeOptions.map((opt) => (_jsx(SelectItem, { value: String(opt), children: opt }, opt))) })] })] }), _jsx(Button, { variant: "outline", size: "sm", disabled: safePage <= 1, onClick: () => onPageChange(safePage - 1), children: "Vorige" }), _jsxs("span", { className: "tabular-nums", children: [safePage, " / ", totalPages] }), _jsx(Button, { variant: "outline", size: "sm", disabled: safePage >= totalPages, onClick: () => onPageChange(safePage + 1), children: "Volgende" })] })] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
connectionId: string | null;
|
|
3
|
+
tradeItemId?: string | null;
|
|
4
|
+
draftId?: string | null;
|
|
5
|
+
}
|
|
6
|
+
export declare function VoorraadStockCard({ connectionId, tradeItemId, draftId }: Props): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=VoorraadStockCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoorraadStockCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadStockCard.tsx"],"names":[],"mappings":"AAaA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,KAAK,2CAoG9E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Button, Card, CardContent, Input, Label, Textarea, toast, } from "@flowselections/core";
|
|
4
|
+
import { Loader2, Package, Check } from "lucide-react";
|
|
5
|
+
import { useTradeItemStock, stockKeyFor } from "../../hooks/useTradeItemStock";
|
|
6
|
+
export function VoorraadStockCard({ connectionId, tradeItemId, draftId }) {
|
|
7
|
+
const key = stockKeyFor({ tradeItemId, draftId });
|
|
8
|
+
const { row, loading, save } = useTradeItemStock(connectionId, key);
|
|
9
|
+
const [values, setValues] = useState(row);
|
|
10
|
+
const [saving, setSaving] = useState(false);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
setValues(row);
|
|
13
|
+
}, [row.updated_at, row.physical_stock, row.minimum_stock, row.reserved_stock, row.incoming_stock, row.notes]);
|
|
14
|
+
if (!key) {
|
|
15
|
+
return (_jsx(Card, { className: "p-4 text-sm text-muted-foreground", children: "Voorraad kan pas worden ingesteld nadat het artikel voor het eerst is opgeslagen." }));
|
|
16
|
+
}
|
|
17
|
+
const available = Math.max(0, values.physical_stock - values.reserved_stock);
|
|
18
|
+
const handleSave = async () => {
|
|
19
|
+
setSaving(true);
|
|
20
|
+
try {
|
|
21
|
+
await save(values);
|
|
22
|
+
toast.success("Voorraad bijgewerkt");
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
toast.error(`Opslaan mislukt: ${e.message}`);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
setSaving(false);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const numField = (id, label) => (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: id, children: label }), _jsx(Input, { id: id, type: "number", min: 0, value: String(values[id] ?? 0), onChange: (e) => setValues((v) => ({ ...v, [id]: Number(e.target.value) || 0 })) })] }));
|
|
32
|
+
return (_jsxs(Card, { children: [_jsxs("div", { className: "grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-3 px-6 py-4", children: [_jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-full border border-primary/40 bg-primary/10 text-primary", children: _jsx(Package, { className: "h-4 w-4" }) }), _jsx("span", { className: "font-medium", children: "Voorraad" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Beschikbaar: ", _jsx("span", { className: "tabular-nums font-medium text-foreground", children: available })] })] }), _jsx(CardContent, { className: "pt-0 space-y-4", children: loading ? (_jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Voorraad laden\u2026"] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid grid-cols-2 gap-4 sm:grid-cols-4", children: [numField("physical_stock", "Liggend"), numField("minimum_stock", "Minimum"), numField("reserved_stock", "Gereserveerd"), numField("incoming_stock", "Inkomend")] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: "stock-notes", children: "Notitie (optioneel)" }), _jsx(Textarea, { id: "stock-notes", rows: 2, value: values.notes ?? "", onChange: (e) => setValues((v) => ({ ...v, notes: e.target.value })), placeholder: "Bijv. locatie of opmerking" })] }), _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { onClick: handleSave, disabled: saving, children: [saving ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Check, { className: "mr-2 h-4 w-4" })), "Voorraad opslaan"] }) })] })) })] }));
|
|
33
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAW3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,
|
|
1
|
+
{"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAW3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,2CA8GA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useNavigate } from "@tanstack/react-router";
|
|
3
3
|
import { Badge } from "@flowselections/core";
|
|
4
4
|
import { Package } from "lucide-react";
|
|
5
5
|
const columns = [
|
|
@@ -11,6 +11,7 @@ const columns = [
|
|
|
11
11
|
{ key: "economicQuantity", label: "Economisch" },
|
|
12
12
|
];
|
|
13
13
|
export function VoorraadTable({ items, loading, }) {
|
|
14
|
+
const navigate = useNavigate();
|
|
14
15
|
if (loading) {
|
|
15
16
|
return _jsx("p", { className: "text-sm text-muted-foreground p-6", children: "Voorraad laden..." });
|
|
16
17
|
}
|
|
@@ -22,9 +23,19 @@ export function VoorraadTable({ items, loading, }) {
|
|
|
22
23
|
const low = !isLocal &&
|
|
23
24
|
item.minQuantity > 0 &&
|
|
24
25
|
item.availableQuantity < item.minQuantity;
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const linkId = isLocal ? item.localId : item.id;
|
|
27
|
+
const clickable = Boolean(linkId);
|
|
28
|
+
const open = () => {
|
|
29
|
+
if (linkId)
|
|
30
|
+
navigate({ to: "/voorraad/$id", params: { id: linkId } });
|
|
31
|
+
};
|
|
32
|
+
return (_jsxs("tr", { className: `border-t hover:bg-muted/30 ${clickable ? "cursor-pointer" : ""}`, onClick: clickable ? open : undefined, role: clickable ? "button" : undefined, tabIndex: clickable ? 0 : undefined, onKeyDown: clickable
|
|
33
|
+
? (e) => {
|
|
34
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
open();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
: undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [_jsx("td", { className: "p-2", children: item.imageUrl ? (_jsx("img", { src: item.imageUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: "font-medium text-foreground", children: item.name }), isLocal && (_jsx(Badge, { variant: "outline", className: "text-[10px] font-normal text-muted-foreground border-amber-500/40 bg-amber-500/10", children: "Niet gepubliceerd" }))] }), low && (_jsx("div", { className: "text-xs text-destructive", children: "onder minimumvoorraad" }))] }), _jsx("td", { className: "p-3 font-mono text-xs", children: item.articleNumber || "—" }), columns.map((c) => (_jsx("td", { className: "p-3 text-right tabular-nums text-muted-foreground", children: Number(item[c.key] ?? 0) }, c.key)))] }, item.id));
|
|
29
40
|
}) })] }) }));
|
|
30
41
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export interface FloridaySchemaField {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
enum?: string[];
|
|
6
|
+
description?: string;
|
|
7
|
+
minLength?: number;
|
|
8
|
+
maxLength?: number;
|
|
9
|
+
minimum?: number;
|
|
10
|
+
maximum?: number;
|
|
11
|
+
pattern?: string;
|
|
12
|
+
nullable?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface FloridaySchema {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
resource: string;
|
|
17
|
+
version: string;
|
|
18
|
+
requiredFields: string[];
|
|
19
|
+
fields: FloridaySchemaField[];
|
|
20
|
+
enums?: Record<string, string[]>;
|
|
21
|
+
schema?: unknown;
|
|
22
|
+
/** §15.2 — code-lists die in dezelfde call zijn meegeleverd. */
|
|
23
|
+
codeLists?: Record<string, Array<{
|
|
24
|
+
code: string;
|
|
25
|
+
label?: string | null;
|
|
26
|
+
description?: string | null;
|
|
27
|
+
payload?: unknown;
|
|
28
|
+
}>>;
|
|
29
|
+
}
|
|
30
|
+
export declare function useFloridaySchema(resource: string, params?: Record<string, string>): import("@tanstack/react-query").UseQueryResult<FloridaySchema, Error>;
|
|
31
|
+
export declare function useTradeItemFormSchema(): import("@tanstack/react-query").UseQueryResult<FloridaySchema, Error>;
|
|
32
|
+
export declare function useCodeList(listName: string | null | undefined): import("@tanstack/react-query").UseQueryResult<{
|
|
33
|
+
ok: boolean;
|
|
34
|
+
listName: string;
|
|
35
|
+
values: {
|
|
36
|
+
code: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
}[];
|
|
39
|
+
}, Error>;
|
|
40
|
+
import type { GatewayEntity } from "../lib/floriday-gateway-entities";
|
|
41
|
+
export declare function useCachedList(entity: GatewayEntity | null | undefined, limit?: number): import("@tanstack/react-query").UseQueryResult<{
|
|
42
|
+
ok: boolean;
|
|
43
|
+
entity: string;
|
|
44
|
+
rows: {
|
|
45
|
+
id: string;
|
|
46
|
+
data: Record<string, any>;
|
|
47
|
+
}[];
|
|
48
|
+
}, Error>;
|
|
49
|
+
/**
|
|
50
|
+
* Invalideert alle floriday-* queries wanneer de actieve connectie
|
|
51
|
+
* (en dus mogelijk de environment) wijzigt. Voorkomt cache-bleed
|
|
52
|
+
* tussen staging en live bij een toekomstige switcher.
|
|
53
|
+
*/
|
|
54
|
+
export declare function useInvalidateFloridayOnConnectionChange(): void;
|
|
55
|
+
//# sourceMappingURL=useFloriday.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFloriday.d.ts","sourceRoot":"","sources":["../../src/hooks/useFloriday.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAChB,MAAM,EACN,KAAK,CAAC;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC,CACH,CAAC;CACH;AAoMD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,yEA0BhC;AAqBD,wBAAgB,sBAAsB,0EA0CrC;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;QAMnD,OAAO;cACD,MAAM;YACR;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE;UAKvD;AAED,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EACxC,KAAK,SAAO;QAOF,OAAO;YACH,MAAM;UACR;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,EAAE;UAKxD;AAED;;;;GAIG;AACH,wBAAgB,uCAAuC,SAStD"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import { gatewaySchemaFn, gatewayCodeListFn, gatewayCachedListFn, } from "../lib/floriday-gateway.functions";
|
|
4
|
+
import { unmappedRequiredFields } from "../lib/wizard-step-fields";
|
|
5
|
+
import { useFloridayConnection } from "./useFloridayConnection";
|
|
6
|
+
import { normalizeFloridayEnvironment } from "../lib/floriday-env";
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
function arrayFromCodeListValue(value) {
|
|
11
|
+
if (Array.isArray(value))
|
|
12
|
+
return value;
|
|
13
|
+
if (!isRecord(value))
|
|
14
|
+
return [];
|
|
15
|
+
const candidates = [
|
|
16
|
+
value.values,
|
|
17
|
+
value.items,
|
|
18
|
+
value.rows,
|
|
19
|
+
value.data,
|
|
20
|
+
value.payload,
|
|
21
|
+
value.entries,
|
|
22
|
+
];
|
|
23
|
+
for (const c of candidates) {
|
|
24
|
+
if (Array.isArray(c))
|
|
25
|
+
return c;
|
|
26
|
+
}
|
|
27
|
+
// Sommige gateway-implementaties geven een codelijst als dictionary terug:
|
|
28
|
+
// { "S62": { description: "..." }, "S98": "..." }. Maak daar alsnog
|
|
29
|
+
// entries van. Een object dat zelf één entry is (heeft code/id/value) laten
|
|
30
|
+
// we ongemoeid om dubbele parsing te voorkomen.
|
|
31
|
+
if (value.code != null || value.id != null || value.value != null)
|
|
32
|
+
return [value];
|
|
33
|
+
return Object.entries(value).map(([code, entry]) => isRecord(entry) ? { code, ...entry } : { code, label: entry });
|
|
34
|
+
}
|
|
35
|
+
function canonicalCodeListName(name) {
|
|
36
|
+
const kebab = name
|
|
37
|
+
.trim()
|
|
38
|
+
.replace(/_/g, "-")
|
|
39
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
40
|
+
.toLowerCase();
|
|
41
|
+
const aliases = {
|
|
42
|
+
vbnproductgroup: "vbn-product-group",
|
|
43
|
+
"vbn-productgroup": "vbn-product-group",
|
|
44
|
+
"vbn-product-groups": "vbn-product-group",
|
|
45
|
+
characteristics: "characteristic",
|
|
46
|
+
"characteristic-type": "characteristic",
|
|
47
|
+
"characteristic-types": "characteristic",
|
|
48
|
+
packagingtype: "packaging-type",
|
|
49
|
+
countryoforigin: "country-of-origin",
|
|
50
|
+
lengthunit: "length-unit",
|
|
51
|
+
};
|
|
52
|
+
return aliases[kebab] ?? aliases[kebab.replace(/-/g, "")] ?? kebab;
|
|
53
|
+
}
|
|
54
|
+
function pickCode(value) {
|
|
55
|
+
if (!isRecord(value))
|
|
56
|
+
return String(value ?? "").trim();
|
|
57
|
+
const payload = isRecord(value.payload) ? value.payload : isRecord(value.data) ? value.data : undefined;
|
|
58
|
+
const raw = value.code ??
|
|
59
|
+
value.id ??
|
|
60
|
+
value.value ??
|
|
61
|
+
value.vbnProductCode ??
|
|
62
|
+
value.productCode ??
|
|
63
|
+
value.vbnCode ??
|
|
64
|
+
value.record_id ??
|
|
65
|
+
payload?.code ??
|
|
66
|
+
payload?.id ??
|
|
67
|
+
payload?.vbnProductCode ??
|
|
68
|
+
payload?.productCode ??
|
|
69
|
+
payload?.vbnCode ??
|
|
70
|
+
payload?.record_id;
|
|
71
|
+
return String(raw ?? "").trim();
|
|
72
|
+
}
|
|
73
|
+
function pickLabel(value, code) {
|
|
74
|
+
if (!isRecord(value))
|
|
75
|
+
return code || String(value ?? "").trim() || null;
|
|
76
|
+
const payload = isRecord(value.payload) ? value.payload : isRecord(value.data) ? value.data : undefined;
|
|
77
|
+
const raw = value.label ??
|
|
78
|
+
value.description ??
|
|
79
|
+
value.name ??
|
|
80
|
+
value.displayName ??
|
|
81
|
+
value.title ??
|
|
82
|
+
payload?.label ??
|
|
83
|
+
payload?.description ??
|
|
84
|
+
payload?.name ??
|
|
85
|
+
payload?.displayName ??
|
|
86
|
+
payload?.title;
|
|
87
|
+
return raw == null ? (code || null) : String(raw);
|
|
88
|
+
}
|
|
89
|
+
function normalizeCodeListEntries(value) {
|
|
90
|
+
return arrayFromCodeListValue(value)
|
|
91
|
+
.map((entry) => {
|
|
92
|
+
const code = pickCode(entry);
|
|
93
|
+
if (!code)
|
|
94
|
+
return null;
|
|
95
|
+
const label = pickLabel(entry, code);
|
|
96
|
+
const payload = isRecord(entry)
|
|
97
|
+
? entry.payload ?? entry.data ?? entry
|
|
98
|
+
: entry;
|
|
99
|
+
return { code, label, description: label, payload };
|
|
100
|
+
})
|
|
101
|
+
.filter(Boolean);
|
|
102
|
+
}
|
|
103
|
+
function normalizeCodeLists(raw) {
|
|
104
|
+
const root = isRecord(raw) ? raw : {};
|
|
105
|
+
const data = isRecord(root.data) ? root.data : undefined;
|
|
106
|
+
const payload = isRecord(root.payload) ? root.payload : undefined;
|
|
107
|
+
const result = isRecord(root.result) ? root.result : undefined;
|
|
108
|
+
const included = isRecord(root.included) ? root.included : undefined;
|
|
109
|
+
const containers = [
|
|
110
|
+
root.codeLists,
|
|
111
|
+
root.code_lists,
|
|
112
|
+
root.includedCodeLists,
|
|
113
|
+
root.included_code_lists,
|
|
114
|
+
data?.codeLists,
|
|
115
|
+
data?.code_lists,
|
|
116
|
+
data?.includedCodeLists,
|
|
117
|
+
data?.included_code_lists,
|
|
118
|
+
isRecord(data?.payload) ? data?.payload?.codeLists ?? data?.payload?.code_lists : undefined,
|
|
119
|
+
payload?.codeLists,
|
|
120
|
+
payload?.code_lists,
|
|
121
|
+
result?.codeLists,
|
|
122
|
+
result?.code_lists,
|
|
123
|
+
included?.codeLists,
|
|
124
|
+
included?.code_lists,
|
|
125
|
+
];
|
|
126
|
+
const out = {};
|
|
127
|
+
for (const container of containers) {
|
|
128
|
+
if (Array.isArray(container)) {
|
|
129
|
+
for (const list of container) {
|
|
130
|
+
if (!isRecord(list))
|
|
131
|
+
continue;
|
|
132
|
+
const name = canonicalCodeListName(String(list.name ?? list.listName ?? list.key ?? list.resource ?? ""));
|
|
133
|
+
if (!name)
|
|
134
|
+
continue;
|
|
135
|
+
const entries = normalizeCodeListEntries(list.values ?? list.items ?? list.rows ?? list.data ?? list.payload);
|
|
136
|
+
if (entries.length)
|
|
137
|
+
out[name] = entries;
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (!isRecord(container))
|
|
142
|
+
continue;
|
|
143
|
+
for (const [name, value] of Object.entries(container)) {
|
|
144
|
+
const canonicalName = canonicalCodeListName(name);
|
|
145
|
+
const entries = normalizeCodeListEntries(value);
|
|
146
|
+
if (entries.length)
|
|
147
|
+
out[canonicalName] = entries;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return Object.keys(out).length ? out : undefined;
|
|
151
|
+
}
|
|
152
|
+
function normalizeSchemaResponse(raw) {
|
|
153
|
+
const root = isRecord(raw) ? raw : {};
|
|
154
|
+
const data = isRecord(root.data) ? root.data : undefined;
|
|
155
|
+
const payload = isRecord(root.payload) ? root.payload : undefined;
|
|
156
|
+
const source = data && (data.fields || data.requiredFields || data.schema || data.enums || data.codeLists || data.code_lists)
|
|
157
|
+
? data
|
|
158
|
+
: payload && (payload.fields || payload.requiredFields || payload.schema || payload.enums || payload.codeLists || payload.code_lists)
|
|
159
|
+
? payload
|
|
160
|
+
: root;
|
|
161
|
+
const rawSchema = source.schema ?? source.jsonSchema ?? source.openApiSchema ?? source.swaggerSchema;
|
|
162
|
+
const codeLists = normalizeCodeLists(raw);
|
|
163
|
+
return {
|
|
164
|
+
...source,
|
|
165
|
+
ok: Boolean(root.ok ?? source.ok),
|
|
166
|
+
resource: String(source.resource ?? root.resource ?? "trade-item"),
|
|
167
|
+
version: String(source.version ?? root.version ?? ""),
|
|
168
|
+
requiredFields: Array.isArray(source.requiredFields)
|
|
169
|
+
? source.requiredFields.map(String)
|
|
170
|
+
: Array.isArray(source.required)
|
|
171
|
+
? source.required.map(String)
|
|
172
|
+
: [],
|
|
173
|
+
fields: Array.isArray(source.fields) ? source.fields : [],
|
|
174
|
+
enums: isRecord(source.enums) ? source.enums : undefined,
|
|
175
|
+
schema: rawSchema,
|
|
176
|
+
codeLists,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Cache-segment per environment zodat een latere live/staging-switch geen
|
|
181
|
+
* stale data uit de andere environment toont. De server resolved de echte
|
|
182
|
+
* environment uit de actieve connectie; deze key is puur voor de query-cache.
|
|
183
|
+
*/
|
|
184
|
+
function useEnvKey() {
|
|
185
|
+
const { environment } = useFloridayConnection();
|
|
186
|
+
try {
|
|
187
|
+
return environment ? normalizeFloridayEnvironment(environment) : "unknown";
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return "unknown";
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
export function useFloridaySchema(resource, params) {
|
|
194
|
+
const envKey = useEnvKey();
|
|
195
|
+
const paramsKey = params ? JSON.stringify(params) : "";
|
|
196
|
+
const q = useQuery({
|
|
197
|
+
queryKey: ["floriday-schema", resource, paramsKey, envKey],
|
|
198
|
+
queryFn: async () => (await gatewaySchemaFn({
|
|
199
|
+
data: { resource, ...(params ?? {}) },
|
|
200
|
+
})),
|
|
201
|
+
staleTime: 60 * 60 * 1000,
|
|
202
|
+
});
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
if (!q.data?.requiredFields)
|
|
205
|
+
return;
|
|
206
|
+
const missing = unmappedRequiredFields(q.data.requiredFields);
|
|
207
|
+
if (missing.length && import.meta.env.DEV) {
|
|
208
|
+
console.warn(`[floriday-schema] ${resource}: required fields zonder step-mapping:`, missing);
|
|
209
|
+
}
|
|
210
|
+
}, [q.data?.requiredFields, resource]);
|
|
211
|
+
return q;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* §15.2 — één HMAC-call die het `trade-item`-schema én alle voor het
|
|
215
|
+
* "Nieuw artikel"-formulier benodigde code-lists meelevert. Vervangt een
|
|
216
|
+
* losse `useFloridaySchema("trade-item")` + meerdere `useCodeList(...)`
|
|
217
|
+
* round-trips bij wizard-open.
|
|
218
|
+
*
|
|
219
|
+
* Fail-closed: gooit als de gateway geen `ok: true` teruggeeft.
|
|
220
|
+
*/
|
|
221
|
+
const TRADE_ITEM_INCLUDE_CODE_LISTS = [
|
|
222
|
+
"vbn-product-group",
|
|
223
|
+
"vbn-product-code",
|
|
224
|
+
"vbn-characteristic",
|
|
225
|
+
"vbn-characteristic-value",
|
|
226
|
+
"characteristic",
|
|
227
|
+
"packaging-type",
|
|
228
|
+
"country-of-origin",
|
|
229
|
+
"length-unit",
|
|
230
|
+
];
|
|
231
|
+
export function useTradeItemFormSchema() {
|
|
232
|
+
const envKey = useEnvKey();
|
|
233
|
+
const q = useQuery({
|
|
234
|
+
queryKey: ["floriday-trade-item-schema", envKey],
|
|
235
|
+
queryFn: async () => {
|
|
236
|
+
const raw = await gatewaySchemaFn({
|
|
237
|
+
data: {
|
|
238
|
+
resource: "trade-item",
|
|
239
|
+
environment: envKey === "live" ? "live" : "staging",
|
|
240
|
+
includeCodeLists: [...TRADE_ITEM_INCLUDE_CODE_LISTS],
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
const res = normalizeSchemaResponse(raw);
|
|
244
|
+
if (!res || res.ok !== true) {
|
|
245
|
+
throw new Error(res?.error ??
|
|
246
|
+
"Floriday trade-item schema niet beschikbaar (gateway gaf geen ok=true terug)");
|
|
247
|
+
}
|
|
248
|
+
const vbnList = res.codeLists?.["vbn-product-group"] ?? [];
|
|
249
|
+
if (vbnList.length === 0) {
|
|
250
|
+
throw new Error("Floriday schema-call is incompleet: codeLists['vbn-product-group'] ontbreekt. Daardoor kunnen VBN-specifieke karakteristieken niet betrouwbaar worden bepaald.");
|
|
251
|
+
}
|
|
252
|
+
return res;
|
|
253
|
+
},
|
|
254
|
+
staleTime: 60 * 60 * 1000,
|
|
255
|
+
});
|
|
256
|
+
useEffect(() => {
|
|
257
|
+
if (!q.data?.requiredFields)
|
|
258
|
+
return;
|
|
259
|
+
const missing = unmappedRequiredFields(q.data.requiredFields);
|
|
260
|
+
if (missing.length && import.meta.env.DEV) {
|
|
261
|
+
console.warn(`[floriday-schema] trade-item: required fields zonder step-mapping:`, missing);
|
|
262
|
+
}
|
|
263
|
+
}, [q.data?.requiredFields]);
|
|
264
|
+
return q;
|
|
265
|
+
}
|
|
266
|
+
export function useCodeList(listName) {
|
|
267
|
+
const envKey = useEnvKey();
|
|
268
|
+
return useQuery({
|
|
269
|
+
queryKey: ["floriday-code-list", listName ?? "", envKey],
|
|
270
|
+
queryFn: async () => (await gatewayCodeListFn({ data: { listName: listName } })),
|
|
271
|
+
staleTime: 60 * 60 * 1000,
|
|
272
|
+
enabled: Boolean(listName),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
export function useCachedList(entity, limit = 1000) {
|
|
276
|
+
const envKey = useEnvKey();
|
|
277
|
+
return useQuery({
|
|
278
|
+
queryKey: ["floriday-cached-list", entity ?? "", limit, envKey],
|
|
279
|
+
queryFn: async () => (await gatewayCachedListFn({ data: { entity: entity, limit } })),
|
|
280
|
+
staleTime: 5 * 60 * 1000,
|
|
281
|
+
enabled: Boolean(entity),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Invalideert alle floriday-* queries wanneer de actieve connectie
|
|
286
|
+
* (en dus mogelijk de environment) wijzigt. Voorkomt cache-bleed
|
|
287
|
+
* tussen staging en live bij een toekomstige switcher.
|
|
288
|
+
*/
|
|
289
|
+
export function useInvalidateFloridayOnConnectionChange() {
|
|
290
|
+
const { activeId, environment } = useFloridayConnection();
|
|
291
|
+
const qc = useQueryClient();
|
|
292
|
+
useEffect(() => {
|
|
293
|
+
qc.invalidateQueries({ queryKey: ["floriday-cached-list"] });
|
|
294
|
+
qc.invalidateQueries({ queryKey: ["floriday-code-list"] });
|
|
295
|
+
qc.invalidateQueries({ queryKey: ["floriday-schema"] });
|
|
296
|
+
qc.invalidateQueries({ queryKey: ["floriday-trade-item-schema"] });
|
|
297
|
+
}, [activeId, environment, qc]);
|
|
298
|
+
}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { WizardData } from "../lib/floriday-payload";
|
|
2
|
-
import type { TradeItem } from "../lib/floriday-client";
|
|
2
|
+
import type { FloridayLinkStatus, TradeItem } from "../lib/floriday-client";
|
|
3
3
|
export interface LocalTradeItemRow {
|
|
4
4
|
id: string;
|
|
5
5
|
connection_id: string | null;
|
|
6
6
|
data: WizardData;
|
|
7
7
|
updated_at: string;
|
|
8
8
|
created_at: string;
|
|
9
|
+
floriday_link_status?: FloridayLinkStatus;
|
|
10
|
+
floriday_id?: string | null;
|
|
11
|
+
floriday_link_error?: string | null;
|
|
12
|
+
missing_required_fields?: string[] | null;
|
|
13
|
+
last_floriday_sync_at?: string | null;
|
|
14
|
+
source?: string | null;
|
|
9
15
|
}
|
|
10
16
|
export declare function useLocalTradeItems(connectionId: string | null): {
|
|
11
17
|
items: TradeItem[];
|
|
@@ -13,10 +19,20 @@ export declare function useLocalTradeItems(connectionId: string | null): {
|
|
|
13
19
|
reload: () => Promise<void>;
|
|
14
20
|
};
|
|
15
21
|
export declare function getLocalTradeItem(id: string): Promise<LocalTradeItemRow | null>;
|
|
22
|
+
export interface DraftMeta {
|
|
23
|
+
floridayLinkStatus?: FloridayLinkStatus;
|
|
24
|
+
floridayId?: string | null;
|
|
25
|
+
floridayLinkError?: string | null;
|
|
26
|
+
missingRequiredFields?: string[];
|
|
27
|
+
lastFloridaySyncAt?: string | null;
|
|
28
|
+
source?: "manual" | "excel_import";
|
|
29
|
+
}
|
|
16
30
|
export declare function upsertLocalTradeItem(params: {
|
|
17
31
|
id?: string;
|
|
18
32
|
connectionId: string;
|
|
19
33
|
data: WizardData;
|
|
34
|
+
meta?: DraftMeta;
|
|
20
35
|
}): Promise<string>;
|
|
36
|
+
export declare function updateDraftMeta(id: string, meta: DraftMeta): Promise<void>;
|
|
21
37
|
export declare function deleteLocalTradeItem(id: string): Promise<void>;
|
|
22
38
|
//# sourceMappingURL=useLocalTradeItems.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLocalTradeItems.d.ts","sourceRoot":"","sources":["../../src/hooks/useLocalTradeItems.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"useLocalTradeItems.d.ts","sourceRoot":"","sources":["../../src/hooks/useLocalTradeItems.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAE5E,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uBAAuB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAgCD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;EA+B7D;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAQrF;AAED,MAAM,WAAW,SAAS;IACxB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,CAAC;CACpC;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2ClB;AAED,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhF;AAED,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE"}
|