@flowselections/floriday-voorraad 1.0.11 → 1.0.13

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 (38) hide show
  1. package/dist-lib/components/voorraad/ConnectionBadge.d.ts +6 -0
  2. package/dist-lib/components/voorraad/ConnectionBadge.d.ts.map +1 -0
  3. package/dist-lib/components/voorraad/ConnectionBadge.js +12 -0
  4. package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
  5. package/dist-lib/components/voorraad/VoorraadPage.js +18 -10
  6. package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
  7. package/dist-lib/components/voorraad/VoorraadTable.js +10 -2
  8. package/dist-lib/hooks/useFloridayConnection.d.ts +9 -4
  9. package/dist-lib/hooks/useFloridayConnection.d.ts.map +1 -1
  10. package/dist-lib/hooks/useFloridayConnection.js +23 -23
  11. package/dist-lib/hooks/useFlorydayCustomers.d.ts +17 -0
  12. package/dist-lib/hooks/useFlorydayCustomers.d.ts.map +1 -0
  13. package/dist-lib/hooks/useFlorydayCustomers.js +65 -0
  14. package/dist-lib/hooks/useLocalTradeItems.d.ts +22 -0
  15. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -0
  16. package/dist-lib/hooks/useLocalTradeItems.js +100 -0
  17. package/dist-lib/hooks/useVoorraadData.d.ts +5 -0
  18. package/dist-lib/hooks/useVoorraadData.d.ts.map +1 -1
  19. package/dist-lib/hooks/useVoorraadData.js +37 -10
  20. package/dist-lib/index.d.ts +1 -1
  21. package/dist-lib/index.d.ts.map +1 -1
  22. package/dist-lib/index.js +1 -1
  23. package/dist-lib/integrations/supabase/auth-middleware.d.ts +2493 -32
  24. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  25. package/dist-lib/integrations/supabase/client.d.ts +2493 -32
  26. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  27. package/dist-lib/integrations/supabase/client.js +1 -1
  28. package/dist-lib/integrations/supabase/client.server.d.ts +2493 -32
  29. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  30. package/dist-lib/integrations/supabase/client.server.js +1 -1
  31. package/dist-lib/integrations/supabase/types.d.ts +2606 -82
  32. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  33. package/dist-lib/integrations/supabase/types.js +10 -0
  34. package/dist-lib/lib/floriday-client.d.ts +10 -12
  35. package/dist-lib/lib/floriday-client.d.ts.map +1 -1
  36. package/dist-lib/lib/floriday-client.js +32 -15
  37. package/dist-lib/styles.css +1 -0
  38. package/package.json +4 -3
@@ -0,0 +1,6 @@
1
+ import type { FloridayActiveConnection } from "../../lib/floriday-client";
2
+ export declare function ConnectionBadge({ connection, loading, }: {
3
+ connection: FloridayActiveConnection | null;
4
+ loading?: boolean;
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=ConnectionBadge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectionBadge.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ConnectionBadge.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1E,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,OAAO,GACR,EAAE;IACD,UAAU,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,2CAqBA"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Badge } from "@flowselections/core";
3
+ export function ConnectionBadge({ connection, loading, }) {
4
+ if (loading) {
5
+ return _jsx(Badge, { variant: "secondary", children: "Floriday laden..." });
6
+ }
7
+ if (!connection) {
8
+ return (_jsx(Badge, { variant: "destructive", children: "Geen actieve Floriday-connectie" }));
9
+ }
10
+ const env = connection.active_environment || connection.environment;
11
+ return (_jsxs(Badge, { variant: "secondary", className: "gap-1.5", children: [_jsx("span", { className: "font-medium", children: "Floriday" }), _jsx("span", { className: "opacity-60", children: "\u00B7" }), _jsx("span", { className: "uppercase tracking-wide text-[10px]", children: env }), _jsx("span", { className: "opacity-60", children: "\u00B7" }), _jsx("span", { children: connection.organization_name || connection.label })] }));
12
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AAUA,wBAAgB,YAAY,4CAuE3B"}
1
+ {"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,YAAY,4CAqF3B"}
@@ -1,23 +1,31 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useState } from "react";
3
3
  import { Link } from "@tanstack/react-router";
4
- import { Button, Card, Input } from "@flowselections/core";
4
+ import { Button, Card, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
5
5
  import { Plus, RefreshCw, Search } from "lucide-react";
6
6
  import { useFloridayConnection } from "../../hooks/useFloridayConnection";
7
7
  import { useVoorraadData } from "../../hooks/useVoorraadData";
8
- import { ConnectionPicker } from "./ConnectionPicker";
8
+ import { ConnectionBadge } from "./ConnectionBadge";
9
9
  import { ExcelExportButton } from "./ExcelExportButton";
10
10
  import { VoorraadTable } from "./VoorraadTable";
11
11
  export function VoorraadPage() {
12
- const { connections, activeId, setActiveId, loading: connLoading, error: connError, } = useFloridayConnection();
12
+ const { activeConnection, activeId, loading: connLoading, error: connError, } = useFloridayConnection();
13
13
  const { items, loading, error, reload } = useVoorraadData(activeId);
14
14
  const [search, setSearch] = useState("");
15
+ const [publishFilter, setPublishFilter] = useState("all");
15
16
  const filtered = useMemo(() => {
16
- if (!search.trim())
17
- return items;
18
- const q = search.toLowerCase();
19
- return items.filter((i) => i.name.toLowerCase().includes(q) ||
20
- i.articleNumber.toLowerCase().includes(q));
21
- }, [items, search]);
22
- return (_jsxs("main", { className: "p-6 space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsxs("div", { className: "relative flex-1 min-w-[240px] max-w-md", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), _jsx(Input, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Zoek op product of artikelnummer...", className: "pl-9" })] }), _jsx(ConnectionPicker, { connections: connections, activeId: activeId, onChange: setActiveId, disabled: connLoading }), _jsxs(Button, { variant: "outline", onClick: reload, disabled: loading || !activeId, children: [_jsx(RefreshCw, { className: `mr-2 h-4 w-4 ${loading ? "animate-spin" : ""}` }), "Vernieuwen"] }), _jsx(ExcelExportButton, { items: filtered }), _jsx(Button, { asChild: true, children: _jsxs(Link, { to: "/voorraad/nieuw", children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Artikel toevoegen"] }) })] }), connError && (_jsxs(Card, { className: "border-destructive/40 bg-destructive/5 p-4 text-sm", children: ["Floriday-connecties laden mislukt: ", connError] })), error && (_jsxs(Card, { className: "border-destructive/40 bg-destructive/5 p-4 text-sm", children: ["Voorraad laden mislukt: ", error] })), _jsxs(Card, { className: "overflow-hidden", children: [_jsxs("div", { className: "px-4 py-2 border-b text-xs text-muted-foreground", children: [filtered.length, " producten ", search && `(gefilterd uit ${items.length})`] }), _jsx(VoorraadTable, { items: filtered, loading: loading })] })] }));
17
+ const q = search.trim().toLowerCase();
18
+ return items.filter((i) => {
19
+ if (publishFilter === "published" && !i.published)
20
+ return false;
21
+ if (publishFilter === "local" && i.published)
22
+ return false;
23
+ if (!q)
24
+ return true;
25
+ return (i.name.toLowerCase().includes(q) ||
26
+ (i.articleNumber ?? "").toLowerCase().includes(q));
27
+ });
28
+ }, [items, search, publishFilter]);
29
+ const localCount = items.filter((i) => !i.published).length;
30
+ return (_jsxs("main", { className: "p-6 space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsxs("div", { className: "relative flex-1 min-w-[240px] max-w-md", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), _jsx(Input, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Zoek op product of artikelnummer...", className: "pl-9" })] }), _jsxs(Select, { value: publishFilter, onValueChange: (v) => setPublishFilter(v), children: [_jsx(SelectTrigger, { className: "w-[200px]", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "Alle producten" }), _jsx(SelectItem, { value: "published", children: "Gepubliceerd" }), _jsxs(SelectItem, { value: "local", children: ["Niet gepubliceerd", localCount > 0 ? ` (${localCount})` : ""] })] })] }), _jsx(ConnectionBadge, { connection: activeConnection, loading: connLoading }), _jsxs(Button, { variant: "outline", onClick: reload, disabled: loading || !activeId, children: [_jsx(RefreshCw, { className: `mr-2 h-4 w-4 ${loading ? "animate-spin" : ""}` }), "Vernieuwen"] }), _jsx(ExcelExportButton, { items: filtered }), _jsx(Button, { asChild: true, disabled: !activeId, children: _jsxs(Link, { to: "/voorraad/nieuw", children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Artikel toevoegen"] }) })] }), connError && (_jsxs(Card, { className: "border-destructive/40 bg-destructive/5 p-4 text-sm", children: ["Floriday-connectie laden mislukt: ", connError] })), error && (_jsxs(Card, { className: "border-destructive/40 bg-destructive/5 p-4 text-sm", children: ["Voorraad laden mislukt: ", error] })), _jsxs(Card, { className: "overflow-hidden", children: [_jsxs("div", { className: "px-4 py-2 border-b text-xs text-muted-foreground", children: [filtered.length, " producten ", search && `(gefilterd uit ${items.length})`, " · ", "live data uit gedeelde cache (sync elke 5 min)", localCount > 0 && ` · ${localCount} niet-gepubliceerd`] }), _jsx(VoorraadTable, { items: filtered, loading: loading })] })] }));
23
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAW3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,2CAoEA"}
1
+ {"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAW3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,2CAqGA"}
@@ -1,4 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Link } from "@tanstack/react-router";
3
+ import { Badge } from "@flowselections/core";
2
4
  import { Package } from "lucide-react";
3
5
  const columns = [
4
6
  { key: "quantity", label: "Liggend" },
@@ -16,7 +18,13 @@ export function VoorraadTable({ items, loading, }) {
16
18
  return (_jsx("p", { className: "text-sm text-muted-foreground p-6", children: "Geen producten gevonden voor deze connectie." }));
17
19
  }
18
20
  return (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-muted/50 text-left", children: _jsxs("tr", { children: [_jsx("th", { className: "p-3 w-14" }), _jsx("th", { className: "p-3", children: "Product" }), _jsx("th", { className: "p-3", children: "Artikelnummer" }), columns.map((c) => (_jsx("th", { className: "p-3 text-right whitespace-nowrap", children: c.label }, c.key)))] }) }), _jsx("tbody", { children: items.map((item) => {
19
- const low = item.minQuantity > 0 && item.availableQuantity < item.minQuantity;
20
- return (_jsxs("tr", { className: "border-t hover:bg-muted/30", children: [_jsx("td", { className: "p-2", children: item.imageUrl ? (_jsx("img", { src: item.imageUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [_jsx("div", { className: "font-medium text-foreground", children: item.name }), low && (_jsx("div", { className: "text-xs text-destructive", children: "onder minimumvoorraad" }))] }), _jsx("td", { className: "p-3 font-mono text-xs", children: item.articleNumber }), columns.map((c) => (_jsx("td", { className: "p-3 text-right tabular-nums", children: Number(item[c.key] ?? 0) }, c.key)))] }, item.id));
21
+ const isLocal = !item.published;
22
+ const low = !isLocal &&
23
+ item.minQuantity > 0 &&
24
+ item.availableQuantity < item.minQuantity;
25
+ const nameContent = (_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: isLocal
26
+ ? "font-medium text-foreground hover:underline"
27
+ : "font-medium text-foreground", children: item.name }), isLocal && (_jsx(Badge, { variant: "outline", className: "text-[10px] font-normal text-muted-foreground border-amber-500/40 bg-amber-500/10", children: "Niet gepubliceerd" }))] }));
28
+ return (_jsxs("tr", { className: "border-t hover:bg-muted/30", children: [_jsx("td", { className: "p-2", children: item.imageUrl ? (_jsx("img", { src: item.imageUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [isLocal && item.localId ? (_jsx(Link, { to: "/voorraad/$id", params: { id: item.localId }, children: nameContent })) : (nameContent), low && (_jsx("div", { className: "text-xs text-destructive", children: "onder minimumvoorraad" }))] }), _jsx("td", { className: "p-3 font-mono text-xs", children: item.articleNumber || "—" }), columns.map((c) => (_jsx("td", { className: "p-3 text-right tabular-nums text-muted-foreground", children: isLocal ? "—" : Number(item[c.key] ?? 0) }, c.key)))] }, item.id));
21
29
  }) })] }) }));
22
30
  }
@@ -1,9 +1,14 @@
1
- import { type FloridayConnection } from "../lib/floriday-client";
1
+ import type { FloridayActiveConnection } from "../lib/floriday-client";
2
+ /**
3
+ * Reads the single active Floriday connection for the currently selected
4
+ * environment (staging/live) via the Auth-module's
5
+ * `get_active_floriday_connection_public` RPC. No tokens or secrets are
6
+ * exposed.
7
+ */
2
8
  export declare function useFloridayConnection(): {
3
- connections: FloridayConnection[];
9
+ activeConnection: FloridayActiveConnection | null;
4
10
  activeId: string | null;
5
- setActiveId: (id: string) => void;
6
- activeConnection: FloridayConnection | null;
11
+ environment: string | null;
7
12
  loading: boolean;
8
13
  error: string | null;
9
14
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useFloridayConnection.d.ts","sourceRoot":"","sources":["../../src/hooks/useFloridayConnection.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAI3E,wBAAgB,qBAAqB;;;sBAyBV,MAAM;;;;EAahC"}
1
+ {"version":3,"file":"useFloridayConnection.d.ts","sourceRoot":"","sources":["../../src/hooks/useFloridayConnection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAEvE;;;;;GAKG;AACH,wBAAgB,qBAAqB;;;;;;EA+BpC"}
@@ -1,39 +1,39 @@
1
1
  import { useEffect, useState } from "react";
2
- import { floriday } from "../lib/floriday-client";
3
- const STORAGE_KEY = "voorraad.activeFloridayConnection";
2
+ import { supabase } from "../integrations/supabase/client";
3
+ /**
4
+ * Reads the single active Floriday connection for the currently selected
5
+ * environment (staging/live) via the Auth-module's
6
+ * `get_active_floriday_connection_public` RPC. No tokens or secrets are
7
+ * exposed.
8
+ */
4
9
  export function useFloridayConnection() {
5
- const [connections, setConnections] = useState([]);
6
- const [activeId, setActiveIdState] = useState(null);
10
+ const [activeConnection, setActive] = useState(null);
7
11
  const [loading, setLoading] = useState(true);
8
12
  const [error, setError] = useState(null);
9
13
  useEffect(() => {
10
14
  let mounted = true;
11
- floriday
12
- .listConnections()
13
- .then((rows) => {
15
+ (async () => {
16
+ const { data, error } = await supabase.rpc("get_active_floriday_connection_public");
14
17
  if (!mounted)
15
18
  return;
16
- setConnections(rows);
17
- const stored = typeof window !== "undefined" ? localStorage.getItem(STORAGE_KEY) : null;
18
- const pick = rows.find((r) => r.id === stored) ?? rows[0];
19
- setActiveIdState(pick?.id ?? null);
20
- })
21
- .catch((e) => setError(e.message))
22
- .finally(() => mounted && setLoading(false));
19
+ if (error) {
20
+ setError(error.message);
21
+ setActive(null);
22
+ }
23
+ else {
24
+ const row = (data ?? [])[0];
25
+ setActive(row && row.id ? row : null);
26
+ }
27
+ setLoading(false);
28
+ })();
23
29
  return () => {
24
30
  mounted = false;
25
31
  };
26
32
  }, []);
27
- const setActiveId = (id) => {
28
- setActiveIdState(id);
29
- if (typeof window !== "undefined")
30
- localStorage.setItem(STORAGE_KEY, id);
31
- };
32
33
  return {
33
- connections,
34
- activeId,
35
- setActiveId,
36
- activeConnection: connections.find((c) => c.id === activeId) ?? null,
34
+ activeConnection,
35
+ activeId: activeConnection?.id ?? null,
36
+ environment: activeConnection?.active_environment ?? null,
37
37
  loading,
38
38
  error,
39
39
  };
@@ -0,0 +1,17 @@
1
+ export interface FloridayCustomer {
2
+ id: string;
3
+ name: string;
4
+ hasRealName: boolean;
5
+ }
6
+ /**
7
+ * Reads buyer organisations from the shared `floriday_connections_cache`
8
+ * (which contains buyer org id + name per supplier connection).
9
+ * If `buyer_organization_name` is NULL (Auth-module hasn't synced names yet),
10
+ * we fall back to a short, readable label so the UI never shows a raw UUID.
11
+ */
12
+ export declare function useFlorydayCustomers(connectionId: string | null): {
13
+ customers: FloridayCustomer[];
14
+ loading: boolean;
15
+ error: string | null;
16
+ };
17
+ //# sourceMappingURL=useFlorydayCustomers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFlorydayCustomers.d.ts","sourceRoot":"","sources":["../../src/hooks/useFlorydayCustomers.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB;AAMD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;EAoD/D"}
@@ -0,0 +1,65 @@
1
+ import { useEffect, useState } from "react";
2
+ import { supabase } from "../integrations/supabase/client";
3
+ function shortId(id) {
4
+ return `Klant ${id.slice(0, 8)}…${id.slice(-4)}`;
5
+ }
6
+ /**
7
+ * Reads buyer organisations from the shared `floriday_connections_cache`
8
+ * (which contains buyer org id + name per supplier connection).
9
+ * If `buyer_organization_name` is NULL (Auth-module hasn't synced names yet),
10
+ * we fall back to a short, readable label so the UI never shows a raw UUID.
11
+ */
12
+ export function useFlorydayCustomers(connectionId) {
13
+ const [customers, setCustomers] = useState([]);
14
+ const [loading, setLoading] = useState(false);
15
+ const [error, setError] = useState(null);
16
+ useEffect(() => {
17
+ let mounted = true;
18
+ if (!connectionId) {
19
+ setCustomers([]);
20
+ return;
21
+ }
22
+ setLoading(true);
23
+ setError(null);
24
+ supabase
25
+ .from("floriday_connections_cache")
26
+ .select("buyer_organization_id,buyer_organization_name")
27
+ .eq("connection_id", connectionId)
28
+ .eq("is_deleted", false)
29
+ .then(({ data, error }) => {
30
+ if (!mounted)
31
+ return;
32
+ if (error) {
33
+ setError(error.message);
34
+ setCustomers([]);
35
+ return;
36
+ }
37
+ const seen = new Set();
38
+ const out = [];
39
+ for (const row of data ?? []) {
40
+ const id = row.buyer_organization_id;
41
+ if (!id || seen.has(id))
42
+ continue;
43
+ seen.add(id);
44
+ const real = (row.buyer_organization_name ?? "").trim();
45
+ out.push({
46
+ id,
47
+ name: real.length > 0 ? real : shortId(id),
48
+ hasRealName: real.length > 0,
49
+ });
50
+ }
51
+ // Real names first (alphabetical), then fallback labels.
52
+ out.sort((a, b) => {
53
+ if (a.hasRealName !== b.hasRealName)
54
+ return a.hasRealName ? -1 : 1;
55
+ return a.name.localeCompare(b.name);
56
+ });
57
+ setCustomers(out);
58
+ })
59
+ .then(() => mounted && setLoading(false));
60
+ return () => {
61
+ mounted = false;
62
+ };
63
+ }, [connectionId]);
64
+ return { customers, loading, error };
65
+ }
@@ -0,0 +1,22 @@
1
+ import type { WizardData } from "../lib/floriday-payload";
2
+ import type { TradeItem } from "../lib/floriday-client";
3
+ export interface LocalTradeItemRow {
4
+ id: string;
5
+ connection_id: string | null;
6
+ data: WizardData;
7
+ updated_at: string;
8
+ created_at: string;
9
+ }
10
+ export declare function useLocalTradeItems(connectionId: string | null): {
11
+ items: TradeItem[];
12
+ loading: boolean;
13
+ reload: () => Promise<void>;
14
+ };
15
+ export declare function getLocalTradeItem(id: string): Promise<LocalTradeItemRow | null>;
16
+ export declare function upsertLocalTradeItem(params: {
17
+ id?: string;
18
+ connectionId: string;
19
+ data: WizardData;
20
+ }): Promise<string>;
21
+ export declare function deleteLocalTradeItem(id: string): Promise<void>;
22
+ //# sourceMappingURL=useLocalTradeItems.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLocalTradeItems.d.ts","sourceRoot":"","sources":["../../src/hooks/useLocalTradeItems.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAwBD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;EA+B7D;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAQrF;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BlB;AAED,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE"}
@@ -0,0 +1,100 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { supabase } from "../integrations/supabase/client";
3
+ function draftToTradeItem(row) {
4
+ const d = row.data ?? {};
5
+ const firstImage = Array.isArray(d.images) && d.images.length > 0 ? d.images[0] : null;
6
+ const imageUrl = (firstImage && (firstImage.url || firstImage.previewUrl)) ?? null;
7
+ return {
8
+ id: `local:${row.id}`,
9
+ localId: row.id,
10
+ name: d.name || d.vbnName || "(naamloos)",
11
+ articleNumber: d.articleCode || d.gtin || "",
12
+ imageUrl,
13
+ quantity: 0,
14
+ minQuantity: 0,
15
+ reservedQuantity: 0,
16
+ availableQuantity: 0,
17
+ incomingQuantity: 0,
18
+ economicQuantity: 0,
19
+ raw: row,
20
+ published: false,
21
+ };
22
+ }
23
+ export function useLocalTradeItems(connectionId) {
24
+ const [items, setItems] = useState([]);
25
+ const [loading, setLoading] = useState(false);
26
+ const load = useCallback(async () => {
27
+ if (!connectionId) {
28
+ setItems([]);
29
+ return;
30
+ }
31
+ setLoading(true);
32
+ try {
33
+ const { data, error } = await supabase
34
+ .from("trade_item_drafts")
35
+ .select("id,connection_id,data,updated_at,created_at")
36
+ .eq("connection_id", connectionId)
37
+ .order("updated_at", { ascending: false })
38
+ .limit(1000);
39
+ if (error)
40
+ throw error;
41
+ setItems((data ?? []).map((r) => draftToTradeItem(r)));
42
+ }
43
+ catch {
44
+ setItems([]);
45
+ }
46
+ finally {
47
+ setLoading(false);
48
+ }
49
+ }, [connectionId]);
50
+ useEffect(() => {
51
+ load();
52
+ }, [load]);
53
+ return { items, loading, reload: load };
54
+ }
55
+ export async function getLocalTradeItem(id) {
56
+ const { data, error } = await supabase
57
+ .from("trade_item_drafts")
58
+ .select("id,connection_id,data,updated_at,created_at")
59
+ .eq("id", id)
60
+ .maybeSingle();
61
+ if (error)
62
+ throw new Error(error.message);
63
+ return data ?? null;
64
+ }
65
+ export async function upsertLocalTradeItem(params) {
66
+ const userRes = await supabase.auth.getUser();
67
+ const userId = userRes.data.user?.id;
68
+ if (!userId)
69
+ throw new Error("Niet ingelogd");
70
+ if (params.id) {
71
+ const { error } = await supabase
72
+ .from("trade_item_drafts")
73
+ .update({
74
+ data: params.data,
75
+ connection_id: params.connectionId,
76
+ updated_at: new Date().toISOString(),
77
+ })
78
+ .eq("id", params.id);
79
+ if (error)
80
+ throw new Error(error.message);
81
+ return params.id;
82
+ }
83
+ const { data, error } = await supabase
84
+ .from("trade_item_drafts")
85
+ .insert({
86
+ user_id: userId,
87
+ connection_id: params.connectionId,
88
+ data: params.data,
89
+ })
90
+ .select("id")
91
+ .single();
92
+ if (error)
93
+ throw new Error(error.message);
94
+ return data.id;
95
+ }
96
+ export async function deleteLocalTradeItem(id) {
97
+ const { error } = await supabase.from("trade_item_drafts").delete().eq("id", id);
98
+ if (error)
99
+ throw new Error(error.message);
100
+ }
@@ -1,4 +1,9 @@
1
1
  import { type TradeItem } from "../lib/floriday-client";
2
+ /**
3
+ * Reads trade items from the shared `floriday_trade_items_cache` (gepubliceerd,
4
+ * gevuld door de Auth-module elke 5 min) en merget lokale, niet-gepubliceerde
5
+ * producten uit `trade_item_drafts`.
6
+ */
2
7
  export declare function useVoorraadData(connectionId: string | null): {
3
8
  items: TradeItem[];
4
9
  loading: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"useVoorraadData.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoorraadData.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAElE,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;;EA4B1D"}
1
+ {"version":3,"file":"useVoorraadData.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoorraadData.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAG5E;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;;EAqD1D"}
@@ -1,30 +1,57 @@
1
1
  import { useCallback, useEffect, useState } from "react";
2
- import { floriday } from "../lib/floriday-client";
2
+ import { supabase } from "../integrations/supabase/client";
3
+ import { normaliseTradeItem } from "../lib/floriday-client";
4
+ import { useLocalTradeItems } from "./useLocalTradeItems";
5
+ /**
6
+ * Reads trade items from the shared `floriday_trade_items_cache` (gepubliceerd,
7
+ * gevuld door de Auth-module elke 5 min) en merget lokale, niet-gepubliceerde
8
+ * producten uit `trade_item_drafts`.
9
+ */
3
10
  export function useVoorraadData(connectionId) {
4
- const [items, setItems] = useState([]);
11
+ const [publishedItems, setPublishedItems] = useState([]);
5
12
  const [loading, setLoading] = useState(false);
6
13
  const [error, setError] = useState(null);
7
- const load = useCallback(async () => {
14
+ const { items: localItems, loading: localLoading, reload: reloadLocal, } = useLocalTradeItems(connectionId);
15
+ const loadPublished = useCallback(async () => {
8
16
  if (!connectionId) {
9
- setItems([]);
17
+ setPublishedItems([]);
10
18
  return;
11
19
  }
12
20
  setLoading(true);
13
21
  setError(null);
14
22
  try {
15
- const data = await floriday.listTradeItems(connectionId);
16
- setItems(data);
23
+ const { data, error } = await supabase
24
+ .from("floriday_trade_items_cache")
25
+ .select("data,floriday_id,is_deleted")
26
+ .eq("connection_id", connectionId)
27
+ .eq("is_deleted", false)
28
+ .limit(1000);
29
+ if (error)
30
+ throw error;
31
+ const normalised = (data ?? [])
32
+ .map((row) => normaliseTradeItem({ ...row.data, id: row.floriday_id }))
33
+ .filter((i) => i.id)
34
+ .map((i) => ({ ...i, published: true }));
35
+ setPublishedItems(normalised);
17
36
  }
18
37
  catch (e) {
19
38
  setError(e.message);
20
- setItems([]);
39
+ setPublishedItems([]);
21
40
  }
22
41
  finally {
23
42
  setLoading(false);
24
43
  }
25
44
  }, [connectionId]);
26
45
  useEffect(() => {
27
- load();
28
- }, [load]);
29
- return { items, loading, error, reload: load };
46
+ loadPublished();
47
+ }, [loadPublished]);
48
+ const reload = useCallback(async () => {
49
+ await Promise.all([loadPublished(), reloadLocal()]);
50
+ }, [loadPublished, reloadLocal]);
51
+ return {
52
+ items: [...localItems, ...publishedItems],
53
+ loading: loading || localLoading,
54
+ error,
55
+ reload,
56
+ };
30
57
  }
@@ -1,5 +1,5 @@
1
1
  import type { FlowModule } from "@flowselections/core";
2
2
  export * from './_core-safelist';
3
3
  export { VoorraadPage } from './components/voorraad/VoorraadPage';
4
- export declare const myModule: FlowModule;
4
+ export declare const floridayVoorraadModule: FlowModule;
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -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;AAIlE,eAAO,MAAM,QAAQ,EAAE,UAYtB,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;AAIlE,eAAO,MAAM,sBAAsB,EAAE,UAYpC,CAAC"}
package/dist-lib/index.js CHANGED
@@ -5,7 +5,7 @@ import { Package } from "lucide-react";
5
5
  export * from './_core-safelist';
6
6
  export { VoorraadPage } from './components/voorraad/VoorraadPage';
7
7
  import { VoorraadSettingsCard } from "./components/settings/VoorraadSettingsCard";
8
- export const myModule = {
8
+ export const floridayVoorraadModule = {
9
9
  id: "voorraad",
10
10
  name: "Voorraad",
11
11
  version: "1.0.0",