@flowselections/floriday-voorraad 1.0.163 → 1.0.165
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/fs-ui/DataTable.d.ts.map +1 -1
- package/dist-lib/components/fs-ui/DataTable.js +2 -2
- package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadPage.js +86 -6
- package/dist-lib/components/voorraad/artikel/ArtikelPagina.d.ts.map +1 -1
- package/dist-lib/components/voorraad/artikel/ArtikelPagina.js +10 -2
- package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.d.ts +3 -1
- package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.d.ts.map +1 -1
- package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.js +5 -2
- package/dist-lib/hooks/useVoorraadLijst.d.ts +4 -5
- package/dist-lib/hooks/useVoorraadLijst.d.ts.map +1 -1
- package/dist-lib/hooks/useVoorraadLijst.js +23 -5
- package/dist-lib/hooks-entry.d.ts +1 -0
- package/dist-lib/hooks-entry.d.ts.map +1 -1
- package/dist-lib/hooks-entry.js +1 -0
- package/dist-lib/integrations/supabase/types.d.ts +537 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/lijst-stand.d.ts +31 -0
- package/dist-lib/lib/lijst-stand.d.ts.map +1 -0
- package/dist-lib/lib/lijst-stand.js +77 -0
- package/dist-lib/lib/voorraad-push-melding.d.ts +10 -0
- package/dist-lib/lib/voorraad-push-melding.d.ts.map +1 -0
- package/dist-lib/lib/voorraad-push-melding.js +11 -0
- package/dist-lib/server-hooks/floriday-mutaties.d.ts +3 -0
- package/dist-lib/server-hooks/floriday-mutaties.d.ts.map +1 -0
- package/dist-lib/server-hooks/floriday-mutaties.js +70 -0
- package/dist-lib/server-hooks/guard.d.ts.map +1 -1
- package/dist-lib/server-hooks/guard.js +1 -1
- package/package.json +22 -1
- package/sql/AGENTS.md +2 -0
- package/sql/floriday-voorraad-schema.sql +1454 -902
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/DataTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKpE,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,CAAC;IAClB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAC3B,OAAO,EACP,IAAI,EACJ,KAAK,EACL,OAAO,EACP,IAAI,EACJ,MAAM,EACN,MAAM,EACN,SAAoB,EACpB,SAAS,EACT,KAAK,EACL,UAAU,EACV,UAAU,EACV,YAAgB,EAChB,QAAe,GAChB,EAAE;IACD,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACzB,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACrC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;KAAE,CAAC;IACrI,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,+
|
|
1
|
+
{"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/fs-ui/DataTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKpE,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,CAAC;IAClB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAC3B,OAAO,EACP,IAAI,EACJ,KAAK,EACL,OAAO,EACP,IAAI,EACJ,MAAM,EACN,MAAM,EACN,SAAoB,EACpB,SAAS,EACT,KAAK,EACL,UAAU,EACV,UAAU,EACV,YAAgB,EAChB,QAAe,GAChB,EAAE;IACD,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACzB,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACrC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;KAAE,CAAC;IACrI,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,+BAqJA"}
|
|
@@ -53,7 +53,7 @@ export function DataTable({ columns, rows, getId, loading, sort, onSort, onOpen,
|
|
|
53
53
|
const kolomBreedtes = [selection ? "36px" : undefined, ...columns.map((c) => c.width), onOpen || rowActions ? "96px" : undefined].filter((_, i, a) => i > 0 || a[0] !== undefined);
|
|
54
54
|
const leeg = !loading && rows.length === 0;
|
|
55
55
|
const eersteLaad = loading && rows.length === 0;
|
|
56
|
-
return (_jsxs("div", { className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm", children: [(_jsxs("ul", { className: "divide-y divide-border md:hidden", children: [eersteLaad && Array.from({ length: 5 }).map((_, i) => (_jsxs("li", { className: "space-y-2 p-4", "aria-hidden": true, children: [_jsx("div", { className: "h-4 w-2/3 animate-pulse rounded bg-muted" }), _jsx("div", { className: "h-3 w-1/2 animate-pulse rounded bg-muted" })] }, i))), rows.map((r) => (_jsx("li", { className: "transition-opacity duration-150 " + (loading ? "opacity-60" : ""), children: _jsx("div", { role: onOpen ? "button" : undefined, tabIndex: onOpen ? 0 : undefined, onClick: () => onOpen?.(r), onKeyDown: (e) => { if (e.key === "Enter" && onOpen)
|
|
56
|
+
return (_jsxs("div", { className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm", children: [(_jsxs("ul", { className: "divide-y divide-border md:hidden", children: [eersteLaad && Array.from({ length: 5 }).map((_, i) => (_jsxs("li", { className: "space-y-2 p-4", "aria-hidden": true, children: [_jsx("div", { className: "h-4 w-2/3 animate-pulse rounded bg-muted" }), _jsx("div", { className: "h-3 w-1/2 animate-pulse rounded bg-muted" })] }, i))), rows.map((r) => (_jsx("li", { "data-id": getId(r), className: "transition-opacity duration-150 " + (loading ? "opacity-60" : ""), children: _jsx("div", { role: onOpen ? "button" : undefined, tabIndex: onOpen ? 0 : undefined, onClick: () => onOpen?.(r), onKeyDown: (e) => { if (e.key === "Enter" && onOpen)
|
|
57
57
|
onOpen(r); }, className: "block min-h-11 p-4 active:bg-muted/60", children: mobileCard ? mobileCard(r) : (_jsx("div", { className: "space-y-1", children: columns.map((c, ci) => (_jsxs("div", { className: ci === 0 ? "min-w-0 text-sm font-medium" : "flex min-w-0 items-baseline justify-between gap-3 text-xs", children: [ci > 0 && _jsx("span", { className: "shrink-0 text-muted-foreground", children: c.header }), _jsx("div", { className: "min-w-0 truncate", children: c.render(r) })] }, c.key))) })) }) }, getId(r)))), leeg && _jsx("li", { children: empty })] })), _jsx("div", { className: "hidden max-h-[calc(100dvh-7rem)] overflow-auto md:block xl:max-h-none xl:overflow-visible", children: _jsxs("table", { className: "w-full [&_thead_th]:h-10 [&_thead_th]:text-[11px] [&_thead_th]:font-semibold [&_thead_th]:uppercase [&_thead_th]:tracking-wide [&_thead_th]:text-muted-foreground min-w-[900px] table-fixed caption-bottom text-sm [&_thead_th]:sticky [&_thead_th]:top-0 [&_thead_th]:z-10 [&_thead_th]:bg-card [&_tbody_tr]:transition-colors", children: [_jsxs("colgroup", { children: [selection && _jsx("col", { style: { width: "36px" } }), columns.map((c) => _jsx("col", { style: c.width ? { width: c.width } : undefined }, c.key)), (onOpen || rowActions) && _jsx("col", { style: { width: "96px" } })] }), _jsx("thead", { children: _jsxs("tr", { className: "border-b border-border", children: [selection && (_jsx("th", { className: "px-2 text-left align-middle", children: _jsx("input", { type: "checkbox", className: "h-4 w-4 rounded accent-primary", checked: allesGekozen, onChange: () => selection.onToggleAll(ids), "aria-label": "Alles op deze pagina kiezen" }) })), columns.map((c) => {
|
|
58
58
|
const act = sort && c.sortKey && sort.key === c.sortKey;
|
|
59
59
|
return (_jsx("th", { scope: "col", className: "px-2 text-left align-middle", "aria-sort": act ? (sort.asc ? "ascending" : "descending") : c.sortKey ? "none" : undefined, children: c.sortKey && onSort ? (_jsxs("button", { type: "button", onClick: () => onSort(c.sortKey), className: "inline-flex items-center gap-1 uppercase tracking-wide hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm " + (act ? "text-foreground" : ""), children: [c.header, act && (sort.asc ? _jsx(ArrowUp, { className: "h-3 w-3" }) : _jsx(ArrowDown, { className: "h-3 w-3" }))] })) : c.header }, c.key));
|
|
@@ -61,7 +61,7 @@ export function DataTable({ columns, rows, getId, loading, sort, onSort, onOpen,
|
|
|
61
61
|
const id = getId(r);
|
|
62
62
|
const isActief = i === actief;
|
|
63
63
|
const gekozen = selection?.selected.has(id);
|
|
64
|
-
return (_jsxs("tr", { "data-rij": i, onClick: () => setActief(i), onDoubleClick: () => onOpen?.(r), className: "group h-[60px] border-b border-border transition-colors duration-150 last:border-0 hover:bg-muted/40 motion-reduce:transition-none " +
|
|
64
|
+
return (_jsxs("tr", { "data-rij": i, "data-id": id, onClick: () => setActief(i), onDoubleClick: () => onOpen?.(r), className: "group h-[60px] border-b border-border transition-colors duration-150 last:border-0 hover:bg-muted/40 motion-reduce:transition-none " +
|
|
65
65
|
(isActief ? "bg-muted/60 " : "") +
|
|
66
66
|
(loading ? "opacity-60" : ""), children: [selection && (_jsxs("td", { className: "relative px-2 py-0 align-middle", onClick: (e) => e.stopPropagation(), children: [(gekozen || isActief) && _jsx("span", { "aria-hidden": true, className: "absolute inset-y-0 left-0 w-[3px] " + (gekozen ? "bg-primary" : "bg-primary/40") }), _jsx("input", { type: "checkbox", className: "h-4 w-4 rounded accent-primary", checked: !!gekozen, onChange: () => selection.onToggle(id), "aria-label": `Kies ${selection.label(r)}` })] })), columns.map((c) => _jsx("td", { className: "truncate px-2 py-0 align-middle " + (c.className ?? ""), children: c.render(r) }, c.key)), (onOpen || rowActions) && (_jsx("td", { className: "px-2 py-0 align-middle", onClick: (e) => e.stopPropagation(), children: _jsxs("div", { className: "flex items-center justify-end gap-1", children: [rowActions?.(r), onOpen && (_jsx("button", { type: "button", onClick: () => onOpen(r), "aria-label": openLabel, title: openLabel, className: "inline-flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground transition-opacity duration-150 hover:bg-muted hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring " + (isActief ? "opacity-100" : "opacity-0 group-hover:opacity-100"), children: _jsx(ChevronRight, { className: "h-4 w-4" }) }))] }) }))] }, id));
|
|
67
67
|
}), leeg && (_jsx("tr", { className: "hover:bg-transparent", children: _jsx("td", { colSpan: columns.length + (selection ? 1 : 0) + (onOpen || rowActions ? 1 : 0), children: empty }) }))] })] }) })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AA6EA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAsDnD,wBAAgB,YAAY,gCA8Q3B"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { TwijfelKiezen } from "./artikel/TwijfelKiezen.js";
|
|
3
|
-
import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from "react";
|
|
4
|
-
import { useNavigate } from "@tanstack/react-router";
|
|
3
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { useNavigate, useRouter, useRouterState } from "@tanstack/react-router";
|
|
5
|
+
import { begrensPagina, geldigeLijstStand, leesScroll, maakLijstStand, zetScroll } from "../../lib/lijst-stand.js";
|
|
5
6
|
import { Button, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@flowselections/core";
|
|
6
7
|
import { Archive, ArrowDownToLine, ClipboardCheck, Columns3, Euro, HelpCircle, Layers, Link2Off, ListChecks, MoreHorizontal, Package, PackageSearch, PackageX, Plus, Send, TrendingDown, } from "lucide-react";
|
|
7
8
|
import { supabase } from "../../integrations/supabase/client.js";
|
|
@@ -10,6 +11,7 @@ import { useFloridayConnection } from "../../hooks/useFloridayConnection.js";
|
|
|
10
11
|
import { useEnsureVoorraadDefaults } from "../../hooks/useEnsureVoorraadDefaults.js";
|
|
11
12
|
import { useVoorraadLijst } from "../../hooks/useVoorraadLijst.js";
|
|
12
13
|
import { aantal, FILTER_LABEL, FILTER_HINT, meldingen, volgendeSortering, zichtbareFilters, } from "../../lib/voorraad-lijst.js";
|
|
14
|
+
import { pushMeldingen } from "../../lib/voorraad-push-melding.js";
|
|
13
15
|
import { floridayConnectionNotice } from "./FloridayConnectionNotice.js";
|
|
14
16
|
import { useStockIntegrityNotices } from "./StockIntegrityAlert.js";
|
|
15
17
|
import { TelmomentButton } from "./TelmomentButton.js";
|
|
@@ -108,14 +110,91 @@ export function VoorraadPage() {
|
|
|
108
110
|
const [afboeken, setAfboeken] = useState(null);
|
|
109
111
|
const { kolommen, toggle: toggleKolom } = useKolommen();
|
|
110
112
|
const guardTrips = useSyncExternalStore(pageRequestGuard.subscribe, () => pageRequestGuard.trips(), () => EMPTY_TRIPS);
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
+
// Scrollherstel: stand staat op de stap in de browsergeschiedenis (alleen bij terugkomen van een artikel).
|
|
114
|
+
const router = useRouter();
|
|
115
|
+
const userId = (router.options.context?.auth?.user?.id) ?? null;
|
|
116
|
+
const historieStand = useRouterState({ select: (s) => s.location.state?.lijstHerstel });
|
|
117
|
+
const herstelRef = useRef(null);
|
|
118
|
+
const overslaanReset = useRef(false);
|
|
119
|
+
const lijstAnker = useRef(null);
|
|
120
|
+
const [klaar, setKlaar] = useState(false);
|
|
121
|
+
useLayoutEffect(() => {
|
|
122
|
+
const s = geldigeLijstStand(historieStand, userId, Date.now());
|
|
123
|
+
if (s) {
|
|
124
|
+
herstelRef.current = s;
|
|
125
|
+
overslaanReset.current = true;
|
|
126
|
+
setZoek(s.zoek);
|
|
127
|
+
setFilter(s.filter);
|
|
128
|
+
setSorteer({ sort: s.sort, oplopend: s.oplopend });
|
|
129
|
+
setPagina(s.pagina);
|
|
130
|
+
setGrootte(s.grootte);
|
|
131
|
+
}
|
|
132
|
+
setKlaar(true);
|
|
133
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
134
|
+
// Nieuwe zoekopdracht, filter of sortering begint op pagina 1 (niet bij het terugzetten van de bewaarde stand).
|
|
135
|
+
useEffect(() => { if (!overslaanReset.current)
|
|
136
|
+
setPagina(1); }, [zoek, filter, sorteer, grootte]);
|
|
137
|
+
useEffect(() => { if (klaar)
|
|
138
|
+
overslaanReset.current = false; }, [klaar]);
|
|
113
139
|
const nieuw = useCallback(() => navigate({ to: "/voorraad/nieuw" }), [navigate]);
|
|
114
140
|
const vraag = { zoek, filter, sort: sorteer.sort, oplopend: sorteer.oplopend, pagina, grootte };
|
|
115
|
-
const { data, kpi, loading, error, reload } = useVoorraadLijst(vraag);
|
|
141
|
+
const { data, kpi, loading, error, reload } = useVoorraadLijst(vraag, { userId, klaar });
|
|
142
|
+
const voorOpenen = useCallback((r) => {
|
|
143
|
+
if (!userId)
|
|
144
|
+
return;
|
|
145
|
+
const stand = maakLijstStand({ userId, ts: Date.now(), zoek, filter, sort: sorteer.sort, oplopend: sorteer.oplopend, pagina, grootte, scrollTop: leesScroll(lijstAnker.current), artikelId: r.id });
|
|
146
|
+
try {
|
|
147
|
+
window.history.replaceState({ ...(window.history.state ?? {}), lijstHerstel: stand }, "");
|
|
148
|
+
}
|
|
149
|
+
catch (e) {
|
|
150
|
+
console.warn("Lijststand niet bewaard; terugkomen begint bovenaan", e);
|
|
151
|
+
}
|
|
152
|
+
}, [userId, zoek, filter, sorteer, pagina, grootte]);
|
|
153
|
+
// Eerst de pagina begrenzen, dan de hoogte, dan zo nodig het artikel in beeld.
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
const s = herstelRef.current;
|
|
156
|
+
if (!s || !klaar || !data || loading && !data.rijen?.length)
|
|
157
|
+
return;
|
|
158
|
+
const p = begrensPagina(pagina, data.totaal ?? 0, grootte);
|
|
159
|
+
if (p !== pagina) {
|
|
160
|
+
setPagina(p);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
herstelRef.current = null;
|
|
164
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
165
|
+
zetScroll(lijstAnker.current, s.scrollTop);
|
|
166
|
+
if (!s.artikelId)
|
|
167
|
+
return;
|
|
168
|
+
const el = Array.from(document.querySelectorAll(`[data-id="${CSS.escape(s.artikelId)}"]`)).find((n) => n.offsetParent !== null);
|
|
169
|
+
if (!el)
|
|
170
|
+
return;
|
|
171
|
+
el.scrollIntoView({ block: "nearest" });
|
|
172
|
+
el.classList.add("bg-primary/10");
|
|
173
|
+
window.setTimeout(() => el.classList.remove("bg-primary/10"), 1500);
|
|
174
|
+
}));
|
|
175
|
+
}, [data, klaar, loading, pagina, grootte]);
|
|
116
176
|
const heeftKoppeling = data?.heeft_koppeling ?? false;
|
|
117
177
|
const filters = useMemo(() => zichtbareFilters(heeftKoppeling), [heeftKoppeling]);
|
|
118
178
|
const melding = data ? meldingen(data) : [];
|
|
179
|
+
// Floriday-leidend: push stilgevallen (> 30 min) of mislukte eigen verkopen; alleen met koppeling.
|
|
180
|
+
const [pushTeksten, setPushTeksten] = useState([]);
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (!heeftKoppeling) {
|
|
183
|
+
setPushTeksten([]);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
let actief = true;
|
|
187
|
+
void (async () => {
|
|
188
|
+
const { data: st, error: stErr } = await supabase.rpc("voorraad_integriteit_status");
|
|
189
|
+
if (stErr) {
|
|
190
|
+
console.error("Voorraadcontrole-status laden mislukt:", stErr.message);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (actief)
|
|
194
|
+
setPushTeksten(pushMeldingen(st?.push));
|
|
195
|
+
})();
|
|
196
|
+
return () => { actief = false; };
|
|
197
|
+
}, [heeftKoppeling, data]);
|
|
119
198
|
// Twijfelgevallen bestaan alleen bij een koppeling; tonen als er iets te kiezen is of als je er al staat.
|
|
120
199
|
const tabs = filters
|
|
121
200
|
.filter((f) => f !== "twijfel" || heeftKoppeling || (data?.tellers?.twijfel ?? 0) > 0 || filter === "twijfel")
|
|
@@ -137,6 +216,7 @@ export function VoorraadPage() {
|
|
|
137
216
|
...(guardTrips.length > 0 ? [_jsxs("span", { children: ["De pagina is gestopt met laden. ", _jsx("span", { role: "button", tabIndex: 0, className: "font-medium underline underline-offset-2", onClick: () => window.location.reload(), children: "Opnieuw laden" })] }, "guard")] : []),
|
|
138
217
|
...(error ? [_jsxs("span", { children: ["De voorraad laden lukt niet. ", _jsx("span", { role: "button", tabIndex: 0, className: "font-medium underline underline-offset-2", onClick: (e) => { e.stopPropagation(); void reload(); }, children: "Opnieuw proberen" })] }, "err")] : []),
|
|
139
218
|
...integriteit.items,
|
|
219
|
+
...pushTeksten.map((t) => _jsx("span", { children: t }, t)),
|
|
140
220
|
...(verbindingTekst ? [verbindingTekst] : []),
|
|
141
221
|
...melding.map((m) => m.actie === "telmoment" ? (_jsxs("span", { className: "inline-flex min-w-0 max-w-full items-center gap-2", children: [_jsx("span", { className: "truncate", children: m.tekst }), _jsx("span", { role: "button", tabIndex: 0, className: "shrink-0 font-medium underline underline-offset-2", onClick: (e) => { e.stopPropagation(); setTelmomentOpen(true); }, onKeyDown: (e) => { if (e.key === "Enter") {
|
|
142
222
|
e.stopPropagation();
|
|
@@ -144,7 +224,7 @@ export function VoorraadPage() {
|
|
|
144
224
|
} }, children: "Telmoment instellen" })] }, m.tekst)) : m.filter ? (_jsx("span", { role: "button", tabIndex: 0, className: "underline-offset-2 hover:underline", onClick: (e) => { e.stopPropagation(); setFilter(m.filter); }, children: m.tekst }, m.tekst)) : m.tekst),
|
|
145
225
|
];
|
|
146
226
|
const leeg = zoek || filter !== "alles" ? (_jsx(EmptyState, { icon: _jsx(PackageSearch, { className: "h-6 w-6" }), title: "Niets gevonden", text: zoek ? `Geen artikelen voor “${zoek}”${filter !== "alles" ? ` in ${FILTER_HINT[filter].toLowerCase()}` : ""}.` : "Geen artikelen in deze weergave.", action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => { setZoek(""); setFilter("alles"); }, children: "Filters wissen" }) })) : (_jsx(EmptyState, { icon: _jsx(Package, { className: "h-6 w-6" }), title: "Nog geen artikelen", text: "Maak je eerste artikel aan of importeer een lijst.", action: _jsxs(Button, { size: "sm", onClick: nieuw, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Nieuw artikel"] }) }));
|
|
147
|
-
return (_jsxs("main", { className: "flex w-full min-w-0 flex-col gap-4 overflow-x-clip p-4 pb-[calc(7rem+env(safe-area-inset-bottom))] sm:p-6 sm:pb-24", children: [_jsx(Sneltoetsen, { onNieuw: nieuw }), _jsx(PageHeader, { title: "Voorraad", updated: _jsx(UpdatedAt, { at: data?.bijgewerkt ?? null }), actions: _jsxs(_Fragment, { children: [_jsx(ImporteerKnop, { connectionId: conn.activeId ?? null, onImported: reload }), _jsx(LijstExportKnop, { vraag: { zoek, filter, sort: sorteer.sort, oplopend: sorteer.oplopend } }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-10 w-10 p-0 sm:h-9 sm:w-auto sm:px-3", "aria-label": "Meer acties", children: [_jsx(MoreHorizontal, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Meer" })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsxs(DropdownMenuItem, { onSelect: () => setTelmomentOpen(true), children: [_jsx(ClipboardCheck, { className: "mr-2 h-4 w-4" }), "Telmoment vastleggen"] }), heeftKoppeling && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: "/voorraad/validatie" }), children: [_jsx(ListChecks, { className: "mr-2 h-4 w-4" }), "Controle koppeling"] }), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: "/voorraad/publicaties" }), children: [_jsx(Send, { className: "mr-2 h-4 w-4" }), "Verzonden naar Floriday"] })] }))] })] }), _jsx(HeaderPrimary, { icon: _jsx(Plus, {}), label: "Nieuw artikel", kbd: "N", onClick: nieuw })] }) }), _jsx(TelmomentButton, { verbergKnop: true, open: telmomentOpen, onOpenChange: setTelmomentOpen, onSaved: reload }), _jsx(NoticeBar, { items: noticeItems }), integriteit.dialog, _jsxs(KpiRow, { children: [_jsx(KpiTile, { title: "Artikelen", icon: _jsx(Package, {}), loading: kpiLaden, value: aantal(kpi?.artikelen ?? 0), sub: "Actief, zonder gearchiveerd", onClick: () => setFilter("alles"), active: false }), _jsx(KpiTile, { title: "Onder minimum", icon: _jsx(TrendingDown, {}), tone: (kpi?.onder_minimum ?? 0) > 0 ? "warning" : "default", loading: kpiLaden, value: aantal(kpi?.onder_minimum ?? 0), sub: (kpi?.onder_minimum ?? 0) > 0 ? _jsx("span", { className: "text-destructive", children: "Bijbestellen of bijmaken" }) : "Alles boven het minimum", onClick: () => setFilter("onder_minimum"), active: filter === "onder_minimum" }), _jsx(KpiTile, { title: "Vrij beschikbaar", icon: _jsx(Layers, {}), loading: kpiLaden, value: aantal(kpi?.vrij ?? 0), sub: "Stuks, losse artikelen" }), _jsx(KpiTile, { title: "Inkomend", icon: _jsx(ArrowDownToLine, {}), loading: kpiLaden, value: aantal(kpi?.inkomend ?? 0), sub: "Stuks verwacht" })] }), _jsx(PillTabs, { tabs: tabs, value: filter, onChange: setFilter, label: "Filter" }), _jsx(Toolbar, { filters: _jsx(FiltersButton, { count: filter !== "alles" ? 1 : 0, onClick: () => setFilterOpen(true) }), chips: _jsx(FilterChips, { chips: filter !== "alles" ? [{ key: "weergave", label: FILTER_HINT[filter], icon: FILTER_ICON[filter], onRemove: () => setFilter("alles") }] : [] }), right: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-9 px-3", "aria-label": "Kolommen kiezen", children: [_jsx(Columns3, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Kolommen" })] }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuLabel, { children: "Kolommen kiezen" }), OPTIONELE_KOLOMMEN.map((c) => (_jsx(DropdownMenuCheckboxItem, { checked: kolommen.has(c.key), onCheckedChange: () => toggleKolom(c.key), children: c.label }, c.key)))] })] }), children: _jsx(SearchInput, { value: zoek, onChange: setZoek, placeholder: "Zoek op naam, artikelnummer of barcode" }) }), selectieBalk && (_jsxs("div", { className: "sticky top-2 z-20 flex flex-wrap items-center gap-2 rounded-lg border border-border bg-card px-4 py-2 text-sm shadow-lg", children: [_jsxs("span", { className: "font-medium tabular-nums", children: [selected.size, " gekozen"] }), _jsx(Button, { size: "sm", className: "h-8", onClick: () => setDrawerOpen(true), children: "Voorraadsturing instellen" }), _jsx(Button, { size: "sm", variant: "ghost", className: "h-8", onClick: () => setSelected(new Set()), children: "Keuze wissen" })] })), filter === "twijfel" ? (_jsx(TwijfelTabel, { rijen: data?.twijfel_rijen ?? [], loading: loading, onGekozen: () => void reload() })) : (_jsx(VoorraadLijstTabel, { rijen: data?.rijen ?? [], loading: loading, sort: sorteer.sort, oplopend: sorteer.oplopend, onSort: (k) => setSorteer((cur) => volgendeSortering(cur, k)), kolommen: kolommen, selected: selected, onToggleSelect: toggleSelect, onToggleAll: toggleAll, onAanpassen: setAanpassen, onAfboeken: setAfboeken, heeftKoppeling: heeftKoppeling, leeg: leeg })), _jsx(Pagination, { totalCount: data?.totaal ?? 0, page: pagina, pageSize: grootte, onPage: setPagina, onPageSize: setGrootte }), _jsx(FilterPanel, { open: filterOpen, onOpenChange: setFilterOpen, onClear: () => setFilter("alles"), children: _jsx(FilterGroup, { title: "Weergave", value: filter, onChange: setFilter, options: tabs.map((t) => ({ value: t.value, label: FILTER_HINT[t.value] })) }) }), _jsx(AanpassenDialog, { rij: aanpassen, onClose: () => setAanpassen(null), onDone: reload }), _jsx(AfboekenDialog, { rij: afboeken, connectionId: stockConnId, onClose: () => setAfboeken(null), onDone: reload }), _jsx(InventorySettingsDrawer, { open: drawerOpen, onOpenChange: setDrawerOpen, connectionId: conn.activeId ?? null, productIds: [...selected], onSaved: reload }), _jsx(MobilePrimaryAction, { onClick: nieuw, hidden: selectieBalk, icon: _jsx(Plus, {}), children: "Nieuw artikel" })] }));
|
|
227
|
+
return (_jsxs("main", { className: "flex w-full min-w-0 flex-col gap-4 overflow-x-clip p-4 pb-[calc(7rem+env(safe-area-inset-bottom))] sm:p-6 sm:pb-24", children: [_jsx(Sneltoetsen, { onNieuw: nieuw }), _jsx(PageHeader, { title: "Voorraad", updated: _jsx(UpdatedAt, { at: data?.bijgewerkt ?? null }), actions: _jsxs(_Fragment, { children: [_jsx(ImporteerKnop, { connectionId: conn.activeId ?? null, onImported: reload }), _jsx(LijstExportKnop, { vraag: { zoek, filter, sort: sorteer.sort, oplopend: sorteer.oplopend } }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-10 w-10 p-0 sm:h-9 sm:w-auto sm:px-3", "aria-label": "Meer acties", children: [_jsx(MoreHorizontal, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Meer" })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsxs(DropdownMenuItem, { onSelect: () => setTelmomentOpen(true), children: [_jsx(ClipboardCheck, { className: "mr-2 h-4 w-4" }), "Telmoment vastleggen"] }), heeftKoppeling && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: "/voorraad/validatie" }), children: [_jsx(ListChecks, { className: "mr-2 h-4 w-4" }), "Controle koppeling"] }), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: "/voorraad/publicaties" }), children: [_jsx(Send, { className: "mr-2 h-4 w-4" }), "Verzonden naar Floriday"] })] }))] })] }), _jsx(HeaderPrimary, { icon: _jsx(Plus, {}), label: "Nieuw artikel", kbd: "N", onClick: nieuw })] }) }), _jsx(TelmomentButton, { verbergKnop: true, open: telmomentOpen, onOpenChange: setTelmomentOpen, onSaved: reload }), _jsx(NoticeBar, { items: noticeItems }), integriteit.dialog, _jsxs(KpiRow, { children: [_jsx(KpiTile, { title: "Artikelen", icon: _jsx(Package, {}), loading: kpiLaden, value: aantal(kpi?.artikelen ?? 0), sub: "Actief, zonder gearchiveerd", onClick: () => setFilter("alles"), active: false }), _jsx(KpiTile, { title: "Onder minimum", icon: _jsx(TrendingDown, {}), tone: (kpi?.onder_minimum ?? 0) > 0 ? "warning" : "default", loading: kpiLaden, value: aantal(kpi?.onder_minimum ?? 0), sub: (kpi?.onder_minimum ?? 0) > 0 ? _jsx("span", { className: "text-destructive", children: "Bijbestellen of bijmaken" }) : "Alles boven het minimum", onClick: () => setFilter("onder_minimum"), active: filter === "onder_minimum" }), _jsx(KpiTile, { title: "Vrij beschikbaar", icon: _jsx(Layers, {}), loading: kpiLaden, value: aantal(kpi?.vrij ?? 0), sub: "Stuks, losse artikelen" }), _jsx(KpiTile, { title: "Inkomend", icon: _jsx(ArrowDownToLine, {}), loading: kpiLaden, value: aantal(kpi?.inkomend ?? 0), sub: "Stuks verwacht" })] }), _jsx(PillTabs, { tabs: tabs, value: filter, onChange: setFilter, label: "Filter" }), _jsx(Toolbar, { filters: _jsx(FiltersButton, { count: filter !== "alles" ? 1 : 0, onClick: () => setFilterOpen(true) }), chips: _jsx(FilterChips, { chips: filter !== "alles" ? [{ key: "weergave", label: FILTER_HINT[filter], icon: FILTER_ICON[filter], onRemove: () => setFilter("alles") }] : [] }), right: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-9 px-3", "aria-label": "Kolommen kiezen", children: [_jsx(Columns3, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Kolommen" })] }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuLabel, { children: "Kolommen kiezen" }), OPTIONELE_KOLOMMEN.map((c) => (_jsx(DropdownMenuCheckboxItem, { checked: kolommen.has(c.key), onCheckedChange: () => toggleKolom(c.key), children: c.label }, c.key)))] })] }), children: _jsx(SearchInput, { value: zoek, onChange: setZoek, placeholder: "Zoek op naam, artikelnummer of barcode" }) }), selectieBalk && (_jsxs("div", { className: "sticky top-2 z-20 flex flex-wrap items-center gap-2 rounded-lg border border-border bg-card px-4 py-2 text-sm shadow-lg", children: [_jsxs("span", { className: "font-medium tabular-nums", children: [selected.size, " gekozen"] }), _jsx(Button, { size: "sm", className: "h-8", onClick: () => setDrawerOpen(true), children: "Voorraadsturing instellen" }), _jsx(Button, { size: "sm", variant: "ghost", className: "h-8", onClick: () => setSelected(new Set()), children: "Keuze wissen" })] })), filter === "twijfel" ? (_jsx(TwijfelTabel, { rijen: data?.twijfel_rijen ?? [], loading: loading, onGekozen: () => void reload() })) : (_jsx("div", { ref: lijstAnker, className: "contents", children: _jsx(VoorraadLijstTabel, { onVoorOpenen: voorOpenen, rijen: data?.rijen ?? [], loading: loading, sort: sorteer.sort, oplopend: sorteer.oplopend, onSort: (k) => setSorteer((cur) => volgendeSortering(cur, k)), kolommen: kolommen, selected: selected, onToggleSelect: toggleSelect, onToggleAll: toggleAll, onAanpassen: setAanpassen, onAfboeken: setAfboeken, heeftKoppeling: heeftKoppeling, leeg: leeg }) })), _jsx(Pagination, { totalCount: data?.totaal ?? 0, page: pagina, pageSize: grootte, onPage: setPagina, onPageSize: setGrootte }), _jsx(FilterPanel, { open: filterOpen, onOpenChange: setFilterOpen, onClear: () => setFilter("alles"), children: _jsx(FilterGroup, { title: "Weergave", value: filter, onChange: setFilter, options: tabs.map((t) => ({ value: t.value, label: FILTER_HINT[t.value] })) }) }), _jsx(AanpassenDialog, { rij: aanpassen, onClose: () => setAanpassen(null), onDone: reload }), _jsx(AfboekenDialog, { rij: afboeken, connectionId: stockConnId, onClose: () => setAfboeken(null), onDone: reload }), _jsx(InventorySettingsDrawer, { open: drawerOpen, onOpenChange: setDrawerOpen, connectionId: conn.activeId ?? null, productIds: [...selected], onSaved: reload }), _jsx(MobilePrimaryAction, { onClick: nieuw, hidden: selectieBalk, icon: _jsx(Plus, {}), children: "Nieuw artikel" })] }));
|
|
148
228
|
}
|
|
149
229
|
function TwijfelTabel({ rijen, loading, onGekozen }) {
|
|
150
230
|
const [open, setOpen] = useState(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArtikelPagina.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/artikel/ArtikelPagina.tsx"],"names":[],"mappings":"AAoGA,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,+
|
|
1
|
+
{"version":3,"file":"ArtikelPagina.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/artikel/ArtikelPagina.tsx"],"names":[],"mappings":"AAoGA,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,+BAyfnI"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { ArtikelFoto } from "../../fs-ui/ArtikelFoto.js";
|
|
4
|
-
import { Link, useBlocker, useRouterState } from "@tanstack/react-router";
|
|
4
|
+
import { Link, useBlocker, useRouter, useRouterState } from "@tanstack/react-router";
|
|
5
5
|
import { datum } from "../../../lib/notatie.js";
|
|
6
6
|
import { Button, Card, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, Input, Label, Skeleton, Tabs, TabsContent, toast, } from "@flowselections/core";
|
|
7
7
|
import { AlertTriangle, Archive, ArchiveRestore, ArrowDownToLine, ArrowLeft, Boxes, Layers, Link2, Loader2, Lock, MoreHorizontal, Minus, Package, Send, SlidersHorizontal } from "lucide-react";
|
|
@@ -301,6 +301,8 @@ export function ArtikelPagina({ id, resumeJobId, onNietGevonden }) {
|
|
|
301
301
|
await laad();
|
|
302
302
|
}
|
|
303
303
|
// Vanaf de controlepagina: open het overzicht vooraf (er wordt niets verstuurd zonder bevestiging).
|
|
304
|
+
const router = useRouter();
|
|
305
|
+
const vanLijst = useRouterState({ select: (st) => Boolean(st.location.state?.vanLijst) });
|
|
304
306
|
const vraagOverzicht = useRouterState({ select: (st) => Boolean(st.location.state?.stuurOverzicht) });
|
|
305
307
|
const overzichtGeopend = useRef(false);
|
|
306
308
|
useEffect(() => {
|
|
@@ -327,7 +329,13 @@ export function ArtikelPagina({ id, resumeJobId, onNietGevonden }) {
|
|
|
327
329
|
const rij = alsLijstRij(detail);
|
|
328
330
|
const opslaanUit = !vuil || opslaan || Boolean(prijsFout) || Boolean(aantalFout);
|
|
329
331
|
const gearchiveerd = Boolean(detail.gearchiveerd_at);
|
|
330
|
-
return (_jsxs("main", { className: "flex w-full min-w-0 flex-col gap-4 overflow-x-clip p-4 pb-[calc(7rem+env(safe-area-inset-bottom))] sm:p-6 sm:pb-24", children: [_jsx(PageHeader, { crumb: _jsxs(Link, { to: "/voorraad", className: "inline-flex items-center gap-1 hover:text-foreground",
|
|
332
|
+
return (_jsxs("main", { className: "flex w-full min-w-0 flex-col gap-4 overflow-x-clip p-4 pb-[calc(7rem+env(safe-area-inset-bottom))] sm:p-6 sm:pb-24", children: [_jsx(PageHeader, { crumb: _jsxs(Link, { to: "/voorraad", className: "inline-flex items-center gap-1 hover:text-foreground", onClick: (e) => {
|
|
333
|
+
// Rechtstreeks uit de lijst: terug in de geschiedenis, zodat de lijst op dezelfde plek terugkomt.
|
|
334
|
+
if (vanLijst && router.history.canGoBack() && !e.metaKey && !e.ctrlKey && !e.shiftKey) {
|
|
335
|
+
e.preventDefault();
|
|
336
|
+
router.history.back();
|
|
337
|
+
}
|
|
338
|
+
}, children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), " Voorraad"] }), media: _jsx("div", { className: "flex h-16 w-16 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-border bg-muted", children: _jsx(ArtikelFoto, { foto: detail.foto, reden: detail.foto_reden, alt: detail.naam, className: "h-full w-full", iconClassName: "h-7 w-7" }) }), title: detail.naam, updated: _jsx("span", { className: "block break-words", children: detail.artikelnummer ?? "Geen artikelnummer" }), meta: _jsxs(_Fragment, { children: [_jsx(ArtikelStatusIcoon, { status: status }), _jsx("span", { className: status === "ok" ? "text-muted-foreground" : "font-medium", children: info.label }), info.actie && info.tab && tabs.includes(info.tab) && (_jsx("button", { type: "button", className: "text-primary underline-offset-2 hover:underline", onClick: () => setTab(info.tab), children: info.actie })), _jsx("span", { className: "text-muted-foreground", children: "\u00B7" }), _jsxs("span", { className: "tabular-nums", children: [geld(detail.velden.sale_price === null ? null : Number(detail.velden.sale_price)), " per stuk"] }), detail.floriday_id && detail.heeft_koppeling && (_jsx(HoverTip, { label: "Gekoppeld met Floriday", content: "Gekoppeld met Floriday", className: "h-5 w-5 text-muted-foreground [&_svg]:h-3.5 [&_svg]:w-3.5", children: _jsx(Link2, {}) })), vuil && _jsx("span", { className: "text-xs font-medium text-warning", children: "Niet opgeslagen" })] }), actions: _jsxs(_Fragment, { children: [_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-10 w-10 p-0 sm:h-9 sm:w-auto sm:px-3", "aria-label": "Meer acties", children: [_jsx(MoreHorizontal, { className: "h-4 w-4 sm:mr-2" }), _jsx("span", { className: "hidden sm:inline", children: "Meer" })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsxs(DropdownMenuItem, { disabled: gearchiveerd, onSelect: () => setAanpassen(true), children: [_jsx(SlidersHorizontal, { className: "mr-2 h-4 w-4" }), "Voorraad aanpassen"] }), _jsxs(DropdownMenuItem, { disabled: gearchiveerd, onSelect: () => setAfboeken(true), children: [_jsx(Minus, { className: "mr-2 h-4 w-4" }), "Afboeken"] }), actie && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => { setFloridayOpen(true); setTab("floriday"); }, children: [_jsx(Send, { className: "mr-2 h-4 w-4" }), actie === "sturen" ? "Naar Floriday sturen" : "Op Floriday zetten"] })] })), _jsx(DropdownMenuSeparator, {}), gearchiveerd
|
|
331
339
|
? _jsxs(DropdownMenuItem, { onSelect: terugzetten, children: [_jsx(ArchiveRestore, { className: "mr-2 h-4 w-4" }), "Terugzetten in voorraad"] })
|
|
332
340
|
: _jsxs(DropdownMenuItem, { onSelect: () => { setArchiefKeuze("hier"); setArchief({}); }, children: [_jsx(Archive, { className: "mr-2 h-4 w-4" }), "Archiveren\u2026"] })] })] }), _jsxs(Button, { size: "sm", className: "hidden sm:inline-flex", onClick: doeOpslaan, disabled: opslaanUit, children: [opslaan && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Opslaan"] })] }) }), gearchiveerd && (detail.orders_gearchiveerd ?? 0) > 0 && (_jsxs(InlineAlert, { tone: "let_op", action: _jsx(Button, { size: "sm", variant: "outline", className: "h-8", onClick: terugzetten, children: "Terugzetten in voorraad" }), children: ["Dit artikel is gearchiveerd, maar er ", detail.orders_gearchiveerd === 1 ? "is 1 open orderregel" : `zijn ${detail.orders_gearchiveerd} open orderregels`, " binnengekomen. De orders zijn gewoon gekoppeld."] })), _jsxs(KpiRow, { children: [_jsx(KpiTile, { title: "Liggend", icon: _jsx(Package, {}), value: aantal(detail.liggend), sub: _jsxs(_Fragment, { children: ["Telmoment ", detail.telmoment ? datum(detail.telmoment) : _jsx("span", { className: "text-destructive", children: "ontbreekt" })] }) }), _jsx(KpiTile, { title: "Gereserveerd", icon: _jsx(Lock, {}), value: aantal(detail.gereserveerd), sub: "Voor open orders" }), _jsx(KpiTile, { title: "Vrij beschikbaar", icon: _jsx(Layers, {}), tone: rij.onder_minimum ? "warning" : "default", value: _jsx("span", { className: rij.onder_minimum ? "text-destructive" : "", children: aantal(detail.vrij) }), sub: detail.minimum > 0 ? (rij.onder_minimum ? _jsxs("span", { className: "text-destructive", children: ["Onder minimum (", aantal(detail.minimum), ")"] }) : `Minimum ${aantal(detail.minimum)}`) : "Geen minimum" }), _jsx(KpiTile, { title: "Inkomend", icon: _jsx(ArrowDownToLine, {}), value: aantal(detail.inkomend), sub: "Stuks verwacht" })] }), _jsx(OpslaanContext.Provider, { value: register, children: _jsxs(Tabs, { value: tab, onValueChange: setTab, children: [_jsx(PillTabs, { tabs: tabs.map((t) => ({ value: t, label: TAB_LABEL[t], icon: TAB_ICON[t] })), value: tab, onChange: setTab, label: "Onderdelen van het artikel" }), _jsxs(TabsContent, { value: "voorraad", forceMount: bezocht.has("voorraad") ? true : undefined, className: "mt-4 space-y-4 data-[state=inactive]:hidden", children: [_jsxs(Card, { className: "space-y-4 rounded-xl p-4 shadow-sm sm:p-5", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsx("h2", { className: "text-base font-semibold", children: "Artikelgegevens" }), detail.heeft_koppeling && _jsx("span", { className: "text-xs text-muted-foreground", children: "Opslaan bewaart alleen in je eigen administratie. Naar Floriday sturen doe je apart." })] }), _jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-5", children: ARTIKEL_VELDEN.map((k) => (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: `veld-${k}`, children: VELD_LABEL[k] }), _jsx(Input, { id: `veld-${k}`, className: "h-10 rounded-lg text-base sm:h-9 sm:text-sm", value: invoer[k] ?? "", inputMode: k === "sale_price" ? "decimal" : undefined, onChange: (e) => setInvoer((s) => ({ ...s, [k]: e.target.value })) }), k === "sale_price" && prijsFout && _jsx("p", { className: "text-xs text-destructive", children: prijsFout })] }, k))) })] }), _jsxs(Card, { className: "space-y-4 rounded-xl p-4 shadow-sm sm:p-5", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-base font-semibold", children: "Voorraad" }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Liggend wijzig je met Aanpassen of Afboeken \u00B7 Telmoment ", detail.telmoment ? new Date(detail.telmoment).toLocaleString("nl-NL") : _jsx("span", { className: "text-destructive", children: "ontbreekt" })] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", className: "h-9", onClick: () => setAanpassen(true), disabled: gearchiveerd, children: [_jsx(SlidersHorizontal, { className: "mr-2 h-4 w-4" }), "Aanpassen"] }), _jsxs(Button, { variant: "outline", size: "sm", className: "h-9", onClick: () => setAfboeken(true), disabled: gearchiveerd, children: [_jsx(Minus, { className: "mr-2 h-4 w-4" }), "Afboeken"] })] })] }), _jsxs("div", { className: "grid w-full gap-3 sm:grid-cols-3", children: [VOORRAAD_VELDEN.map((k) => (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: `voorraad-${k}`, children: VOORRAAD_LABEL[k] }), _jsx(Input, { id: `voorraad-${k}`, className: "h-10 rounded-lg text-base sm:h-9 sm:text-sm", value: invoer[k] ?? "", inputMode: k === "notes" ? undefined : "numeric", onChange: (e) => setInvoer((s) => ({ ...s, [k]: e.target.value })) })] }, k))), aantalFout && _jsx("p", { className: "text-xs text-destructive sm:col-span-3", children: aantalFout })] })] }), _jsxs(Suspense, { fallback: _jsx(Laden, {}), children: [_jsx(StockMutationHistoryCard, { tradeItemKey: detail.voorraad_sleutel, productId: detail.id, sleutels: detail.controle?.mutatie_sleutels ?? undefined }), _jsx(OrderHistoryCard, { tradeItemKey: detail.voorraad_sleutel, productName: detail.naam, productId: detail.id, productIds: detail.controle?.zelfde_sleutel_ids }), _jsx(ProductCustomFieldsCard, { productId: detail.id, beginVelden: detail.eigen_velden?.definities, beginWaarden: detail.eigen_velden?.waarden })] })] }), _jsx(TabsContent, { value: "verpakking", forceMount: bezocht.has("verpakking") ? true : undefined, className: "mt-4 space-y-4 data-[state=inactive]:hidden", children: _jsxs(Suspense, { fallback: _jsx(Laden, {}), children: [_jsx(ProductStructureCard, { productId: detail.id }), _jsx(ArtikelCompositionCard, { productId: detail.id, floridayId: detail.floriday_id }), _jsx(TrayStickerCard, { productId: detail.id })] }) }), _jsxs(TabsContent, { value: "koppelingen", className: "mt-4 space-y-4", children: [_jsx(TwijfelKiezen, { productId: detail.id, onGekozen: () => void laad() }), _jsxs(Suspense, { fallback: _jsx(Laden, {}), children: [detail.floriday_id && detail.heeft_koppeling ? (_jsx(FloridayInfoCard, { floridayTradeItemId: detail.floriday_id, local: { name: detail.naam, articleNumber: detail.artikelnummer, gtin: detail.velden.barcode ?? null } })) : detail.heeft_koppeling ? (_jsx(Card, { className: "rounded-xl p-4 text-sm text-muted-foreground shadow-sm", children: detail.floriday_verwijderd_at ? "Dit artikel is in Floriday verwijderd." : "Dit artikel is niet aan Floriday gekoppeld." })) : null, _jsx(ProductLinkCard, { tradeItemKey: detail.voorraad_sleutel, productName: detail.naam })] })] }), tabs.includes("floriday") && (_jsx(TabsContent, { value: "floriday", className: "mt-4", children: _jsx(Suspense, { fallback: _jsx(Laden, {}), children: _jsx(ArtikelWizard, { productId: detail.id, resumeJobId: resumeJobId, embedded: true }) }) }))] }) }), _jsx(MobilePrimaryAction, { onClick: () => void doeOpslaan(), disabled: opslaanUit, children: opslaan ? "Opslaan…" : "Opslaan" }), _jsx(AanpassenDialog, { rij: aanpassen ? rij : null, onClose: () => setAanpassen(false), onDone: () => { setAanpassen(false); void laad(); } }), _jsx(AfboekenDialog, { rij: afboeken ? rij : null, connectionId: null, onClose: () => setAfboeken(false), onDone: () => { setAfboeken(false); void laad(); } }), _jsx(Dialog, { open: Boolean(conflicten && conflicten.length), onOpenChange: (o) => !o && setConflicten(null), children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Iemand anders heeft dit ook gewijzigd" }), _jsx(DialogDescription, { children: "Er is niets opgeslagen. Kies per veld welke waarde blijft." })] }), _jsx("div", { className: "space-y-3", children: (conflicten ?? []).map((c) => (_jsxs("div", { className: "rounded-md border p-3 text-sm space-y-2", children: [_jsx("div", { className: "font-medium", children: VELD_LABEL[c.veld] ?? VOORRAAD_LABEL[c.veld] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Jouw wijziging" }), toon(c.jouw)] }), _jsxs("div", { children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Hun wijziging" }), toon(c.hun)] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "outline", onClick: () => houdJouw(c), children: "Mijn waarde houden" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => neemHunOver(c), children: "Hun waarde overnemen" })] })] }, c.veld))) })] }) }), _jsx(Dialog, { open: archief !== null, onOpenChange: (o) => !o && setArchief(null), children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Artikel archiveren" }), _jsx(DialogDescription, { children: "Het artikel wordt nooit verwijderd. Je kunt het later terugzetten." })] }), archief?.waarschuwing && (_jsxs("div", { className: "flex gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "h-4 w-4 shrink-0 text-destructive" }), _jsxs("span", { children: ["Let op: er ", archief.waarschuwing.open_orders === 1 ? "is 1 open order" : `zijn ${archief.waarschuwing.open_orders} open orders`, " en ", aantal(archief.waarschuwing.gereserveerd), " gereserveerd. Die blijven bestaan."] })] })), _jsxs("div", { className: "space-y-2 text-sm", children: [_jsxs("label", { className: "flex gap-2 items-start", children: [_jsx("input", { type: "radio", checked: archiefKeuze === "hier", onChange: () => setArchiefKeuze("hier") }), _jsxs("span", { children: [_jsx("strong", { children: detail.floriday_id && detail.heeft_koppeling ? "Alleen hier." : "Archiveren." }), " ", detail.floriday_id && detail.heeft_koppeling && !detail.floriday_verwijderd_at
|
|
333
341
|
? "Floriday blijft ongewijzigd: het artikel blijft op Floriday te koop."
|
|
@@ -8,7 +8,9 @@ export declare const OPTIONELE_KOLOMMEN: Array<{
|
|
|
8
8
|
export declare function ArtikelStatusIcoon({ status }: {
|
|
9
9
|
status: LijstStatus;
|
|
10
10
|
}): import("react").JSX.Element;
|
|
11
|
-
export declare function VoorraadLijstTabel({ rijen, loading, sort, oplopend, onSort, kolommen, selected, onToggleSelect, onToggleAll, onAanpassen, onAfboeken, heeftKoppeling, leeg, }: {
|
|
11
|
+
export declare function VoorraadLijstTabel({ rijen, loading, sort, oplopend, onSort, kolommen, selected, onToggleSelect, onToggleAll, onAanpassen, onAfboeken, heeftKoppeling, leeg, onVoorOpenen, }: {
|
|
12
|
+
/** Vlak vóór het openen van een artikel (lijststand vastleggen voor terugkomen). */
|
|
13
|
+
onVoorOpenen?: (r: LijstRij) => void;
|
|
12
14
|
heeftKoppeling?: boolean;
|
|
13
15
|
rijen: LijstRij[];
|
|
14
16
|
loading: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoorraadLijstTabel.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/lijst/VoorraadLijstTabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAC;AAQrD,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,6BAA6B,CAAC;AAErC,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AAChF,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAK5E,CAAC;AAmBF,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,+BAGrE;AAeD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAsB,EACtB,IAAI,
|
|
1
|
+
{"version":3,"file":"VoorraadLijstTabel.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/lijst/VoorraadLijstTabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAC;AAQrD,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,6BAA6B,CAAC;AAErC,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AAChF,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAK5E,CAAC;AAmBF,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,+BAGrE;AAeD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAsB,EACtB,IAAI,EACJ,YAAY,GACb,EAAE;IACD,oFAAoF;IACpF,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IAC9B,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,WAAW,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;IACnC,UAAU,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;IAClC,sDAAsD;IACtD,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,+BAgGA"}
|
|
@@ -41,7 +41,7 @@ function Koppeling({ r, heeftKoppeling }) {
|
|
|
41
41
|
return null;
|
|
42
42
|
return (_jsx(HoverTip, { label: "Gekoppeld met Floriday", content: "Gekoppeld met Floriday", className: "h-5 w-5 text-muted-foreground [&_svg]:h-3.5 [&_svg]:w-3.5", children: _jsx(Link2, {}) }));
|
|
43
43
|
}
|
|
44
|
-
export function VoorraadLijstTabel({ rijen, loading, sort, oplopend, onSort, kolommen, selected, onToggleSelect, onToggleAll, onAanpassen, onAfboeken, heeftKoppeling = false, leeg, }) {
|
|
44
|
+
export function VoorraadLijstTabel({ rijen, loading, sort, oplopend, onSort, kolommen, selected, onToggleSelect, onToggleAll, onAanpassen, onAfboeken, heeftKoppeling = false, leeg, onVoorOpenen, }) {
|
|
45
45
|
const navigate = useNavigate();
|
|
46
46
|
const k = (s) => kolommen.has(s);
|
|
47
47
|
const getal = (n, extra = "") => _jsxs("span", { className: "tabular-nums " + extra, children: [aantal(n), " ", _jsx("span", { className: "text-xs font-normal text-muted-foreground", children: "stuks" })] });
|
|
@@ -66,7 +66,10 @@ export function VoorraadLijstTabel({ rijen, loading, sort, oplopend, onSort, kol
|
|
|
66
66
|
{ key: "status", header: "Status", width: "76px", render: (r) => _jsx(ArtikelStatusIcoon, { status: r.status }) },
|
|
67
67
|
];
|
|
68
68
|
const columns = kolomDefs.filter(Boolean);
|
|
69
|
-
const open = (r) =>
|
|
69
|
+
const open = (r) => {
|
|
70
|
+
onVoorOpenen?.(r);
|
|
71
|
+
void navigate({ to: "/voorraad/$id", params: { id: r.id }, state: { vanLijst: true } });
|
|
72
|
+
};
|
|
70
73
|
return (_jsx(DataTable, { columns: columns, rows: rijen, getId: (r) => r.id, loading: loading, sort: { key: sort, asc: oplopend }, onSort: (key) => onSort(key), onOpen: open, openLabel: "Artikel openen", selection: { selected, onToggle: onToggleSelect, onToggleAll, label: (r) => r.naam }, empty: leeg ?? _jsx(EmptyState, { icon: _jsx(PackageSearch, { className: "h-6 w-6" }), title: "Geen artikelen gevonden" }), rowActions: (r) => {
|
|
71
74
|
const gearchiveerd = !!r.gearchiveerd_at;
|
|
72
75
|
const knop = "inline-flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
@@ -17,11 +17,10 @@ export interface VoorraadKpi {
|
|
|
17
17
|
}
|
|
18
18
|
export declare function haalVoorraadKpi(): Promise<VoorraadKpi>;
|
|
19
19
|
export declare function haalVoorraadLijst(v: LijstVraag): Promise<LijstAntwoord>;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export declare function useVoorraadLijst(vraag: LijstVraag): {
|
|
20
|
+
export declare function useVoorraadLijst(vraag: LijstVraag, opties?: {
|
|
21
|
+
userId?: string | null;
|
|
22
|
+
klaar?: boolean;
|
|
23
|
+
}): {
|
|
25
24
|
data: LijstAntwoord | null;
|
|
26
25
|
kpi: VoorraadKpi | null;
|
|
27
26
|
loading: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVoorraadLijst.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoorraadLijst.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"useVoorraadLijst.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoorraadLijst.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGnF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qFAAqF;AACrF,MAAM,WAAW,WAAW;IAAG,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAC7H,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CAI5D;AAGD,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAW7E;AASD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO;;;;;;EAmE3G"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { supabase } from "../integrations/supabase/client.js";
|
|
3
3
|
import { createBundler, pageRequestGuard } from "../lib/request-guard.js";
|
|
4
|
+
import { maakLijstCache } from "../lib/lijst-stand.js";
|
|
4
5
|
export async function haalVoorraadKpi() {
|
|
5
6
|
const { data, error } = await supabase.rpc("voorraad_kpi");
|
|
6
7
|
if (error)
|
|
@@ -25,8 +26,15 @@ export async function haalVoorraadLijst(v) {
|
|
|
25
26
|
* Eén aanvraag per wijziging van zoeken/filter/sortering/pagina. Live-updates
|
|
26
27
|
* gebundeld: één kanaal, hooguit één herlaadactie per 3 s, niet in een verborgen tabblad.
|
|
27
28
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const lijstCache = maakLijstCache();
|
|
30
|
+
const vraagSleutel = (v) => `${v.zoek}|${v.filter}|${v.sort}|${v.oplopend}|${v.pagina}|${v.grootte}`;
|
|
31
|
+
export function useVoorraadLijst(vraag, opties = {}) {
|
|
32
|
+
const userId = opties.userId ?? null;
|
|
33
|
+
const klaar = opties.klaar ?? true;
|
|
34
|
+
const userRef = useRef(userId);
|
|
35
|
+
userRef.current = userId;
|
|
36
|
+
// Bij terugkomen staan de laatst getoonde rijen (zelfde gebruiker, < 30 min) direct in beeld; daarna stil verversen.
|
|
37
|
+
const [data, setData] = useState(() => (userId && klaar ? lijstCache.get(`${userId}#${vraagSleutel(vraag)}`, Date.now()) : null));
|
|
30
38
|
const [kpi, setKpi] = useState(null);
|
|
31
39
|
const [loading, setLoading] = useState(true);
|
|
32
40
|
const [error, setError] = useState(null);
|
|
@@ -48,9 +56,12 @@ export function useVoorraadLijst(vraag) {
|
|
|
48
56
|
const mijn = ++seq.current;
|
|
49
57
|
setLoading(true);
|
|
50
58
|
try {
|
|
51
|
-
const
|
|
59
|
+
const v = vraagRef.current;
|
|
60
|
+
const a = await haalVoorraadLijst(v);
|
|
52
61
|
if (mijn !== seq.current)
|
|
53
62
|
return;
|
|
63
|
+
if (userRef.current)
|
|
64
|
+
lijstCache.set(`${userRef.current}#${vraagSleutel(v)}`, a, Date.now());
|
|
54
65
|
setData(a);
|
|
55
66
|
setError(null);
|
|
56
67
|
}
|
|
@@ -64,10 +75,17 @@ export function useVoorraadLijst(vraag) {
|
|
|
64
75
|
setLoading(false);
|
|
65
76
|
}
|
|
66
77
|
}, []);
|
|
67
|
-
const key =
|
|
78
|
+
const key = vraagSleutel(vraag);
|
|
68
79
|
useEffect(() => {
|
|
80
|
+
if (!klaar)
|
|
81
|
+
return;
|
|
82
|
+
if (userId) {
|
|
83
|
+
const c = lijstCache.get(`${userId}#${key}`, Date.now());
|
|
84
|
+
if (c)
|
|
85
|
+
setData(c);
|
|
86
|
+
}
|
|
69
87
|
void laad();
|
|
70
|
-
}, [key, laad]);
|
|
88
|
+
}, [key, laad, klaar, userId]);
|
|
71
89
|
useEffect(() => {
|
|
72
90
|
const bundler = createBundler(() => { void laad(); void laadKpi(); }, 3000);
|
|
73
91
|
const trigger = () => bundler.trigger();
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export { handleFloridayBaseSupply } from "./server-hooks/floriday-base-supply.js";
|
|
7
7
|
export { handleFloridayContinuousStock } from "./server-hooks/floriday-continuous-stock.js";
|
|
8
8
|
export { handleFloridayFollow } from "./server-hooks/floriday-follow.js";
|
|
9
|
+
export { handleFloridayMutaties } from "./server-hooks/floriday-mutaties.js";
|
|
9
10
|
export { handleFloridayContinuousStockPull } from "./server-hooks/floriday-continuous-stock-pull.js";
|
|
10
11
|
export { handleFloridayStockReconcile } from "./server-hooks/floriday-stock-reconcile.js";
|
|
11
12
|
export { handleLogisticsTasksRun } from "./server-hooks/logistics-tasks-run.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-entry.d.ts","sourceRoot":"","sources":["../src/hooks-entry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,iCAAiC,EAAE,MAAM,+CAA+C,CAAC;AAClG,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC"}
|
|
1
|
+
{"version":3,"file":"hooks-entry.d.ts","sourceRoot":"","sources":["../src/hooks-entry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,iCAAiC,EAAE,MAAM,+CAA+C,CAAC;AAClG,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC"}
|
package/dist-lib/hooks-entry.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export { handleFloridayBaseSupply } from "./server-hooks/floriday-base-supply.js";
|
|
7
7
|
export { handleFloridayContinuousStock } from "./server-hooks/floriday-continuous-stock.js";
|
|
8
8
|
export { handleFloridayFollow } from "./server-hooks/floriday-follow.js";
|
|
9
|
+
export { handleFloridayMutaties } from "./server-hooks/floriday-mutaties.js";
|
|
9
10
|
export { handleFloridayContinuousStockPull } from "./server-hooks/floriday-continuous-stock-pull.js";
|
|
10
11
|
export { handleFloridayStockReconcile } from "./server-hooks/floriday-stock-reconcile.js";
|
|
11
12
|
export { handleLogisticsTasksRun } from "./server-hooks/logistics-tasks-run.js";
|