@flowselections/floriday-voorraad 1.0.12 → 1.0.14

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 (123) hide show
  1. package/dist-lib/assets/floriday-logo.png.asset.json +11 -0
  2. package/dist-lib/components/voorraad/ArtikelWizard.d.ts +5 -0
  3. package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -0
  4. package/dist-lib/components/voorraad/ArtikelWizard.js +1229 -0
  5. package/dist-lib/components/voorraad/ConnectionBadge.d.ts +6 -0
  6. package/dist-lib/components/voorraad/ConnectionBadge.d.ts.map +1 -0
  7. package/dist-lib/components/voorraad/ConnectionBadge.js +12 -0
  8. package/dist-lib/components/voorraad/EditArtikelPage.d.ts +4 -0
  9. package/dist-lib/components/voorraad/EditArtikelPage.d.ts.map +1 -0
  10. package/dist-lib/components/voorraad/EditArtikelPage.js +51 -0
  11. package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts +2 -0
  12. package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts.map +1 -0
  13. package/dist-lib/components/voorraad/NieuwArtikelPage.js +5 -0
  14. package/dist-lib/components/voorraad/StockBulkButtons.d.ts +7 -0
  15. package/dist-lib/components/voorraad/StockBulkButtons.d.ts.map +1 -0
  16. package/dist-lib/components/voorraad/StockBulkButtons.js +356 -0
  17. package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts +7 -0
  18. package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts.map +1 -0
  19. package/dist-lib/components/voorraad/ValidationOverviewTable.js +87 -0
  20. package/dist-lib/components/voorraad/ValidationPage.d.ts +2 -0
  21. package/dist-lib/components/voorraad/ValidationPage.d.ts.map +1 -0
  22. package/dist-lib/components/voorraad/ValidationPage.js +12 -0
  23. package/dist-lib/components/voorraad/VoorraadDashboard.d.ts +6 -0
  24. package/dist-lib/components/voorraad/VoorraadDashboard.d.ts.map +1 -0
  25. package/dist-lib/components/voorraad/VoorraadDashboard.js +42 -0
  26. package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
  27. package/dist-lib/components/voorraad/VoorraadPage.js +78 -11
  28. package/dist-lib/components/voorraad/VoorraadPagination.d.ts +10 -0
  29. package/dist-lib/components/voorraad/VoorraadPagination.d.ts.map +1 -0
  30. package/dist-lib/components/voorraad/VoorraadPagination.js +12 -0
  31. package/dist-lib/components/voorraad/VoorraadStockCard.d.ts +8 -0
  32. package/dist-lib/components/voorraad/VoorraadStockCard.d.ts.map +1 -0
  33. package/dist-lib/components/voorraad/VoorraadStockCard.js +33 -0
  34. package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
  35. package/dist-lib/components/voorraad/VoorraadTable.js +21 -2
  36. package/dist-lib/hooks/useFloriday.d.ts +55 -0
  37. package/dist-lib/hooks/useFloriday.d.ts.map +1 -0
  38. package/dist-lib/hooks/useFloriday.js +298 -0
  39. package/dist-lib/hooks/useFloridayConnection.d.ts +9 -4
  40. package/dist-lib/hooks/useFloridayConnection.d.ts.map +1 -1
  41. package/dist-lib/hooks/useFloridayConnection.js +23 -23
  42. package/dist-lib/hooks/useFlorydayCustomers.d.ts +17 -0
  43. package/dist-lib/hooks/useFlorydayCustomers.d.ts.map +1 -0
  44. package/dist-lib/hooks/useFlorydayCustomers.js +65 -0
  45. package/dist-lib/hooks/useLocalTradeItems.d.ts +38 -0
  46. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -0
  47. package/dist-lib/hooks/useLocalTradeItems.js +144 -0
  48. package/dist-lib/hooks/useTradeItemSpec.d.ts +42 -0
  49. package/dist-lib/hooks/useTradeItemSpec.d.ts.map +1 -0
  50. package/dist-lib/hooks/useTradeItemSpec.js +448 -0
  51. package/dist-lib/hooks/useTradeItemStock.d.ts +19 -0
  52. package/dist-lib/hooks/useTradeItemStock.d.ts.map +1 -0
  53. package/dist-lib/hooks/useTradeItemStock.js +78 -0
  54. package/dist-lib/hooks/useVbnRegulatoryFeatures.d.ts +3 -0
  55. package/dist-lib/hooks/useVbnRegulatoryFeatures.d.ts.map +1 -0
  56. package/dist-lib/hooks/useVbnRegulatoryFeatures.js +19 -0
  57. package/dist-lib/hooks/useVoorraadData.d.ts +6 -0
  58. package/dist-lib/hooks/useVoorraadData.d.ts.map +1 -1
  59. package/dist-lib/hooks/useVoorraadData.js +65 -10
  60. package/dist-lib/index.d.ts +4 -0
  61. package/dist-lib/index.d.ts.map +1 -1
  62. package/dist-lib/index.js +6 -5
  63. package/dist-lib/integrations/supabase/auth-middleware.d.ts +9085 -1645
  64. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  65. package/dist-lib/integrations/supabase/client.d.ts +9085 -1645
  66. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  67. package/dist-lib/integrations/supabase/client.server.d.ts +9085 -1645
  68. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  69. package/dist-lib/integrations/supabase/types.d.ts +9298 -1655
  70. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  71. package/dist-lib/integrations/supabase/types.js +20 -1
  72. package/dist-lib/lib/__tests__/floricode-required-features.test.d.ts +2 -0
  73. package/dist-lib/lib/__tests__/floricode-required-features.test.d.ts.map +1 -0
  74. package/dist-lib/lib/__tests__/floricode-required-features.test.js +186 -0
  75. package/dist-lib/lib/floricode-client.d.ts +15 -1
  76. package/dist-lib/lib/floricode-client.d.ts.map +1 -1
  77. package/dist-lib/lib/floricode-client.js +42 -4
  78. package/dist-lib/lib/floricode-required-features.functions.d.ts +10026 -0
  79. package/dist-lib/lib/floricode-required-features.functions.d.ts.map +1 -0
  80. package/dist-lib/lib/floricode-required-features.functions.js +170 -0
  81. package/dist-lib/lib/floriday-client.d.ts +45 -19
  82. package/dist-lib/lib/floriday-client.d.ts.map +1 -1
  83. package/dist-lib/lib/floriday-client.js +236 -38
  84. package/dist-lib/lib/floriday-env.d.ts +29 -0
  85. package/dist-lib/lib/floriday-env.d.ts.map +1 -0
  86. package/dist-lib/lib/floriday-env.js +42 -0
  87. package/dist-lib/lib/floriday-env.server.d.ts +15 -0
  88. package/dist-lib/lib/floriday-env.server.d.ts.map +1 -0
  89. package/dist-lib/lib/floriday-env.server.js +13 -0
  90. package/dist-lib/lib/floriday-field-sources.d.ts +18 -0
  91. package/dist-lib/lib/floriday-field-sources.d.ts.map +1 -0
  92. package/dist-lib/lib/floriday-field-sources.js +45 -0
  93. package/dist-lib/lib/floriday-gateway-entities.d.ts +44 -0
  94. package/dist-lib/lib/floriday-gateway-entities.d.ts.map +1 -0
  95. package/dist-lib/lib/floriday-gateway-entities.js +51 -0
  96. package/dist-lib/lib/floriday-gateway.functions.d.ts +39999 -0
  97. package/dist-lib/lib/floriday-gateway.functions.d.ts.map +1 -0
  98. package/dist-lib/lib/floriday-gateway.functions.js +68 -0
  99. package/dist-lib/lib/floriday-gateway.server.d.ts +122 -0
  100. package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -0
  101. package/dist-lib/lib/floriday-gateway.server.js +230 -0
  102. package/dist-lib/lib/floriday-import-validator.d.ts +26 -0
  103. package/dist-lib/lib/floriday-import-validator.d.ts.map +1 -0
  104. package/dist-lib/lib/floriday-import-validator.js +41 -0
  105. package/dist-lib/lib/floriday-payload.d.ts +47 -3
  106. package/dist-lib/lib/floriday-payload.d.ts.map +1 -1
  107. package/dist-lib/lib/floriday-payload.js +179 -7
  108. package/dist-lib/lib/floriday-schema-to-zod.d.ts +9 -0
  109. package/dist-lib/lib/floriday-schema-to-zod.d.ts.map +1 -0
  110. package/dist-lib/lib/floriday-schema-to-zod.js +53 -0
  111. package/dist-lib/lib/floriday-writes.functions.d.ts +19998 -0
  112. package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -0
  113. package/dist-lib/lib/floriday-writes.functions.js +74 -0
  114. package/dist-lib/lib/image-resize.d.ts +43 -0
  115. package/dist-lib/lib/image-resize.d.ts.map +1 -0
  116. package/dist-lib/lib/image-resize.js +212 -0
  117. package/dist-lib/lib/normalize-errors-middleware.d.ts +2 -0
  118. package/dist-lib/lib/normalize-errors-middleware.d.ts.map +1 -0
  119. package/dist-lib/lib/normalize-errors-middleware.js +24 -0
  120. package/dist-lib/lib/wizard-step-fields.d.ts +15 -0
  121. package/dist-lib/lib/wizard-step-fields.d.ts.map +1 -0
  122. package/dist-lib/lib/wizard-step-fields.js +51 -0
  123. package/package.json +29 -14
@@ -0,0 +1,298 @@
1
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
2
+ import { useEffect } from "react";
3
+ import { gatewaySchemaFn, gatewayCodeListFn, gatewayCachedListFn, } from "../lib/floriday-gateway.functions";
4
+ import { unmappedRequiredFields } from "../lib/wizard-step-fields";
5
+ import { useFloridayConnection } from "./useFloridayConnection";
6
+ import { normalizeFloridayEnvironment } from "../lib/floriday-env";
7
+ function isRecord(value) {
8
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9
+ }
10
+ function arrayFromCodeListValue(value) {
11
+ if (Array.isArray(value))
12
+ return value;
13
+ if (!isRecord(value))
14
+ return [];
15
+ const candidates = [
16
+ value.values,
17
+ value.items,
18
+ value.rows,
19
+ value.data,
20
+ value.payload,
21
+ value.entries,
22
+ ];
23
+ for (const c of candidates) {
24
+ if (Array.isArray(c))
25
+ return c;
26
+ }
27
+ // Sommige gateway-implementaties geven een codelijst als dictionary terug:
28
+ // { "S62": { description: "..." }, "S98": "..." }. Maak daar alsnog
29
+ // entries van. Een object dat zelf één entry is (heeft code/id/value) laten
30
+ // we ongemoeid om dubbele parsing te voorkomen.
31
+ if (value.code != null || value.id != null || value.value != null)
32
+ return [value];
33
+ return Object.entries(value).map(([code, entry]) => isRecord(entry) ? { code, ...entry } : { code, label: entry });
34
+ }
35
+ function canonicalCodeListName(name) {
36
+ const kebab = name
37
+ .trim()
38
+ .replace(/_/g, "-")
39
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
40
+ .toLowerCase();
41
+ const aliases = {
42
+ vbnproductgroup: "vbn-product-group",
43
+ "vbn-productgroup": "vbn-product-group",
44
+ "vbn-product-groups": "vbn-product-group",
45
+ characteristics: "characteristic",
46
+ "characteristic-type": "characteristic",
47
+ "characteristic-types": "characteristic",
48
+ packagingtype: "packaging-type",
49
+ countryoforigin: "country-of-origin",
50
+ lengthunit: "length-unit",
51
+ };
52
+ return aliases[kebab] ?? aliases[kebab.replace(/-/g, "")] ?? kebab;
53
+ }
54
+ function pickCode(value) {
55
+ if (!isRecord(value))
56
+ return String(value ?? "").trim();
57
+ const payload = isRecord(value.payload) ? value.payload : isRecord(value.data) ? value.data : undefined;
58
+ const raw = value.code ??
59
+ value.id ??
60
+ value.value ??
61
+ value.vbnProductCode ??
62
+ value.productCode ??
63
+ value.vbnCode ??
64
+ value.record_id ??
65
+ payload?.code ??
66
+ payload?.id ??
67
+ payload?.vbnProductCode ??
68
+ payload?.productCode ??
69
+ payload?.vbnCode ??
70
+ payload?.record_id;
71
+ return String(raw ?? "").trim();
72
+ }
73
+ function pickLabel(value, code) {
74
+ if (!isRecord(value))
75
+ return code || String(value ?? "").trim() || null;
76
+ const payload = isRecord(value.payload) ? value.payload : isRecord(value.data) ? value.data : undefined;
77
+ const raw = value.label ??
78
+ value.description ??
79
+ value.name ??
80
+ value.displayName ??
81
+ value.title ??
82
+ payload?.label ??
83
+ payload?.description ??
84
+ payload?.name ??
85
+ payload?.displayName ??
86
+ payload?.title;
87
+ return raw == null ? (code || null) : String(raw);
88
+ }
89
+ function normalizeCodeListEntries(value) {
90
+ return arrayFromCodeListValue(value)
91
+ .map((entry) => {
92
+ const code = pickCode(entry);
93
+ if (!code)
94
+ return null;
95
+ const label = pickLabel(entry, code);
96
+ const payload = isRecord(entry)
97
+ ? entry.payload ?? entry.data ?? entry
98
+ : entry;
99
+ return { code, label, description: label, payload };
100
+ })
101
+ .filter(Boolean);
102
+ }
103
+ function normalizeCodeLists(raw) {
104
+ const root = isRecord(raw) ? raw : {};
105
+ const data = isRecord(root.data) ? root.data : undefined;
106
+ const payload = isRecord(root.payload) ? root.payload : undefined;
107
+ const result = isRecord(root.result) ? root.result : undefined;
108
+ const included = isRecord(root.included) ? root.included : undefined;
109
+ const containers = [
110
+ root.codeLists,
111
+ root.code_lists,
112
+ root.includedCodeLists,
113
+ root.included_code_lists,
114
+ data?.codeLists,
115
+ data?.code_lists,
116
+ data?.includedCodeLists,
117
+ data?.included_code_lists,
118
+ isRecord(data?.payload) ? data?.payload?.codeLists ?? data?.payload?.code_lists : undefined,
119
+ payload?.codeLists,
120
+ payload?.code_lists,
121
+ result?.codeLists,
122
+ result?.code_lists,
123
+ included?.codeLists,
124
+ included?.code_lists,
125
+ ];
126
+ const out = {};
127
+ for (const container of containers) {
128
+ if (Array.isArray(container)) {
129
+ for (const list of container) {
130
+ if (!isRecord(list))
131
+ continue;
132
+ const name = canonicalCodeListName(String(list.name ?? list.listName ?? list.key ?? list.resource ?? ""));
133
+ if (!name)
134
+ continue;
135
+ const entries = normalizeCodeListEntries(list.values ?? list.items ?? list.rows ?? list.data ?? list.payload);
136
+ if (entries.length)
137
+ out[name] = entries;
138
+ }
139
+ continue;
140
+ }
141
+ if (!isRecord(container))
142
+ continue;
143
+ for (const [name, value] of Object.entries(container)) {
144
+ const canonicalName = canonicalCodeListName(name);
145
+ const entries = normalizeCodeListEntries(value);
146
+ if (entries.length)
147
+ out[canonicalName] = entries;
148
+ }
149
+ }
150
+ return Object.keys(out).length ? out : undefined;
151
+ }
152
+ function normalizeSchemaResponse(raw) {
153
+ const root = isRecord(raw) ? raw : {};
154
+ const data = isRecord(root.data) ? root.data : undefined;
155
+ const payload = isRecord(root.payload) ? root.payload : undefined;
156
+ const source = data && (data.fields || data.requiredFields || data.schema || data.enums || data.codeLists || data.code_lists)
157
+ ? data
158
+ : payload && (payload.fields || payload.requiredFields || payload.schema || payload.enums || payload.codeLists || payload.code_lists)
159
+ ? payload
160
+ : root;
161
+ const rawSchema = source.schema ?? source.jsonSchema ?? source.openApiSchema ?? source.swaggerSchema;
162
+ const codeLists = normalizeCodeLists(raw);
163
+ return {
164
+ ...source,
165
+ ok: Boolean(root.ok ?? source.ok),
166
+ resource: String(source.resource ?? root.resource ?? "trade-item"),
167
+ version: String(source.version ?? root.version ?? ""),
168
+ requiredFields: Array.isArray(source.requiredFields)
169
+ ? source.requiredFields.map(String)
170
+ : Array.isArray(source.required)
171
+ ? source.required.map(String)
172
+ : [],
173
+ fields: Array.isArray(source.fields) ? source.fields : [],
174
+ enums: isRecord(source.enums) ? source.enums : undefined,
175
+ schema: rawSchema,
176
+ codeLists,
177
+ };
178
+ }
179
+ /**
180
+ * Cache-segment per environment zodat een latere live/staging-switch geen
181
+ * stale data uit de andere environment toont. De server resolved de echte
182
+ * environment uit de actieve connectie; deze key is puur voor de query-cache.
183
+ */
184
+ function useEnvKey() {
185
+ const { environment } = useFloridayConnection();
186
+ try {
187
+ return environment ? normalizeFloridayEnvironment(environment) : "unknown";
188
+ }
189
+ catch {
190
+ return "unknown";
191
+ }
192
+ }
193
+ export function useFloridaySchema(resource, params) {
194
+ const envKey = useEnvKey();
195
+ const paramsKey = params ? JSON.stringify(params) : "";
196
+ const q = useQuery({
197
+ queryKey: ["floriday-schema", resource, paramsKey, envKey],
198
+ queryFn: async () => (await gatewaySchemaFn({
199
+ data: { resource, ...(params ?? {}) },
200
+ })),
201
+ staleTime: 60 * 60 * 1000,
202
+ });
203
+ useEffect(() => {
204
+ if (!q.data?.requiredFields)
205
+ return;
206
+ const missing = unmappedRequiredFields(q.data.requiredFields);
207
+ if (missing.length && import.meta.env.DEV) {
208
+ console.warn(`[floriday-schema] ${resource}: required fields zonder step-mapping:`, missing);
209
+ }
210
+ }, [q.data?.requiredFields, resource]);
211
+ return q;
212
+ }
213
+ /**
214
+ * §15.2 — één HMAC-call die het `trade-item`-schema én alle voor het
215
+ * "Nieuw artikel"-formulier benodigde code-lists meelevert. Vervangt een
216
+ * losse `useFloridaySchema("trade-item")` + meerdere `useCodeList(...)`
217
+ * round-trips bij wizard-open.
218
+ *
219
+ * Fail-closed: gooit als de gateway geen `ok: true` teruggeeft.
220
+ */
221
+ const TRADE_ITEM_INCLUDE_CODE_LISTS = [
222
+ "vbn-product-group",
223
+ "vbn-product-code",
224
+ "vbn-characteristic",
225
+ "vbn-characteristic-value",
226
+ "characteristic",
227
+ "packaging-type",
228
+ "country-of-origin",
229
+ "length-unit",
230
+ ];
231
+ export function useTradeItemFormSchema() {
232
+ const envKey = useEnvKey();
233
+ const q = useQuery({
234
+ queryKey: ["floriday-trade-item-schema", envKey],
235
+ queryFn: async () => {
236
+ const raw = await gatewaySchemaFn({
237
+ data: {
238
+ resource: "trade-item",
239
+ environment: envKey === "live" ? "live" : "staging",
240
+ includeCodeLists: [...TRADE_ITEM_INCLUDE_CODE_LISTS],
241
+ },
242
+ });
243
+ const res = normalizeSchemaResponse(raw);
244
+ if (!res || res.ok !== true) {
245
+ throw new Error(res?.error ??
246
+ "Floriday trade-item schema niet beschikbaar (gateway gaf geen ok=true terug)");
247
+ }
248
+ const vbnList = res.codeLists?.["vbn-product-group"] ?? [];
249
+ if (vbnList.length === 0) {
250
+ throw new Error("Floriday schema-call is incompleet: codeLists['vbn-product-group'] ontbreekt. Daardoor kunnen VBN-specifieke karakteristieken niet betrouwbaar worden bepaald.");
251
+ }
252
+ return res;
253
+ },
254
+ staleTime: 60 * 60 * 1000,
255
+ });
256
+ useEffect(() => {
257
+ if (!q.data?.requiredFields)
258
+ return;
259
+ const missing = unmappedRequiredFields(q.data.requiredFields);
260
+ if (missing.length && import.meta.env.DEV) {
261
+ console.warn(`[floriday-schema] trade-item: required fields zonder step-mapping:`, missing);
262
+ }
263
+ }, [q.data?.requiredFields]);
264
+ return q;
265
+ }
266
+ export function useCodeList(listName) {
267
+ const envKey = useEnvKey();
268
+ return useQuery({
269
+ queryKey: ["floriday-code-list", listName ?? "", envKey],
270
+ queryFn: async () => (await gatewayCodeListFn({ data: { listName: listName } })),
271
+ staleTime: 60 * 60 * 1000,
272
+ enabled: Boolean(listName),
273
+ });
274
+ }
275
+ export function useCachedList(entity, limit = 1000) {
276
+ const envKey = useEnvKey();
277
+ return useQuery({
278
+ queryKey: ["floriday-cached-list", entity ?? "", limit, envKey],
279
+ queryFn: async () => (await gatewayCachedListFn({ data: { entity: entity, limit } })),
280
+ staleTime: 5 * 60 * 1000,
281
+ enabled: Boolean(entity),
282
+ });
283
+ }
284
+ /**
285
+ * Invalideert alle floriday-* queries wanneer de actieve connectie
286
+ * (en dus mogelijk de environment) wijzigt. Voorkomt cache-bleed
287
+ * tussen staging en live bij een toekomstige switcher.
288
+ */
289
+ export function useInvalidateFloridayOnConnectionChange() {
290
+ const { activeId, environment } = useFloridayConnection();
291
+ const qc = useQueryClient();
292
+ useEffect(() => {
293
+ qc.invalidateQueries({ queryKey: ["floriday-cached-list"] });
294
+ qc.invalidateQueries({ queryKey: ["floriday-code-list"] });
295
+ qc.invalidateQueries({ queryKey: ["floriday-schema"] });
296
+ qc.invalidateQueries({ queryKey: ["floriday-trade-item-schema"] });
297
+ }, [activeId, environment, qc]);
298
+ }
@@ -1,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,38 @@
1
+ import type { WizardData } from "../lib/floriday-payload";
2
+ import type { FloridayLinkStatus, 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
+ floriday_link_status?: FloridayLinkStatus;
10
+ floriday_id?: string | null;
11
+ floriday_link_error?: string | null;
12
+ missing_required_fields?: string[] | null;
13
+ last_floriday_sync_at?: string | null;
14
+ source?: string | null;
15
+ }
16
+ export declare function useLocalTradeItems(connectionId: string | null): {
17
+ items: TradeItem[];
18
+ loading: boolean;
19
+ reload: () => Promise<void>;
20
+ };
21
+ export declare function getLocalTradeItem(id: string): Promise<LocalTradeItemRow | null>;
22
+ export interface DraftMeta {
23
+ floridayLinkStatus?: FloridayLinkStatus;
24
+ floridayId?: string | null;
25
+ floridayLinkError?: string | null;
26
+ missingRequiredFields?: string[];
27
+ lastFloridaySyncAt?: string | null;
28
+ source?: "manual" | "excel_import";
29
+ }
30
+ export declare function upsertLocalTradeItem(params: {
31
+ id?: string;
32
+ connectionId: string;
33
+ data: WizardData;
34
+ meta?: DraftMeta;
35
+ }): Promise<string>;
36
+ export declare function updateDraftMeta(id: string, meta: DraftMeta): Promise<void>;
37
+ export declare function deleteLocalTradeItem(id: string): Promise<void>;
38
+ //# 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,kBAAkB,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAE5E,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uBAAuB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAgCD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;EA+B7D;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAQrF;AAED,MAAM,WAAW,SAAS;IACxB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,CAAC;CACpC;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2ClB;AAED,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhF;AAED,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE"}
@@ -0,0 +1,144 @@
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
+ linkStatus: row.floriday_link_status ?? "unlinked",
22
+ missingFields: row.missing_required_fields ?? [],
23
+ linkError: row.floriday_link_error ?? null,
24
+ lastSyncAt: row.last_floriday_sync_at ?? null,
25
+ floridayId: row.floriday_id ?? null,
26
+ };
27
+ }
28
+ const SELECT_COLS = "id,connection_id,data,updated_at,created_at,floriday_link_status,floriday_id,floriday_link_error,missing_required_fields,last_floriday_sync_at,source";
29
+ export function useLocalTradeItems(connectionId) {
30
+ const [items, setItems] = useState([]);
31
+ const [loading, setLoading] = useState(false);
32
+ const load = useCallback(async () => {
33
+ if (!connectionId) {
34
+ setItems([]);
35
+ return;
36
+ }
37
+ setLoading(true);
38
+ try {
39
+ const { data, error } = await supabase
40
+ .from("trade_item_drafts")
41
+ .select(SELECT_COLS)
42
+ .eq("connection_id", connectionId)
43
+ .order("updated_at", { ascending: false })
44
+ .limit(1000);
45
+ if (error)
46
+ throw error;
47
+ setItems((data ?? []).map((r) => draftToTradeItem(r)));
48
+ }
49
+ catch {
50
+ setItems([]);
51
+ }
52
+ finally {
53
+ setLoading(false);
54
+ }
55
+ }, [connectionId]);
56
+ useEffect(() => {
57
+ load();
58
+ }, [load]);
59
+ return { items, loading, reload: load };
60
+ }
61
+ export async function getLocalTradeItem(id) {
62
+ const { data, error } = await supabase
63
+ .from("trade_item_drafts")
64
+ .select(SELECT_COLS)
65
+ .eq("id", id)
66
+ .maybeSingle();
67
+ if (error)
68
+ throw new Error(error.message);
69
+ return data ?? null;
70
+ }
71
+ export async function upsertLocalTradeItem(params) {
72
+ const userRes = await supabase.auth.getUser();
73
+ const userId = userRes.data.user?.id;
74
+ if (!userId)
75
+ throw new Error("Niet ingelogd");
76
+ const metaRow = {};
77
+ const m = params.meta;
78
+ if (m) {
79
+ if (m.floridayLinkStatus !== undefined)
80
+ metaRow.floriday_link_status = m.floridayLinkStatus;
81
+ if (m.floridayId !== undefined)
82
+ metaRow.floriday_id = m.floridayId;
83
+ if (m.floridayLinkError !== undefined)
84
+ metaRow.floriday_link_error = m.floridayLinkError;
85
+ if (m.missingRequiredFields !== undefined)
86
+ metaRow.missing_required_fields = m.missingRequiredFields;
87
+ if (m.lastFloridaySyncAt !== undefined)
88
+ metaRow.last_floriday_sync_at = m.lastFloridaySyncAt;
89
+ if (m.source !== undefined)
90
+ metaRow.source = m.source;
91
+ }
92
+ if (params.id) {
93
+ const patch = {
94
+ data: params.data,
95
+ connection_id: params.connectionId,
96
+ updated_at: new Date().toISOString(),
97
+ ...metaRow,
98
+ };
99
+ const { error } = await supabase
100
+ .from("trade_item_drafts")
101
+ .update(patch)
102
+ .eq("id", params.id);
103
+ if (error)
104
+ throw new Error(error.message);
105
+ return params.id;
106
+ }
107
+ const insertRow = {
108
+ user_id: userId,
109
+ connection_id: params.connectionId,
110
+ data: params.data,
111
+ ...metaRow,
112
+ };
113
+ const { data, error } = await supabase
114
+ .from("trade_item_drafts")
115
+ .insert(insertRow)
116
+ .select("id")
117
+ .single();
118
+ if (error)
119
+ throw new Error(error.message);
120
+ return data.id;
121
+ }
122
+ export async function updateDraftMeta(id, meta) {
123
+ const row = {};
124
+ if (meta.floridayLinkStatus !== undefined)
125
+ row.floriday_link_status = meta.floridayLinkStatus;
126
+ if (meta.floridayId !== undefined)
127
+ row.floriday_id = meta.floridayId;
128
+ if (meta.floridayLinkError !== undefined)
129
+ row.floriday_link_error = meta.floridayLinkError;
130
+ if (meta.missingRequiredFields !== undefined)
131
+ row.missing_required_fields = meta.missingRequiredFields;
132
+ if (meta.lastFloridaySyncAt !== undefined)
133
+ row.last_floriday_sync_at = meta.lastFloridaySyncAt;
134
+ if (Object.keys(row).length === 0)
135
+ return;
136
+ const { error } = await supabase.from("trade_item_drafts").update(row).eq("id", id);
137
+ if (error)
138
+ throw new Error(error.message);
139
+ }
140
+ export async function deleteLocalTradeItem(id) {
141
+ const { error } = await supabase.from("trade_item_drafts").delete().eq("id", id);
142
+ if (error)
143
+ throw new Error(error.message);
144
+ }