@flowselections/floriday-voorraad 1.0.147 → 1.0.149

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist-lib/components/voorraad/EditArtikelPage.d.ts.map +1 -1
  2. package/dist-lib/components/voorraad/EditArtikelPage.js +13 -20
  3. package/dist-lib/components/voorraad/OrderHistoryCard.d.ts +3 -1
  4. package/dist-lib/components/voorraad/OrderHistoryCard.d.ts.map +1 -1
  5. package/dist-lib/components/voorraad/OrderHistoryCard.js +7 -3
  6. package/dist-lib/components/voorraad/ProductCustomFieldsCard.d.ts +5 -1
  7. package/dist-lib/components/voorraad/ProductCustomFieldsCard.d.ts.map +1 -1
  8. package/dist-lib/components/voorraad/ProductCustomFieldsCard.js +9 -6
  9. package/dist-lib/components/voorraad/ProductSalePriceField.d.ts.map +1 -1
  10. package/dist-lib/components/voorraad/ProductSalePriceField.js +2 -0
  11. package/dist-lib/components/voorraad/StockMutationHistoryCard.d.ts +3 -1
  12. package/dist-lib/components/voorraad/StockMutationHistoryCard.d.ts.map +1 -1
  13. package/dist-lib/components/voorraad/StockMutationHistoryCard.js +16 -10
  14. package/dist-lib/components/voorraad/VoorraadBeheerCard.d.ts +3 -0
  15. package/dist-lib/components/voorraad/VoorraadBeheerCard.d.ts.map +1 -0
  16. package/dist-lib/components/voorraad/VoorraadBeheerCard.js +44 -0
  17. package/dist-lib/components/voorraad/artikel/ArtikelPagina.d.ts +2 -1
  18. package/dist-lib/components/voorraad/artikel/ArtikelPagina.d.ts.map +1 -1
  19. package/dist-lib/components/voorraad/artikel/ArtikelPagina.js +60 -10
  20. package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.d.ts.map +1 -1
  21. package/dist-lib/components/voorraad/lijst/VoorraadLijstTabel.js +5 -4
  22. package/dist-lib/hooks/useVoorraadCustomFields.d.ts +2 -1
  23. package/dist-lib/hooks/useVoorraadCustomFields.d.ts.map +1 -1
  24. package/dist-lib/hooks/useVoorraadCustomFields.js +8 -4
  25. package/dist-lib/index.d.ts.map +1 -1
  26. package/dist-lib/index.js +2 -0
  27. package/dist-lib/integrations/supabase/types.d.ts +283 -0
  28. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  29. package/dist-lib/lib/artikel-gewijzigd.d.ts +4 -0
  30. package/dist-lib/lib/artikel-gewijzigd.d.ts.map +1 -0
  31. package/dist-lib/lib/artikel-gewijzigd.js +7 -0
  32. package/dist-lib/lib/artikel-pagina.d.ts +14 -3
  33. package/dist-lib/lib/artikel-pagina.d.ts.map +1 -1
  34. package/dist-lib/lib/artikel-pagina.js +5 -1
  35. package/dist-lib/lib/floriday-versie-ronde.d.ts +59 -0
  36. package/dist-lib/lib/floriday-versie-ronde.d.ts.map +1 -0
  37. package/dist-lib/lib/floriday-versie-ronde.functions.d.ts +10 -0
  38. package/dist-lib/lib/floriday-versie-ronde.functions.d.ts.map +1 -0
  39. package/dist-lib/lib/floriday-versie-ronde.functions.js +22 -0
  40. package/dist-lib/lib/floriday-versie-ronde.js +106 -0
  41. package/dist-lib/lib/voorraad-lijst.d.ts +3 -2
  42. package/dist-lib/lib/voorraad-lijst.d.ts.map +1 -1
  43. package/dist-lib/lib/voorraad-lijst.js +6 -2
  44. package/dist-lib/server-hooks/floriday-stock-reconcile.d.ts.map +1 -1
  45. package/dist-lib/server-hooks/floriday-stock-reconcile.js +5 -0
  46. package/dist-lib/server-hooks/floriday-versieronde.d.ts +2 -0
  47. package/dist-lib/server-hooks/floriday-versieronde.d.ts.map +1 -0
  48. package/dist-lib/server-hooks/floriday-versieronde.js +29 -0
  49. package/dist-lib/server-hooks/guard.js +1 -1
  50. package/package.json +1 -1
  51. package/sql/AGENTS.md +2 -0
  52. package/sql/floriday-voorraad-schema.sql +638 -18
@@ -1 +1 @@
1
- {"version":3,"file":"EditArtikelPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/EditArtikelPage.tsx"],"names":[],"mappings":"AAYA,wBAAgB,eAAe,CAAC,EAC9B,EAAE,EACF,WAAW,GACZ,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,+BA4EA"}
1
+ {"version":3,"file":"EditArtikelPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/EditArtikelPage.tsx"],"names":[],"mappings":"AAYA,wBAAgB,eAAe,CAAC,EAC9B,EAAE,EACF,WAAW,GACZ,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,+BAqEA"}
@@ -1,29 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
2
+ import { useCallback, useEffect, useState } from "react";
3
3
  import { Card } from "@flowselections/core";
4
4
  import { Loader2 } from "lucide-react";
5
5
  import { ArtikelWizard } from "./ArtikelWizard.js";
6
6
  import { ArtikelPagina } from "./artikel/ArtikelPagina.js";
7
7
  import { supabase } from "../../integrations/supabase/client.js";
8
8
  export function EditArtikelPage({ id, resumeJobId, }) {
9
- const [resolved, setResolved] = useState(null);
9
+ // Eerst direct de artikelpagina (één aanvraag); alleen als het id geen artikel is, zoeken we verder.
10
+ const [resolved, setResolved] = useState({ kind: "product", id });
11
+ const [zoekVerder, setZoekVerder] = useState(false);
12
+ useEffect(() => { setResolved({ kind: "product", id }); setZoekVerder(false); }, [id]);
13
+ const nietGevonden = useCallback(() => { setResolved(null); setZoekVerder(true); }, []);
10
14
  useEffect(() => {
15
+ if (!zoekVerder)
16
+ return;
11
17
  let cancelled = false;
12
- setResolved(null);
13
18
  (async () => {
14
- // 1. Volwaardig product (canonieke bron sinds de dedup-migratie).
15
- const prodRes = await supabase
16
- .from("products")
17
- .select("id")
18
- .eq("id", id)
19
- .maybeSingle();
20
- if (cancelled)
21
- return;
22
- if (prodRes.data) {
23
- setResolved({ kind: "product", id });
24
- return;
25
- }
26
- // 2. Product met dit Floriday-artikel-ID.
19
+ // Product met dit Floriday-artikel-ID.
27
20
  const byFloriday = await supabase
28
21
  .from("products")
29
22
  .select("id")
@@ -31,11 +24,11 @@ export function EditArtikelPage({ id, resumeJobId, }) {
31
24
  .maybeSingle();
32
25
  if (cancelled)
33
26
  return;
34
- if (byFloriday.data?.id) {
27
+ if (byFloriday.data?.id && byFloriday.data.id !== id) {
35
28
  setResolved({ kind: "product", id: byFloriday.data.id });
36
29
  return;
37
30
  }
38
- // 3. Alleen nog in de Floriday-cache aanwezig (nog niet lokaal gespiegeld).
31
+ // Alleen nog in de Floriday-cache aanwezig (nog niet lokaal gespiegeld).
39
32
  const pubRes = await supabase
40
33
  .from("floriday_trade_items_cache")
41
34
  .select("floriday_id")
@@ -55,7 +48,7 @@ export function EditArtikelPage({ id, resumeJobId, }) {
55
48
  return () => {
56
49
  cancelled = true;
57
50
  };
58
- }, [id]);
51
+ }, [id, zoekVerder]);
59
52
  if (!resolved) {
60
53
  return (_jsx("main", { className: "p-6", children: _jsxs(Card, { className: "p-6 flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), "Artikel laden\u2026"] }) }));
61
54
  }
@@ -63,7 +56,7 @@ export function EditArtikelPage({ id, resumeJobId, }) {
63
56
  return (_jsx("main", { className: "p-6", children: _jsxs(Card, { className: "p-6 text-sm space-y-1", children: [_jsx("div", { children: "Artikel niet gevonden." }), resolved.reason && (_jsx("div", { className: "text-muted-foreground", children: resolved.reason }))] }) }));
64
57
  }
65
58
  if (resolved.kind === "product") {
66
- return _jsx(ArtikelPagina, { id: resolved.id, resumeJobId: resumeJobId });
59
+ return _jsx(ArtikelPagina, { id: resolved.id, resumeJobId: resumeJobId, onNietGevonden: resolved.id === id && !zoekVerder ? nietGevonden : undefined }, resolved.id);
67
60
  }
68
61
  return _jsx(ArtikelWizard, { tradeItemId: resolved.id, resumeJobId: resumeJobId });
69
62
  }
@@ -2,7 +2,9 @@ interface Props {
2
2
  tradeItemKey: string | null;
3
3
  productName: string | null;
4
4
  productId?: string | null;
5
+ /** Artikelen met dezelfde voorraadsleutel, uit voorraad_artikel_detail. */
6
+ productIds?: string[];
5
7
  }
6
- export declare function OrderHistoryCard({ tradeItemKey, productName, productId }: Props): import("react").JSX.Element;
8
+ export declare function OrderHistoryCard({ tradeItemKey, productName, productId, productIds: bekendeIds }: Props): import("react").JSX.Element;
7
9
  export {};
8
10
  //# sourceMappingURL=OrderHistoryCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OrderHistoryCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/OrderHistoryCard.tsx"],"names":[],"mappings":"AAKA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAgDD,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,KAAK,+BAoK/E"}
1
+ {"version":3,"file":"OrderHistoryCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/OrderHistoryCard.tsx"],"names":[],"mappings":"AAKA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAgDD,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,KAAK,+BAsKvG"}
@@ -43,7 +43,7 @@ function formatDate(v) {
43
43
  return v;
44
44
  }
45
45
  }
46
- export function OrderHistoryCard({ tradeItemKey, productName, productId }) {
46
+ export function OrderHistoryCard({ tradeItemKey, productName, productId, productIds: bekendeIds }) {
47
47
  const [rows, setRows] = useState(null);
48
48
  const [error, setError] = useState(null);
49
49
  useEffect(() => {
@@ -55,7 +55,11 @@ export function OrderHistoryCard({ tradeItemKey, productName, productId }) {
55
55
  const productIds = new Set();
56
56
  if (productId)
57
57
  productIds.add(productId);
58
- if (tradeItemKey) {
58
+ if (bekendeIds) {
59
+ for (const p of bekendeIds)
60
+ productIds.add(p);
61
+ }
62
+ else if (tradeItemKey) {
59
63
  const { data: prods } = await supabase
60
64
  .from("products")
61
65
  .select("id")
@@ -122,7 +126,7 @@ export function OrderHistoryCard({ tradeItemKey, productName, productId }) {
122
126
  cancelled = true;
123
127
  supabase.removeChannel(channel);
124
128
  };
125
- }, [tradeItemKey, productName, productId]);
129
+ }, [tradeItemKey, productName, productId, bekendeIds?.join("|")]); // eslint-disable-line react-hooks/exhaustive-deps
126
130
  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(ClipboardList, { className: "h-4 w-4" }) }), _jsx("span", { className: "font-medium", children: "Bestelgeschiedenis" }), _jsx("span", { className: "text-xs text-muted-foreground tabular-nums", children: rows ? `${rows.length} bestelling${rows.length === 1 ? "" : "en"}` : "" })] }), _jsxs(CardContent, { className: "pt-0", children: [error && (_jsxs("div", { className: "text-sm text-destructive", children: ["Kon bestelgeschiedenis niet laden: ", error] })), !rows && !error && (_jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Bestellingen laden\u2026"] })), rows && rows.length === 0 && !error && (_jsx("div", { className: "text-sm text-muted-foreground", children: "Nog geen bestellingen voor dit artikel." })), rows && rows.length > 0 && (_jsx("div", { className: "overflow-x-auto rounded-md border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-muted/50 text-xs uppercase text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "px-3 py-2 text-left", children: "Ordernummer" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Klant" }), _jsx("th", { className: "px-3 py-2 text-right", children: "Fusten" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Besteldatum" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Status" }), _jsx("th", { className: "px-3 py-2" })] }) }), _jsx("tbody", { children: rows.map((r, i) => {
127
131
  const label = normalizeStatus(r.status);
128
132
  const tone = STATUS_TONE[label.toLowerCase()] ??
@@ -1,5 +1,9 @@
1
+ import { type VoorraadCustomField } from "../../lib/voorraad-custom-fields.js";
1
2
  /** Eigen voorraadvelden met `show_in_detail`, tonen en bewerken op de productpagina. */
2
- export declare function ProductCustomFieldsCard({ productId }: {
3
+ export declare function ProductCustomFieldsCard({ productId, beginVelden, beginWaarden, }: {
3
4
  productId: string;
5
+ /** Uit voorraad_artikel_detail: scheelt twee aanvragen bij het openen. */
6
+ beginVelden?: VoorraadCustomField[];
7
+ beginWaarden?: Record<string, unknown>;
4
8
  }): import("react").JSX.Element | null;
5
9
  //# sourceMappingURL=ProductCustomFieldsCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductCustomFieldsCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ProductCustomFieldsCard.tsx"],"names":[],"mappings":"AAuBA,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,sCA+I3E"}
1
+ {"version":3,"file":"ProductCustomFieldsCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ProductCustomFieldsCard.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,kCAAkC,CAAC;AAE1C,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,EACtC,SAAS,EACT,WAAW,EACX,YAAY,GACb,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC,sCAmJA"}
@@ -5,13 +5,16 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle, Checkbox, In
5
5
  import { useVoorraadCustomFields } from "../../hooks/useVoorraadCustomFields.js";
6
6
  import { fetchProductCustomValues, saveProductCustomValues, } from "../../lib/voorraad-custom-fields.js";
7
7
  /** Eigen voorraadvelden met `show_in_detail`, tonen en bewerken op de productpagina. */
8
- export function ProductCustomFieldsCard({ productId }) {
9
- const { fields, loading } = useVoorraadCustomFields();
10
- const [values, setValues] = useState({});
11
- const [opened, setOpened] = useState({});
12
- const [loadingValues, setLoadingValues] = useState(true);
8
+ export function ProductCustomFieldsCard({ productId, beginVelden, beginWaarden, }) {
9
+ const { fields, loading } = useVoorraadCustomFields(beginVelden?.map((f) => ({ ...f, options: Array.isArray(f.options) ? f.options : [] })));
10
+ const [values, setValues] = useState(beginWaarden ?? {});
11
+ const [opened, setOpened] = useState(beginWaarden ?? {});
12
+ const [loadingValues, setLoadingValues] = useState(!beginWaarden);
13
+ const heeftBegin = Boolean(beginWaarden);
13
14
  const [saving, setSaving] = useState(false);
14
15
  useEffect(() => {
16
+ if (heeftBegin)
17
+ return;
15
18
  let cancelled = false;
16
19
  setLoadingValues(true);
17
20
  fetchProductCustomValues(productId)
@@ -34,7 +37,7 @@ export function ProductCustomFieldsCard({ productId }) {
34
37
  return () => {
35
38
  cancelled = true;
36
39
  };
37
- }, [productId]);
40
+ }, [productId, heeftBegin]);
38
41
  const detailFields = fields.filter((f) => f.show_in_detail);
39
42
  const set = (key, value) => setValues((prev) => ({ ...prev, [key]: value }));
40
43
  const gewijzigd = detailFields.filter((f) => JSON.stringify(values[f.field_key] ?? null) !== JSON.stringify(opened[f.field_key] ?? null));
@@ -1 +1 @@
1
- {"version":3,"file":"ProductSalePriceField.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ProductSalePriceField.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,OAAO,GACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,sCAoGA;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,sCAqCtE"}
1
+ {"version":3,"file":"ProductSalePriceField.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ProductSalePriceField.tsx"],"names":[],"mappings":"AAoBA,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,OAAO,GACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,sCAqGA;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,sCAqCtE"}
@@ -12,6 +12,7 @@ import { Button, Input, Label, toast } from "@flowselections/core";
12
12
  import { AlertTriangle, Loader2 } from "lucide-react";
13
13
  import { supabase } from "../../integrations/supabase/client.js";
14
14
  import { priceProblem } from "../../lib/floriday-base-supply.js";
15
+ import { meldArtikelGewijzigd } from "../../lib/artikel-gewijzigd.js";
15
16
  function isPieceUnit(unit) {
16
17
  const u = String(unit ?? "").trim().toLowerCase();
17
18
  return u === "" || u === "stuks" || u === "stuk";
@@ -70,6 +71,7 @@ export function ProductSalePriceField({ productId, onSaved, }) {
70
71
  }
71
72
  setSaved(parsed);
72
73
  onSaved?.(parsed);
74
+ meldArtikelGewijzigd(productId);
73
75
  toast.success("Prijs opgeslagen (alleen lokaal).");
74
76
  }
75
77
  catch (e) {
@@ -1,7 +1,9 @@
1
1
  interface Props {
2
2
  tradeItemKey: string | null;
3
3
  productId?: string | null;
4
+ /** Sleutels uit voorraad_artikel_detail; scheelt een aparte aanvraag bij het openen. */
5
+ sleutels?: string[];
4
6
  }
5
- export declare function StockMutationHistoryCard({ tradeItemKey, productId }: Props): import("react").JSX.Element;
7
+ export declare function StockMutationHistoryCard({ tradeItemKey, productId, sleutels }: Props): import("react").JSX.Element;
6
8
  export {};
7
9
  //# sourceMappingURL=StockMutationHistoryCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StockMutationHistoryCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockMutationHistoryCard.tsx"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAiDD,wBAAgB,wBAAwB,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,KAAK,+BA4O1E"}
1
+ {"version":3,"file":"StockMutationHistoryCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockMutationHistoryCard.tsx"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAiDD,wBAAgB,wBAAwB,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,KAAK,+BAgPpF"}
@@ -42,7 +42,7 @@ function formatMoment(v) {
42
42
  return v;
43
43
  }
44
44
  }
45
- export function StockMutationHistoryCard({ tradeItemKey, productId }) {
45
+ export function StockMutationHistoryCard({ tradeItemKey, productId, sleutels }) {
46
46
  const [rows, setRows] = useState(null);
47
47
  const [error, setError] = useState(null);
48
48
  const [expanded, setExpanded] = useState(false);
@@ -60,14 +60,20 @@ export function StockMutationHistoryCard({ tradeItemKey, productId }) {
60
60
  keys.add(tradeItemKey);
61
61
  if (productId)
62
62
  keys.add(productId);
63
- // Groepssleutels waaronder dit artikel ook afgeboekt kan worden.
64
- const { data: groups } = await supabase
65
- .from("product_group_items")
66
- .select("product_group_id")
67
- .in("trade_item_id", [...keys])
68
- .limit(20);
69
- for (const g of (groups ?? [])) {
70
- keys.add(`group:${g.product_group_id}`);
63
+ // Groepssleutels waaronder dit artikel ook afgeboekt kan worden (meestal al meegeleverd).
64
+ if (sleutels) {
65
+ for (const k of sleutels)
66
+ keys.add(k);
67
+ }
68
+ else {
69
+ const { data: groups } = await supabase
70
+ .from("product_group_items")
71
+ .select("product_group_id")
72
+ .in("trade_item_id", [...keys])
73
+ .limit(20);
74
+ for (const g of (groups ?? [])) {
75
+ keys.add(`group:${g.product_group_id}`);
76
+ }
71
77
  }
72
78
  const { data, error } = await supabase
73
79
  .from("stock_mutation_log")
@@ -135,7 +141,7 @@ export function StockMutationHistoryCard({ tradeItemKey, productId }) {
135
141
  cancelled = true;
136
142
  supabase.removeChannel(channel);
137
143
  };
138
- }, [tradeItemKey, productId]);
144
+ }, [tradeItemKey, productId, sleutels?.join("|")]); // eslint-disable-line react-hooks/exhaustive-deps
139
145
  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(History, { className: "h-4 w-4" }) }), _jsx("span", { className: "font-medium", children: "Afboekgeschiedenis" }), _jsx("span", { className: "text-xs text-muted-foreground tabular-nums", children: rows ? `${rows.length} mutatie${rows.length === 1 ? "" : "s"}` : "" })] }), _jsxs(CardContent, { className: "pt-0", children: [error && (_jsx("div", { className: "text-sm text-destructive", children: error })), !rows && !error && (_jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Mutaties laden\u2026"] })), rows && rows.length === 0 && !error && (_jsx("div", { className: "text-sm text-muted-foreground", children: "Nog geen voorraadmutaties voor dit artikel." })), rows && rows.length > 0 && (_jsxs("div", { className: "overflow-x-auto rounded-md border", children: [_jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-muted/50 text-xs uppercase text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "px-3 py-2 text-left", children: "Wanneer" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Soort" }), _jsx("th", { className: "px-3 py-2 text-right", children: "Aantal" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Van \u2192 naar" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Order" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Door" }), _jsx("th", { className: "px-3 py-2 text-left", children: "Reden" })] }) }), _jsx("tbody", { children: (expanded ? rows : rows.slice(0, 5)).map((r) => {
140
146
  const meta = TYPE_LABEL[r.mutation_type] ?? {
141
147
  label: r.mutation_type || "Onbekend",
@@ -0,0 +1,3 @@
1
+ /** Inklapbaar blok "Beheer": alleen zichtbaar voor beheerders, alleen informatie plus één knop. */
2
+ export declare function VoorraadBeheerCard(): import("react").JSX.Element | null;
3
+ //# sourceMappingURL=VoorraadBeheerCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VoorraadBeheerCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadBeheerCard.tsx"],"names":[],"mappings":"AAuBA,mGAAmG;AACnG,wBAAgB,kBAAkB,uCAwDjC"}
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { Button, Card, CardContent, CardHeader, CardTitle, toast } from "@flowselections/core";
4
+ import { supabase } from "../../integrations/supabase/client.js";
5
+ import { dbFoutTekst } from "../../lib/db-error-message.js";
6
+ import { toonVersieBeheer } from "../../lib/floriday-versie-ronde.js";
7
+ import { floridayVersiesControleren } from "../../lib/floriday-versie-ronde.functions.js";
8
+ const STATUS_TEKST = {
9
+ geslaagd: "geslaagd",
10
+ onvolledig: "nog niet compleet (wordt automatisch opnieuw geprobeerd)",
11
+ mislukt: "mislukt (wordt automatisch opnieuw geprobeerd)",
12
+ };
13
+ /** Inklapbaar blok "Beheer": alleen zichtbaar voor beheerders, alleen informatie plus één knop. */
14
+ export function VoorraadBeheerCard() {
15
+ const [status, setStatus] = useState(null);
16
+ const [bezig, setBezig] = useState(false);
17
+ const laad = useCallback(async () => {
18
+ const { data, error } = await supabase.rpc("voorraad_floriday_versieronde_status");
19
+ if (error) {
20
+ setStatus(null);
21
+ return;
22
+ }
23
+ setStatus(data);
24
+ }, []);
25
+ useEffect(() => { void laad(); }, [laad]);
26
+ if (!toonVersieBeheer(status) || !status?.heeft_koppeling)
27
+ return null;
28
+ const start = async () => {
29
+ setBezig(true);
30
+ try {
31
+ await floridayVersiesControleren();
32
+ toast.success("Controle gestart. Dit loopt op de achtergrond.");
33
+ await laad();
34
+ }
35
+ catch (e) {
36
+ toast.error(dbFoutTekst(e));
37
+ }
38
+ finally {
39
+ setBezig(false);
40
+ }
41
+ };
42
+ const l = status.laatste;
43
+ return (_jsx(Card, { children: _jsxs("details", { children: [_jsx("summary", { className: "cursor-pointer list-none", children: _jsx(CardHeader, { children: _jsx(CardTitle, { children: "Beheer" }) }) }), _jsxs(CardContent, { className: "space-y-2 text-sm", children: [_jsx("p", { className: "font-medium", children: "Controle van Floriday-artikelen" }), _jsx("p", { className: "text-muted-foreground", children: "Loopt vanzelf elke nacht. Oude versies van Floriday-artikelen worden geen zichtbaar artikel." }), _jsxs("p", { children: ["Laatste controle:", " ", l ? `${new Date(l.uitgevoerd_at).toLocaleString("nl-NL")} — ${STATUS_TEKST[l.status] ?? l.status}` : "nog niet uitgevoerd", status.bezig && " · nu bezig"] }), l?.melding && l.status !== "geslaagd" && _jsx("p", { className: "text-muted-foreground", children: l.melding }), _jsxs("p", { children: ["Vervangen in Floriday: ", status.vervangen ?? 0, " \u00B7 Vervallen: ", status.vervallen ?? 0, " \u00B7 Apart gezet (geen antwoord van Floriday): ", status.onbekend ?? 0] }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => void start(), disabled: bezig || status.bezig, children: bezig ? "Bezig…" : "Nu opnieuw controleren" })] })] }) }));
44
+ }
@@ -1,5 +1,6 @@
1
- export declare function ArtikelPagina({ id, resumeJobId }: {
1
+ export declare function ArtikelPagina({ id, resumeJobId, onNietGevonden }: {
2
2
  id: string;
3
3
  resumeJobId?: string;
4
+ onNietGevonden?: () => void;
4
5
  }): import("react").JSX.Element;
5
6
  //# sourceMappingURL=ArtikelPagina.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ArtikelPagina.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/artikel/ArtikelPagina.tsx"],"names":[],"mappings":"AAiFA,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,+BA0ZtF"}
1
+ {"version":3,"file":"ArtikelPagina.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/artikel/ArtikelPagina.tsx"],"names":[],"mappings":"AAwFA,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,+BA+bnI"}
@@ -5,6 +5,7 @@ import { Badge, Button, Card, Dialog, DialogContent, DialogDescription, DialogFo
5
5
  import { AlertTriangle, ArrowLeft, Loader2, MoreHorizontal, Package, Send } from "lucide-react";
6
6
  import { supabase } from "../../../integrations/supabase/client.js";
7
7
  import { dbFoutTekst } from "../../../lib/db-error-message.js";
8
+ import { ARTIKEL_GEWIJZIGD } from "../../../lib/artikel-gewijzigd.js";
8
9
  import { ARTIKEL_VELDEN, VELD_LABEL, VOORRAAD_LABEL, VOORRAAD_VELDEN, aantalUitInvoer, gewijzigdeVoorraad, alsLijstRij, artikelStatus, artikelTabs, floridayActie, gewijzigdeVelden, prijsUitInvoer, } from "../../../lib/artikel-pagina.js";
9
10
  import { STATUS_INFO, aantal, geld } from "../../../lib/voorraad-lijst.js";
10
11
  import { AanpassenDialog, AfboekenDialog } from "../lijst/SnelActieDialogen.js";
@@ -34,7 +35,11 @@ function toon(v) {
34
35
  return "(leeg)";
35
36
  return String(v);
36
37
  }
37
- export function ArtikelPagina({ id, resumeJobId }) {
38
+ function gelijk(a, b) {
39
+ const n = (v) => (v === null || v === undefined ? "" : String(v).trim());
40
+ return n(a) === n(b);
41
+ }
42
+ export function ArtikelPagina({ id, resumeJobId, onNietGevonden }) {
38
43
  const [detail, setDetail] = useState(null);
39
44
  const [fout, setFout] = useState(null);
40
45
  const [bijOpenen, setBijOpenen] = useState(null);
@@ -50,6 +55,7 @@ export function ArtikelPagina({ id, resumeJobId }) {
50
55
  const [archiefKeuze, setArchiefKeuze] = useState("hier");
51
56
  const [bezig, setBezig] = useState(false);
52
57
  const geladen = useRef(false);
58
+ const invoerRef = useRef({});
53
59
  // Onderdelen (eigen velden, traysticker) die meedoen met de ene knop "Opslaan".
54
60
  const [deelnemers, setDeelnemers] = useState({});
55
61
  const register = useMemo(() => ({
@@ -76,7 +82,10 @@ export function ArtikelPagina({ id, resumeJobId }) {
76
82
  }
77
83
  const d = data;
78
84
  if (!d?.gevonden) {
79
- setFout("Dit artikel bestaat niet (meer) in de voorraad.");
85
+ if (onNietGevonden)
86
+ onNietGevonden();
87
+ else
88
+ setFout("Dit artikel bestaat niet (meer) in de voorraad.");
80
89
  return;
81
90
  }
82
91
  setDetail(d);
@@ -91,24 +100,63 @@ export function ArtikelPagina({ id, resumeJobId }) {
91
100
  ...Object.fromEntries(VOORRAAD_VELDEN.map((k) => [k, vb[k] === null ? "" : String(vb[k])])),
92
101
  });
93
102
  }
94
- }, [id]);
95
- useEffect(() => { geladen.current = false; void laad(); }, [laad]);
103
+ else {
104
+ // Velden die je niet zelf aan het wijzigen bent, volgen de nieuwe stand (ook na opslaan in een ander tabblad).
105
+ const inv = invoerRef.current;
106
+ const vb = { minimum_stock: d.minimum, incoming_stock: d.inkomend, notes: d.notitie ?? null };
107
+ const volg = {};
108
+ setBijOpenen((b) => {
109
+ if (!b)
110
+ return b;
111
+ const n = { ...b };
112
+ for (const k of ARTIKEL_VELDEN)
113
+ if (gelijk(inv[k], b[k]) && !gelijk(b[k], d.velden[k])) {
114
+ n[k] = d.velden[k];
115
+ volg[k] = d.velden[k] === null ? "" : String(d.velden[k]);
116
+ }
117
+ return n;
118
+ });
119
+ setVoorraadBij((b) => {
120
+ if (!b)
121
+ return b;
122
+ const n = { ...b };
123
+ for (const k of VOORRAAD_VELDEN)
124
+ if (gelijk(inv[k], b[k]) && !gelijk(b[k], vb[k])) {
125
+ n[k] = vb[k];
126
+ volg[k] = vb[k] === null ? "" : String(vb[k]);
127
+ }
128
+ return n;
129
+ });
130
+ setInvoer((s) => ({ ...s, ...volg }));
131
+ }
132
+ }, [id, onNietGevonden]);
133
+ useEffect(() => { invoerRef.current = invoer; }, [invoer]);
134
+ useEffect(() => { geladen.current = false; void laad(); }, [id]); // eslint-disable-line react-hooks/exhaustive-deps
135
+ // Opslag in een ander tabblad van deze pagina (prijs in het Floriday-formulier, samenstelling): kop direct bijwerken.
136
+ useEffect(() => {
137
+ const h = (e) => { if (e.detail?.id === id)
138
+ void laad(); };
139
+ window.addEventListener(ARTIKEL_GEWIJZIGD, h);
140
+ return () => window.removeEventListener(ARTIKEL_GEWIJZIGD, h);
141
+ }, [id, laad]);
96
142
  // Live bijwerken alleen voor dit artikel (voorraadregel en artikelrij), gebundeld.
143
+ const heeftDetail = Boolean(detail);
144
+ const voorraadSleutel = detail?.voorraad_sleutel ?? null;
97
145
  useEffect(() => {
98
- if (!detail)
146
+ if (!heeftDetail)
99
147
  return;
100
148
  let t = null;
101
149
  const later = () => { if (t)
102
150
  clearTimeout(t); t = setTimeout(() => void laad(), 1500); };
103
151
  let ch = supabase.channel(`artikel-${id}`)
104
152
  .on("postgres_changes", { event: "*", schema: "public", table: "products", filter: `id=eq.${id}` }, later);
105
- if (detail.voorraad_sleutel) {
106
- ch = ch.on("postgres_changes", { event: "*", schema: "public", table: "trade_item_stock", filter: `trade_item_key=eq.${detail.voorraad_sleutel}` }, later);
153
+ if (voorraadSleutel) {
154
+ ch = ch.on("postgres_changes", { event: "*", schema: "public", table: "trade_item_stock", filter: `trade_item_key=eq.${voorraadSleutel}` }, later);
107
155
  }
108
156
  ch.subscribe();
109
157
  return () => { if (t)
110
158
  clearTimeout(t); supabase.removeChannel(ch); };
111
- }, [id, detail?.voorraad_sleutel, laad, detail]);
159
+ }, [id, voorraadSleutel, laad, heeftDetail]);
112
160
  const nieuw = useMemo(() => {
113
161
  if (!bijOpenen)
114
162
  return null;
@@ -249,7 +297,7 @@ export function ArtikelPagina({ id, resumeJobId }) {
249
297
  if (floridayOpen && !tabs.includes("floriday") && actie === "op_floriday")
250
298
  tabs.push("floriday");
251
299
  const rij = alsLijstRij(detail);
252
- return (_jsxs("main", { className: "p-6 space-y-4", children: [_jsxs(Link, { to: "/voorraad", className: "inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), " Terug naar voorraad"] }), _jsx(Card, { className: "p-4", children: _jsxs("div", { className: "flex flex-wrap items-start gap-4", children: [_jsx("div", { className: "h-20 w-20 shrink-0 overflow-hidden rounded-md border bg-muted flex items-center justify-center", children: detail.foto ? _jsx("img", { src: detail.foto, alt: detail.naam, className: "h-full w-full object-cover" }) : _jsx(Package, { className: "h-8 w-8 text-muted-foreground" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h1", { className: "text-xl font-semibold truncate", children: detail.naam }), _jsx("div", { className: "text-sm text-muted-foreground", children: detail.artikelnummer ?? "Geen artikelnummer" }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-2 text-sm", children: [_jsx(Badge, { variant: status === "ok" ? "secondary" : status === "gearchiveerd" ? "outline" : "destructive", children: info.label }), info.actie && info.tab && tabs.includes(info.tab) && (_jsx("button", { type: "button", className: "underline text-muted-foreground", onClick: () => setTab(info.tab), children: info.actie })), vuil && _jsx("span", { className: "text-muted-foreground", children: "\u00B7 Niet-opgeslagen wijzigingen" })] })] }), _jsx("dl", { className: "grid grid-cols-5 gap-4 text-center", children: [
300
+ return (_jsxs("main", { className: "p-6 space-y-4", children: [_jsxs(Link, { to: "/voorraad", className: "inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), " Terug naar voorraad"] }), _jsx(Card, { className: "p-4", children: _jsxs("div", { className: "flex flex-wrap items-start gap-4", children: [_jsx("div", { className: "h-20 w-20 shrink-0 overflow-hidden rounded-md border bg-muted flex items-center justify-center", children: detail.foto ? _jsx("img", { src: detail.foto, alt: detail.naam, className: "h-full w-full object-cover" }) : _jsx(Package, { className: "h-8 w-8 text-muted-foreground" }) }), _jsxs("div", { className: "min-w-0 flex-1 basis-64", children: [_jsx("h1", { className: "text-xl font-semibold leading-tight break-words", children: detail.naam }), _jsx("div", { className: "mt-1 text-sm text-muted-foreground break-words", children: detail.artikelnummer ?? "Geen artikelnummer" }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-2 text-sm", children: [_jsx(Badge, { variant: status === "ok" ? "secondary" : status === "gearchiveerd" ? "outline" : "destructive", children: info.label }), info.actie && info.tab && tabs.includes(info.tab) && (_jsx("button", { type: "button", className: "underline text-muted-foreground", onClick: () => setTab(info.tab), children: info.actie })), vuil && _jsx("span", { className: "text-muted-foreground", children: "\u00B7 Niet-opgeslagen wijzigingen" })] })] }), _jsx("dl", { className: "grid grid-cols-3 gap-4 text-center sm:grid-cols-5", children: [
253
301
  ["Liggend", aantal(detail.liggend)],
254
302
  ["Gereserveerd", aantal(detail.gereserveerd)],
255
303
  ["Inkomend", aantal(detail.inkomend)],
@@ -257,7 +305,9 @@ export function ArtikelPagina({ id, resumeJobId }) {
257
305
  ["Prijs per stuk", geld(detail.velden.sale_price === null ? null : Number(detail.velden.sale_price))],
258
306
  ].map(([l, v], i) => (_jsxs("div", { children: [_jsx("dt", { className: "text-xs text-muted-foreground", children: l }), _jsx("dd", { className: `text-lg font-semibold tabular-nums ${i === 3 && rij.onder_minimum ? "text-destructive" : ""}`, children: v })] }, l))) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { onClick: doeOpslaan, disabled: !vuil || opslaan || Boolean(prijsFout) || Boolean(aantalFout), children: [opslaan && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Opslaan"] }), actie && (_jsxs(Button, { variant: "outline", onClick: () => { setFloridayOpen(true); setTab("floriday"); }, children: [_jsx(Send, { className: "mr-2 h-4 w-4" }), actie === "sturen" ? "Naar Floriday sturen" : "Op Floriday zetten"] })), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Meer acties", children: _jsx(MoreHorizontal, { className: "h-4 w-4" }) }) }), _jsx(DropdownMenuContent, { align: "end", children: detail.gearchiveerd_at
259
307
  ? _jsx(DropdownMenuItem, { onClick: terugzetten, children: "Terugzetten in voorraad" })
260
- : _jsx(DropdownMenuItem, { onClick: () => { setArchiefKeuze("hier"); setArchief({}); }, children: "Archiveren\u2026" }) })] })] })] }) }), detail.gearchiveerd_at && (detail.orders_gearchiveerd ?? 0) > 0 && (_jsxs("div", { role: "alert", className: "flex flex-wrap items-center gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), _jsxs("span", { 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."] }), _jsx(Button, { size: "sm", variant: "outline", onClick: terugzetten, children: "Terugzetten in voorraad" })] })), _jsx(OpslaanContext.Provider, { value: register, children: _jsxs(Tabs, { value: tab, onValueChange: setTab, children: [_jsx(TabsList, { children: tabs.map((t) => _jsx(TabsTrigger, { value: t, children: TAB_LABEL[t] }, t)) }), _jsxs(TabsContent, { value: "voorraad", forceMount: bezocht.has("voorraad") ? true : undefined, className: "space-y-4 data-[state=inactive]:hidden", children: [_jsxs(Card, { className: "p-4 space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsx("h2", { className: "font-medium", children: "Artikelgegevens" }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Opslaan is alleen lokaal; er gaat niets automatisch naar Floriday." })] }), _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}`, 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: "p-4 flex flex-wrap items-center justify-between gap-2", children: [_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}`, 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("div", { className: "text-sm", children: [_jsx("div", { className: "font-medium", children: "Voorraad" }), _jsxs("div", { className: "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: [_jsx(Button, { variant: "outline", onClick: () => setAanpassen(true), disabled: Boolean(detail.gearchiveerd_at), children: "Aanpassen" }), _jsx(Button, { variant: "outline", onClick: () => setAfboeken(true), disabled: Boolean(detail.gearchiveerd_at), children: "Afboeken" })] })] }), _jsxs(Suspense, { fallback: _jsx(Laden, {}), children: [_jsx(StockMutationHistoryCard, { tradeItemKey: detail.voorraad_sleutel, productId: detail.id }), _jsx(OrderHistoryCard, { tradeItemKey: detail.voorraad_sleutel, productName: detail.naam, productId: detail.id }), _jsx(ProductCustomFieldsCard, { productId: detail.id })] })] }), _jsx(TabsContent, { value: "verpakking", forceMount: bezocht.has("verpakking") ? true : undefined, className: "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: "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 } })) : (_jsx(Card, { className: "p-4 text-sm text-muted-foreground", children: detail.heeft_koppeling ? "Dit artikel is niet aan Floriday gekoppeld." : "Er is geen Floriday-koppeling in deze omgeving; het artikel werkt volledig lokaal." })), _jsx(ProductLinkCard, { tradeItemKey: detail.voorraad_sleutel, productName: detail.naam })] })] }), tabs.includes("floriday") && (_jsx(TabsContent, { value: "floriday", children: _jsx(Suspense, { fallback: _jsx(Laden, {}), children: _jsx(ArtikelWizard, { productId: detail.id, resumeJobId: resumeJobId, embedded: true }) }) }))] }) }), _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: "Alleen hier." }), " Floriday blijft ongewijzigd: het artikel blijft op Floriday te koop."] })] }), detail.floriday_id && detail.heeft_koppeling && (_jsxs("label", { className: "flex gap-2 items-start", children: [_jsx("input", { type: "radio", checked: archiefKeuze === "floriday", onChange: () => setArchiefKeuze("floriday") }), _jsxs("span", { children: [_jsx("strong", { children: "Ook in Floriday." }), " De voorraad op Floriday wordt 0."] })] })), archiefKeuze === "floriday" && (_jsxs("div", { className: "rounded-md border p-3 space-y-1", children: [_jsx("div", { className: "font-medium", children: "Overzicht vooraf" }), _jsx("div", { children: "Voorraad op Floriday: wordt 0 (niet meer te koop)." }), _jsxs("div", { children: ["Je eigen voorraad blijft ", aantal(detail.liggend), " liggend."] }), _jsx("div", { className: "text-muted-foreground", children: detail.floriday_stuurt
308
+ : _jsx(DropdownMenuItem, { onClick: () => { setArchiefKeuze("hier"); setArchief({}); }, children: "Archiveren\u2026" }) })] })] })] }) }), detail.gearchiveerd_at && (detail.orders_gearchiveerd ?? 0) > 0 && (_jsxs("div", { role: "alert", className: "flex flex-wrap items-center gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), _jsxs("span", { 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."] }), _jsx(Button, { size: "sm", variant: "outline", onClick: terugzetten, children: "Terugzetten in voorraad" })] })), _jsx(OpslaanContext.Provider, { value: register, children: _jsxs(Tabs, { value: tab, onValueChange: setTab, children: [_jsx(TabsList, { children: tabs.map((t) => _jsx(TabsTrigger, { value: t, children: TAB_LABEL[t] }, t)) }), _jsxs(TabsContent, { value: "voorraad", forceMount: bezocht.has("voorraad") ? true : undefined, className: "space-y-4 data-[state=inactive]:hidden", children: [_jsxs(Card, { className: "p-4 space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsx("h2", { className: "font-medium", children: "Artikelgegevens" }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Opslaan is alleen lokaal; er gaat niets automatisch naar Floriday." })] }), _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}`, 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: "p-4 flex flex-wrap items-center justify-between gap-2", children: [_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}`, 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("div", { className: "text-sm", children: [_jsx("div", { className: "font-medium", children: "Voorraad" }), _jsxs("div", { className: "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: [_jsx(Button, { variant: "outline", onClick: () => setAanpassen(true), disabled: Boolean(detail.gearchiveerd_at), children: "Aanpassen" }), _jsx(Button, { variant: "outline", onClick: () => setAfboeken(true), disabled: Boolean(detail.gearchiveerd_at), children: "Afboeken" })] })] }), _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: "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: "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 } })) : (_jsx(Card, { className: "p-4 text-sm text-muted-foreground", children: detail.heeft_koppeling ? (detail.floriday_verwijderd_at ? "Dit artikel is in Floriday verwijderd." : "Dit artikel is niet aan Floriday gekoppeld.") : "Er is geen Floriday-koppeling in deze omgeving; het artikel werkt volledig lokaal." })), _jsx(ProductLinkCard, { tradeItemKey: detail.voorraad_sleutel, productName: detail.naam })] })] }), tabs.includes("floriday") && (_jsx(TabsContent, { value: "floriday", children: _jsx(Suspense, { fallback: _jsx(Laden, {}), children: _jsx(ArtikelWizard, { productId: detail.id, resumeJobId: resumeJobId, embedded: true }) }) }))] }) }), _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
309
+ ? "Floriday blijft ongewijzigd: het artikel blijft op Floriday te koop."
310
+ : "Het artikel verdwijnt uit de voorraadlijst en de tellers."] })] }), detail.floriday_id && detail.heeft_koppeling && !detail.floriday_verwijderd_at && (_jsxs("label", { className: "flex gap-2 items-start", children: [_jsx("input", { type: "radio", checked: archiefKeuze === "floriday", onChange: () => setArchiefKeuze("floriday") }), _jsxs("span", { children: [_jsx("strong", { children: "Ook in Floriday." }), " De voorraad op Floriday wordt 0."] })] })), archiefKeuze === "floriday" && (_jsxs("div", { className: "rounded-md border p-3 space-y-1", children: [_jsx("div", { className: "font-medium", children: "Overzicht vooraf" }), _jsx("div", { children: "Voorraad op Floriday: wordt 0 (niet meer te koop)." }), _jsxs("div", { children: ["Je eigen voorraad blijft ", aantal(detail.liggend), " liggend."] }), _jsx("div", { className: "text-muted-foreground", children: detail.floriday_stuurt
261
311
  ? "Gaat via de gewone Floriday-wachtrij, met de bestaande schrijfstop."
262
312
  : "Floriday is voor dit artikel leidend: er wordt niets verstuurd tot het systeem de voorraad stuurt." })] }))] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "ghost", onClick: () => setArchief(null), children: "Annuleren" }), _jsx(Button, { variant: "destructive", disabled: bezig, onClick: () => archiveren(Boolean(archief?.waarschuwing)), children: archief?.waarschuwing ? "Toch archiveren" : "Archiveren" })] })] }) })] }));
263
313
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VoorraadLijstTabel.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/lijst/VoorraadLijstTabel.tsx"],"names":[],"mappings":"AAeA,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,SAAS,EAEf,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;AA8CF,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,GACvB,EAAE;IACD,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;CACnC,+BAyFA"}
1
+ {"version":3,"file":"VoorraadLijstTabel.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/lijst/VoorraadLijstTabel.tsx"],"names":[],"mappings":"AAeA,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,SAAS,EAEf,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;AA+CF,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,GACvB,EAAE;IACD,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;CACnC,+BAyFA"}
@@ -15,10 +15,11 @@ function StatusIcoon({ status }) {
15
15
  const titel = info.actie ? `${info.label} — ${info.actie}` : info.label;
16
16
  const cls = "h-4 w-4";
17
17
  const icon = status === "verpakking" ? _jsx(PackageX, { className: `${cls} text-destructive` }) :
18
- status === "niet_gekoppeld" ? _jsx(Link2Off, { className: `${cls} text-muted-foreground` }) :
19
- status === "prijs" ? _jsx(Euro, { className: `${cls} text-destructive` }) :
20
- status === "gearchiveerd" ? _jsx(Minus, { className: `${cls} text-muted-foreground` }) :
21
- _jsx(CheckCircle2, { className: `${cls} text-primary` });
18
+ status === "verwijderd_floriday" ? _jsx(Link2Off, { className: `${cls} text-destructive` }) :
19
+ status === "niet_gekoppeld" ? _jsx(Link2Off, { className: `${cls} text-muted-foreground` }) :
20
+ status === "prijs" ? _jsx(Euro, { className: `${cls} text-destructive` }) :
21
+ status === "gearchiveerd" ? _jsx(Minus, { className: `${cls} text-muted-foreground` }) :
22
+ _jsx(CheckCircle2, { className: `${cls} text-primary` });
22
23
  return (_jsxs("span", { title: titel, "aria-label": titel, className: "inline-flex items-center gap-1.5", children: [icon, status !== "ok" && _jsx("span", { className: "text-xs text-muted-foreground hidden xl:inline", children: info.label })] }));
23
24
  }
24
25
  function Kop({ kolom, label, sort, oplopend, onSort, rechts, }) {
@@ -1,6 +1,7 @@
1
1
  import { type VoorraadCustomField } from "../lib/voorraad-custom-fields.js";
2
2
  /** Laadt de door de gebruiker gedefinieerde voorraadvelden. */
3
- export declare function useVoorraadCustomFields(): {
3
+ /** `begin`: velden die al bekend zijn (uit voorraad_artikel_detail); dan geen eigen aanvraag. */
4
+ export declare function useVoorraadCustomFields(begin?: VoorraadCustomField[]): {
4
5
  fields: VoorraadCustomField[];
5
6
  loading: boolean;
6
7
  error: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"useVoorraadCustomFields.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoorraadCustomFields.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,+BAA+B,CAAC;AAEvC,+DAA+D;AAC/D,wBAAgB,uBAAuB;;;;;EAuBtC"}
1
+ {"version":3,"file":"useVoorraadCustomFields.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoorraadCustomFields.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,+BAA+B,CAAC;AAEvC,+DAA+D;AAC/D,iGAAiG;AACjG,wBAAgB,uBAAuB,CAAC,KAAK,CAAC,EAAE,mBAAmB,EAAE;;;;;EAyBpE"}
@@ -1,9 +1,10 @@
1
1
  import { useCallback, useEffect, useState } from "react";
2
2
  import { fetchVoorraadCustomFields, } from "../lib/voorraad-custom-fields.js";
3
3
  /** Laadt de door de gebruiker gedefinieerde voorraadvelden. */
4
- export function useVoorraadCustomFields() {
5
- const [fields, setFields] = useState([]);
6
- const [loading, setLoading] = useState(true);
4
+ /** `begin`: velden die al bekend zijn (uit voorraad_artikel_detail); dan geen eigen aanvraag. */
5
+ export function useVoorraadCustomFields(begin) {
6
+ const [fields, setFields] = useState(begin ?? []);
7
+ const [loading, setLoading] = useState(!begin);
7
8
  const [error, setError] = useState(null);
8
9
  const reload = useCallback(async () => {
9
10
  setLoading(true);
@@ -19,8 +20,11 @@ export function useVoorraadCustomFields() {
19
20
  setLoading(false);
20
21
  }
21
22
  }, []);
23
+ const heeftBegin = Boolean(begin);
22
24
  useEffect(() => {
25
+ if (heeftBegin)
26
+ return;
23
27
  void reload();
24
- }, [reload]);
28
+ }, [reload, heeftBegin]);
25
29
  return { fields, loading, error, reload };
26
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAKpE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAExE,eAAO,MAAM,sBAAsB,EAAE,UAiBpC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAMpE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAExE,eAAO,MAAM,sBAAsB,EAAE,UAkBpC,CAAC"}