@flowselections/floriday-voorraad 1.0.19 → 1.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/voorraad/ArtikelCompositionCard.d.ts +7 -0
- package/dist-lib/components/voorraad/ArtikelCompositionCard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/ArtikelCompositionCard.js +196 -0
- package/dist-lib/components/voorraad/ArtikelWizard.d.ts +2 -1
- package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/ArtikelWizard.js +259 -26
- package/dist-lib/components/voorraad/EditArtikelPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/EditArtikelPage.js +28 -85
- package/dist-lib/components/voorraad/FloridayStatusBadge.d.ts +4 -0
- package/dist-lib/components/voorraad/FloridayStatusBadge.d.ts.map +1 -0
- package/dist-lib/components/voorraad/FloridayStatusBadge.js +8 -0
- package/dist-lib/components/voorraad/StockBulkButtons.js +7 -6
- package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts +5 -0
- package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts.map +1 -1
- package/dist-lib/components/voorraad/ValidationOverviewTable.js +26 -56
- package/dist-lib/components/voorraad/VoorraadDashboard.d.ts +4 -0
- package/dist-lib/components/voorraad/VoorraadDashboard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadDashboard.js +14 -6
- package/dist-lib/components/voorraad/VoorraadStockCard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadStockCard.js +11 -0
- package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadTable.js +5 -12
- package/dist-lib/hooks/useFloridayContinuousStock.d.ts +13 -0
- package/dist-lib/hooks/useFloridayContinuousStock.d.ts.map +1 -0
- package/dist-lib/hooks/useFloridayContinuousStock.js +109 -0
- package/dist-lib/hooks/useFlorydayCustomers.d.ts +11 -4
- package/dist-lib/hooks/useFlorydayCustomers.d.ts.map +1 -1
- package/dist-lib/hooks/useFlorydayCustomers.js +85 -38
- package/dist-lib/hooks/useLocalTradeItems.d.ts +26 -2
- package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
- package/dist-lib/hooks/useLocalTradeItems.js +119 -79
- package/dist-lib/hooks/useVoorraadData.d.ts +5 -5
- package/dist-lib/hooks/useVoorraadData.d.ts.map +1 -1
- package/dist-lib/hooks/useVoorraadData.js +127 -50
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +662 -168
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +662 -168
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +662 -168
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +678 -163
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/floricode-required-features.functions.d.ts +662 -168
- package/dist-lib/lib/floricode-required-features.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-client.d.ts +29 -12
- package/dist-lib/lib/floriday-client.d.ts.map +1 -1
- package/dist-lib/lib/floriday-client.js +36 -0
- package/dist-lib/lib/floriday-customer-offer.functions.d.ts +662 -168
- package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-gateway.functions.d.ts +3220 -750
- package/dist-lib/lib/floriday-gateway.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-gateway.server.d.ts +14 -0
- package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -1
- package/dist-lib/lib/floriday-gateway.server.js +3 -0
- package/dist-lib/lib/floriday-payload.d.ts.map +1 -1
- package/dist-lib/lib/floriday-payload.js +32 -8
- package/dist-lib/lib/floriday-warehouse.functions.d.ts +1932 -450
- package/dist-lib/lib/floriday-warehouse.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-writes.functions.d.ts +1333 -345
- package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
- package/dist-lib/lib/merge-products.d.ts +8 -0
- package/dist-lib/lib/merge-products.d.ts.map +1 -0
- package/dist-lib/lib/merge-products.js +17 -0
- package/package.json +3 -3
|
@@ -22,15 +22,16 @@ const COLUMNS = [
|
|
|
22
22
|
"Inkomende voorraad",
|
|
23
23
|
];
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* to when the row was created — never by the synthetic UI id `erp:<uuid>`.
|
|
25
|
+
* Bepaalt de sleutel in `trade_item_stock`. Sinds de dedup-migratie is dat altijd
|
|
26
|
+
* `product:<uuid>`; oude `draft:` / `floriday:` waarden zijn ge-repoint.
|
|
28
27
|
*/
|
|
29
28
|
function toKey(item) {
|
|
30
29
|
if (item.tradeItemKey)
|
|
31
30
|
return item.tradeItemKey;
|
|
31
|
+
if (item.productId)
|
|
32
|
+
return `product:${item.productId}`;
|
|
32
33
|
if (item.localId)
|
|
33
|
-
return `
|
|
34
|
+
return `product:${item.localId}`;
|
|
34
35
|
return item.id;
|
|
35
36
|
}
|
|
36
37
|
function parseNumber(val) {
|
|
@@ -333,7 +334,7 @@ export function StockBulkButtons({ items, activeConnectionId, onImported, }) {
|
|
|
333
334
|
},
|
|
334
335
|
});
|
|
335
336
|
created++;
|
|
336
|
-
// Stock koppelen aan
|
|
337
|
+
// Stock koppelen aan het nieuwe product (draftId is nu de product-uuid)
|
|
337
338
|
const anyStock = stockValues.physical_stock !== null ||
|
|
338
339
|
stockValues.minimum_stock !== null ||
|
|
339
340
|
stockValues.reserved_stock !== null ||
|
|
@@ -342,7 +343,7 @@ export function StockBulkButtons({ items, activeConnectionId, onImported, }) {
|
|
|
342
343
|
stockBatch.push({
|
|
343
344
|
user_id: userId,
|
|
344
345
|
connection_id: activeConnectionId,
|
|
345
|
-
trade_item_key: `
|
|
346
|
+
trade_item_key: `product:${draftId}`,
|
|
346
347
|
physical_stock: stockValues.physical_stock ?? 0,
|
|
347
348
|
minimum_stock: stockValues.minimum_stock ?? 0,
|
|
348
349
|
reserved_stock: stockValues.reserved_stock ?? 0,
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { TradeItem } from "../../lib/floriday-client";
|
|
2
|
+
/**
|
|
3
|
+
* Overzicht van producten die (nog) niet actief op Floriday staan. Er is geen concept-status
|
|
4
|
+
* meer — het gaat puur om welke Floriday-velden ontbreken en of het product klaar is om te
|
|
5
|
+
* activeren. Producten blijven volwaardig in gebruik binnen ERP, ongeacht Floriday-status.
|
|
6
|
+
*/
|
|
2
7
|
export declare function ValidationOverviewTable({ items, connectionId, onChanged, }: {
|
|
3
8
|
items: TradeItem[];
|
|
4
9
|
connectionId: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidationOverviewTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ValidationOverviewTable.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"ValidationOverviewTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ValidationOverviewTable.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAM3D;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,KAAK,EACL,YAAY,EACZ,SAAS,GACV,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,2CA4GA"}
|
|
@@ -2,86 +2,56 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { useNavigate } from "@tanstack/react-router";
|
|
4
4
|
import { Badge, Button } from "@flowselections/core";
|
|
5
|
-
import { Pencil,
|
|
5
|
+
import { Pencil, Send } from "lucide-react";
|
|
6
6
|
import { validateDraftForPublish } from "../../lib/floriday-import-validator";
|
|
7
7
|
import { updateDraftMeta } from "../../hooks/useLocalTradeItems";
|
|
8
8
|
import { floriday } from "../../lib/floriday-client";
|
|
9
9
|
import { toast } from "@flowselections/core";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
case "ambiguous_match":
|
|
16
|
-
return _jsx(Badge, { className: "bg-amber-500/15 text-amber-700 border-amber-500/30", children: "Meerdere matches" });
|
|
17
|
-
case "waiting_for_data":
|
|
18
|
-
return _jsx(Badge, { className: "bg-amber-500/15 text-amber-700 border-amber-500/30", children: "Wacht op gegevens" });
|
|
19
|
-
case "ready_to_publish":
|
|
20
|
-
return _jsx(Badge, { className: "bg-blue-500/15 text-blue-700 border-blue-500/30", children: "Klaar voor publicatie" });
|
|
21
|
-
case "publish_failed":
|
|
22
|
-
return _jsx(Badge, { variant: "destructive", children: "Publicatie mislukt" });
|
|
23
|
-
default:
|
|
24
|
-
return _jsx(Badge, { variant: "outline", children: "Niet gekoppeld" });
|
|
25
|
-
}
|
|
26
|
-
}
|
|
10
|
+
/**
|
|
11
|
+
* Overzicht van producten die (nog) niet actief op Floriday staan. Er is geen concept-status
|
|
12
|
+
* meer — het gaat puur om welke Floriday-velden ontbreken en of het product klaar is om te
|
|
13
|
+
* activeren. Producten blijven volwaardig in gebruik binnen ERP, ongeacht Floriday-status.
|
|
14
|
+
*/
|
|
27
15
|
export function ValidationOverviewTable({ items, connectionId, onChanged, }) {
|
|
28
16
|
const navigate = useNavigate();
|
|
29
|
-
const rows = useMemo(() => items.filter((i) => !i.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (!item.localId)
|
|
17
|
+
const rows = useMemo(() => items.filter((i) => !i.floridayActive), [items]);
|
|
18
|
+
const publish = async (item) => {
|
|
19
|
+
const productId = item.productId ?? item.localId;
|
|
20
|
+
if (!productId || !connectionId)
|
|
34
21
|
return;
|
|
35
|
-
const
|
|
36
|
-
const v = validateDraftForPublish(
|
|
37
|
-
try {
|
|
38
|
-
await updateDraftMeta(item.localId, {
|
|
39
|
-
missingRequiredFields: v.missing,
|
|
40
|
-
floridayLinkStatus: v.ok ? "ready_to_publish" : "waiting_for_data",
|
|
41
|
-
lastFloridaySyncAt: new Date().toISOString(),
|
|
42
|
-
});
|
|
43
|
-
toast.success("Validatie bijgewerkt");
|
|
44
|
-
await onChanged();
|
|
45
|
-
}
|
|
46
|
-
catch (e) {
|
|
47
|
-
toast.error(e?.message ?? "Bijwerken mislukt");
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
const republish = async (item) => {
|
|
51
|
-
if (!item.localId || !connectionId)
|
|
52
|
-
return;
|
|
53
|
-
const d = item.raw?.data;
|
|
54
|
-
const v = validateDraftForPublish(d);
|
|
22
|
+
const payload = item.raw?.floriday_payload ?? item.raw?.data ?? {};
|
|
23
|
+
const v = validateDraftForPublish(payload);
|
|
55
24
|
if (!v.ok) {
|
|
56
25
|
toast.error("Nog niet compleet: " + v.missing.join(", "));
|
|
57
26
|
return;
|
|
58
27
|
}
|
|
59
28
|
try {
|
|
60
29
|
const { buildAddTradeItemPayload } = await import("../../lib/floriday-payload");
|
|
61
|
-
const
|
|
62
|
-
const res = await floriday.createTradeItem(connectionId,
|
|
63
|
-
await updateDraftMeta(
|
|
30
|
+
const built = buildAddTradeItemPayload(payload);
|
|
31
|
+
const res = await floriday.createTradeItem(connectionId, built);
|
|
32
|
+
await updateDraftMeta(productId, {
|
|
64
33
|
floridayLinkStatus: "published",
|
|
65
34
|
floridayId: res?.tradeItemId ?? null,
|
|
66
35
|
floridayLinkError: null,
|
|
67
36
|
lastFloridaySyncAt: new Date().toISOString(),
|
|
68
37
|
});
|
|
69
|
-
toast.success("
|
|
38
|
+
toast.success("Product staat nu actief op Floriday");
|
|
70
39
|
await onChanged();
|
|
71
40
|
}
|
|
72
41
|
catch (e) {
|
|
73
|
-
|
|
74
|
-
floridayLinkStatus: "publish_failed",
|
|
75
|
-
floridayLinkError: e?.message ?? String(e),
|
|
76
|
-
lastFloridaySyncAt: new Date().toISOString(),
|
|
77
|
-
});
|
|
78
|
-
toast.error(e?.message ?? "Publicatie mislukt");
|
|
42
|
+
toast.error(e?.message ?? "Activeren op Floriday mislukt");
|
|
79
43
|
await onChanged();
|
|
80
44
|
}
|
|
81
45
|
};
|
|
82
46
|
if (rows.length === 0) {
|
|
83
|
-
return (_jsx("div", { className: "p-8 text-center text-sm text-muted-foreground", children: "Alle
|
|
47
|
+
return (_jsx("div", { className: "p-8 text-center text-sm text-muted-foreground", children: "Alle producten staan actief op Floriday." }));
|
|
84
48
|
}
|
|
85
|
-
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", children: "Artikelcode" }), _jsx("th", { className: "p-3", children: "Artikelnaam" }), _jsx("th", { className: "p-3", children: "
|
|
86
|
-
|
|
49
|
+
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", children: "Artikelcode" }), _jsx("th", { className: "p-3", children: "Artikelnaam" }), _jsx("th", { className: "p-3", children: "Floriday-status" }), _jsx("th", { className: "p-3", children: "Ontbrekende Floriday-velden" }), _jsx("th", { className: "p-3 text-right", children: "Acties" })] }) }), _jsx("tbody", { children: rows.map((it) => {
|
|
50
|
+
const payload = it.raw?.floriday_payload ?? it.raw?.data ?? {};
|
|
51
|
+
const v = validateDraftForPublish(payload);
|
|
52
|
+
return (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "p-3 font-mono text-xs", children: it.articleNumber || "—" }), _jsx("td", { className: "p-3", children: it.name }), _jsx("td", { className: "p-3", children: _jsx(Badge, { className: "bg-slate-500/15 text-slate-700 border-slate-500/30", children: "Niet actief op Floriday" }) }), _jsx("td", { className: "p-3", children: v.missing.length === 0 ? (_jsx("span", { className: "text-xs text-emerald-700", children: "Klaar om te activeren" })) : (_jsx("div", { className: "flex flex-wrap gap-1", children: v.missing.map((m) => (_jsx(Badge, { variant: "outline", className: "text-[10px]", children: m }, m))) })) }), _jsx("td", { className: "p-3", children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
53
|
+
const target = it.productId ?? it.localId ?? it.id;
|
|
54
|
+
navigate({ to: "/voorraad/$id", params: { id: target } });
|
|
55
|
+
}, children: [_jsx(Pencil, { className: "h-3 w-3 mr-1" }), "Bewerken"] }), _jsxs(Button, { size: "sm", onClick: () => publish(it), disabled: !v.ok, children: [_jsx(Send, { className: "h-3 w-3 mr-1" }), "Activeer op Floriday"] })] }) })] }, it.id));
|
|
56
|
+
}) })] }) }));
|
|
87
57
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { TradeItem } from "../../lib/floriday-client";
|
|
2
|
+
/**
|
|
3
|
+
* Producten zijn altijd volwaardig. De dashboard-statistieken tonen alleen of ze op
|
|
4
|
+
* Floriday actief zijn — geen concept-status meer.
|
|
5
|
+
*/
|
|
2
6
|
export declare function VoorraadDashboard({ items, connectionId, }: {
|
|
3
7
|
items: TradeItem[];
|
|
4
8
|
connectionId: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoorraadDashboard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadDashboard.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"VoorraadDashboard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadDashboard.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AA4B3D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,YAAY,GACb,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,2CAuDA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Link } from "@tanstack/react-router";
|
|
3
3
|
import { Card } from "@flowselections/core";
|
|
4
|
+
import { validateDraftForPublish } from "../../lib/floriday-import-validator";
|
|
4
5
|
function Stat({ label, value, tone = "default", }) {
|
|
5
6
|
const toneCls = tone === "danger"
|
|
6
7
|
? "text-destructive"
|
|
@@ -11,13 +12,20 @@ function Stat({ label, value, tone = "default", }) {
|
|
|
11
12
|
: "text-foreground";
|
|
12
13
|
return (_jsxs("div", { children: [_jsx("div", { className: "text-xs text-muted-foreground", children: label }), _jsx("div", { className: `text-2xl font-semibold tabular-nums ${toneCls}`, children: value })] }));
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Producten zijn altijd volwaardig. De dashboard-statistieken tonen alleen of ze op
|
|
17
|
+
* Floriday actief zijn — geen concept-status meer.
|
|
18
|
+
*/
|
|
14
19
|
export function VoorraadDashboard({ items, connectionId, }) {
|
|
15
20
|
const total = items.length;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
const active = items.filter((i) => i.floridayActive).length;
|
|
22
|
+
const inactive = total - active;
|
|
23
|
+
const missingFields = items.filter((i) => {
|
|
24
|
+
if (i.floridayActive)
|
|
25
|
+
return false;
|
|
26
|
+
const payload = i.raw?.floriday_payload ?? i.raw?.data ?? {};
|
|
27
|
+
return !validateDraftForPublish(payload).ok;
|
|
28
|
+
}).length;
|
|
21
29
|
// Nieuw sinds laatste import
|
|
22
30
|
let lastImport = null;
|
|
23
31
|
try {
|
|
@@ -38,5 +46,5 @@ export function VoorraadDashboard({ items, connectionId, }) {
|
|
|
38
46
|
return src === "excel_import" && created && created >= lastImport;
|
|
39
47
|
}).length
|
|
40
48
|
: 0;
|
|
41
|
-
return (_jsxs(Card, { className: "p-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-3 mb-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: "
|
|
49
|
+
return (_jsxs(Card, { className: "p-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-3 mb-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: "Voorraad-overzicht" }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Alle producten zijn volwaardig; alleen de Floriday-activatie verschilt." })] }), _jsx(Link, { to: "/voorraad/validatie", className: "text-xs text-primary hover:underline", children: "Producten zonder Floriday-activatie \u2192" })] }), _jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-4", children: [_jsx(Stat, { label: "Producten", value: total }), _jsx(Stat, { label: "Actief op Floriday", value: active, tone: "good" }), _jsx(Stat, { label: "Niet actief op Floriday", value: inactive }), _jsx(Stat, { label: "Ontbrekende Floriday-velden", value: missingFields, tone: "warn" }), _jsx(Stat, { label: "Nieuw sinds import", value: newSinceImport })] })] }));
|
|
42
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoorraadStockCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadStockCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VoorraadStockCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadStockCard.tsx"],"names":[],"mappings":"AAcA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,2CAsHzF"}
|
|
@@ -3,15 +3,26 @@ import { useEffect, useState } from "react";
|
|
|
3
3
|
import { Button, Card, CardContent, Input, Label, Textarea, toast, } from "@flowselections/core";
|
|
4
4
|
import { Loader2, Package, Check } from "lucide-react";
|
|
5
5
|
import { useTradeItemStock, stockKeysFor } from "../../hooks/useTradeItemStock";
|
|
6
|
+
import { useFloridayContinuousStock } from "../../hooks/useFloridayContinuousStock";
|
|
6
7
|
export function VoorraadStockCard({ connectionId, tradeItemId, draftId, productId }) {
|
|
7
8
|
const keys = stockKeysFor({ tradeItemId, draftId, productId });
|
|
8
9
|
const key = keys[0] ?? null;
|
|
9
10
|
const { row, loading, save } = useTradeItemStock(connectionId, keys);
|
|
10
11
|
const [values, setValues] = useState(row);
|
|
11
12
|
const [saving, setSaving] = useState(false);
|
|
13
|
+
const floridayPieces = useFloridayContinuousStock(connectionId, tradeItemId ?? null);
|
|
12
14
|
useEffect(() => {
|
|
13
15
|
setValues(row);
|
|
14
16
|
}, [row.updated_at, row.physical_stock, row.minimum_stock, row.reserved_stock, row.incoming_stock, row.notes]);
|
|
17
|
+
// Silent sync: als Floriday een nieuwe voorraad terugmeldt, overschrijven
|
|
18
|
+
// we het "Liggend"-veld zonder extra UI-signaal.
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (floridayPieces === undefined)
|
|
21
|
+
return;
|
|
22
|
+
setValues((v) => v.physical_stock === floridayPieces
|
|
23
|
+
? v
|
|
24
|
+
: { ...v, physical_stock: floridayPieces });
|
|
25
|
+
}, [floridayPieces]);
|
|
15
26
|
if (!key) {
|
|
16
27
|
return (_jsx(Card, { className: "p-4 text-sm text-muted-foreground", children: "Voorraad kan pas worden ingesteld nadat het artikel voor het eerst is opgeslagen." }));
|
|
17
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;
|
|
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;AAY3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,2CAmHA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useNavigate } from "@tanstack/react-router";
|
|
3
|
-
import { Badge } from "@flowselections/core";
|
|
4
3
|
import { Package } from "lucide-react";
|
|
4
|
+
import { Badge } from "@flowselections/core";
|
|
5
5
|
const columns = [
|
|
6
6
|
{ key: "quantity", label: "Liggend" },
|
|
7
7
|
{ key: "minQuantity", label: "Minimum" },
|
|
@@ -18,17 +18,10 @@ export function VoorraadTable({ items, loading, }) {
|
|
|
18
18
|
if (items.length === 0) {
|
|
19
19
|
return (_jsx("p", { className: "text-sm text-muted-foreground p-6", children: "Geen producten gevonden voor deze connectie." }));
|
|
20
20
|
}
|
|
21
|
-
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) => {
|
|
22
|
-
const
|
|
23
|
-
const isErp = item.source === "erp";
|
|
24
|
-
const low = !isLocal &&
|
|
25
|
-
item.minQuantity > 0 &&
|
|
21
|
+
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: "Type" }), _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) => {
|
|
22
|
+
const low = item.minQuantity > 0 &&
|
|
26
23
|
item.availableQuantity < item.minQuantity;
|
|
27
|
-
const linkId =
|
|
28
|
-
? item.productId
|
|
29
|
-
: isLocal
|
|
30
|
-
? item.localId
|
|
31
|
-
: item.id;
|
|
24
|
+
const linkId = item.productId ?? item.localId ?? item.id;
|
|
32
25
|
const clickable = Boolean(linkId);
|
|
33
26
|
const open = () => {
|
|
34
27
|
if (linkId)
|
|
@@ -41,6 +34,6 @@ export function VoorraadTable({ items, loading, }) {
|
|
|
41
34
|
open();
|
|
42
35
|
}
|
|
43
36
|
}
|
|
44
|
-
: undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [_jsx("td", { className: "p-2", children: item.imageUrl ? (_jsx("img", { src: item.imageUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [
|
|
37
|
+
: undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [_jsx("td", { className: "p-2", children: item.imageUrl ? (_jsx("img", { src: item.imageUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [_jsx("div", { className: "flex items-center gap-2 flex-wrap", children: _jsx("span", { className: "font-medium text-foreground", children: item.name }) }), low && (_jsx("div", { className: "text-xs text-destructive", children: "onder minimumvoorraad" }))] }), _jsx("td", { className: "p-3", children: item.itemType === "productgroep" ? (_jsx(Badge, { className: "bg-indigo-500/15 text-indigo-700 border-indigo-500/30", children: "Productgroep" })) : item.itemType === "samenstelling" ? (_jsx(Badge, { className: "bg-emerald-500/15 text-emerald-700 border-emerald-500/30", children: "Samenstelling" })) : (_jsx(Badge, { variant: "secondary", children: "Artikel" })) }), _jsx("td", { className: "p-3 font-mono text-xs", children: item.articleNumber || "—" }), columns.map((c) => (_jsx("td", { className: "p-3 text-right tabular-nums text-muted-foreground", children: Number(item[c.key] ?? 0) }, c.key)))] }, item.id));
|
|
45
38
|
}) })] }) }));
|
|
46
39
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Silent live-cache van Floriday `continuous-stock.numberOfPieces` per
|
|
3
|
+
* trade_item_id, geïndexeerd binnen één connectie. Vult zichzelf via
|
|
4
|
+
* Supabase realtime — er zijn geen extra UI-elementen nodig.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useFloridayContinuousStockMap(connectionId: string | null): Map<string, number>;
|
|
7
|
+
/**
|
|
8
|
+
* Enkelvoudige variant voor per-artikel view (VoorraadStockCard). Retourneert
|
|
9
|
+
* `undefined` zolang er geen cache-waarde bekend is; realtime updates komen
|
|
10
|
+
* vanzelf binnen zonder extra UI.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useFloridayContinuousStock(connectionId: string | null, tradeItemId: string | null | undefined): number | undefined;
|
|
13
|
+
//# sourceMappingURL=useFloridayContinuousStock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFloridayContinuousStock.d.ts","sourceRoot":"","sources":["../../src/hooks/useFloridayContinuousStock.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,YAAY,EAAE,MAAM,GAAG,IAAI,GAC1B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA8DrB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,MAAM,GAAG,SAAS,CAqDpB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { supabase } from "../integrations/supabase/client";
|
|
3
|
+
/**
|
|
4
|
+
* Silent live-cache van Floriday `continuous-stock.numberOfPieces` per
|
|
5
|
+
* trade_item_id, geïndexeerd binnen één connectie. Vult zichzelf via
|
|
6
|
+
* Supabase realtime — er zijn geen extra UI-elementen nodig.
|
|
7
|
+
*/
|
|
8
|
+
export function useFloridayContinuousStockMap(connectionId) {
|
|
9
|
+
const [map, setMap] = useState(new Map());
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!connectionId) {
|
|
12
|
+
setMap(new Map());
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let cancelled = false;
|
|
16
|
+
const load = async () => {
|
|
17
|
+
const { data, error } = await supabase
|
|
18
|
+
.from("floriday_continuous_stock_cache")
|
|
19
|
+
.select("trade_item_id, number_of_pieces")
|
|
20
|
+
.eq("connection_id", connectionId);
|
|
21
|
+
if (cancelled || error || !data)
|
|
22
|
+
return;
|
|
23
|
+
const next = new Map();
|
|
24
|
+
for (const r of data) {
|
|
25
|
+
next.set(r.trade_item_id, r.number_of_pieces);
|
|
26
|
+
}
|
|
27
|
+
setMap(next);
|
|
28
|
+
};
|
|
29
|
+
load();
|
|
30
|
+
const channel = supabase
|
|
31
|
+
.channel(`floriday-continuous-stock-${connectionId}`)
|
|
32
|
+
.on("postgres_changes", {
|
|
33
|
+
event: "*",
|
|
34
|
+
schema: "public",
|
|
35
|
+
table: "floriday_continuous_stock_cache",
|
|
36
|
+
filter: `connection_id=eq.${connectionId}`,
|
|
37
|
+
}, (payload) => {
|
|
38
|
+
setMap((prev) => {
|
|
39
|
+
const next = new Map(prev);
|
|
40
|
+
const row = payload.new ?? payload.old ?? {};
|
|
41
|
+
const id = row.trade_item_id;
|
|
42
|
+
if (!id)
|
|
43
|
+
return prev;
|
|
44
|
+
if (payload.eventType === "DELETE") {
|
|
45
|
+
next.delete(id);
|
|
46
|
+
}
|
|
47
|
+
else if (typeof row.number_of_pieces === "number") {
|
|
48
|
+
next.set(id, row.number_of_pieces);
|
|
49
|
+
}
|
|
50
|
+
return next;
|
|
51
|
+
});
|
|
52
|
+
})
|
|
53
|
+
.subscribe();
|
|
54
|
+
return () => {
|
|
55
|
+
cancelled = true;
|
|
56
|
+
supabase.removeChannel(channel);
|
|
57
|
+
};
|
|
58
|
+
}, [connectionId]);
|
|
59
|
+
return map;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Enkelvoudige variant voor per-artikel view (VoorraadStockCard). Retourneert
|
|
63
|
+
* `undefined` zolang er geen cache-waarde bekend is; realtime updates komen
|
|
64
|
+
* vanzelf binnen zonder extra UI.
|
|
65
|
+
*/
|
|
66
|
+
export function useFloridayContinuousStock(connectionId, tradeItemId) {
|
|
67
|
+
const [value, setValue] = useState(undefined);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!connectionId || !tradeItemId) {
|
|
70
|
+
setValue(undefined);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
let cancelled = false;
|
|
74
|
+
const load = async () => {
|
|
75
|
+
const { data } = await supabase
|
|
76
|
+
.from("floriday_continuous_stock_cache")
|
|
77
|
+
.select("number_of_pieces")
|
|
78
|
+
.eq("connection_id", connectionId)
|
|
79
|
+
.eq("trade_item_id", tradeItemId)
|
|
80
|
+
.maybeSingle();
|
|
81
|
+
if (cancelled)
|
|
82
|
+
return;
|
|
83
|
+
if (data && typeof data.number_of_pieces === "number") {
|
|
84
|
+
setValue(data.number_of_pieces);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
load();
|
|
88
|
+
const channel = supabase
|
|
89
|
+
.channel(`floriday-cs-${connectionId}-${tradeItemId}`)
|
|
90
|
+
.on("postgres_changes", {
|
|
91
|
+
event: "*",
|
|
92
|
+
schema: "public",
|
|
93
|
+
table: "floriday_continuous_stock_cache",
|
|
94
|
+
filter: `trade_item_id=eq.${tradeItemId}`,
|
|
95
|
+
}, (payload) => {
|
|
96
|
+
const row = payload.new ?? {};
|
|
97
|
+
if (row.connection_id === connectionId &&
|
|
98
|
+
typeof row.number_of_pieces === "number") {
|
|
99
|
+
setValue(row.number_of_pieces);
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
.subscribe();
|
|
103
|
+
return () => {
|
|
104
|
+
cancelled = true;
|
|
105
|
+
supabase.removeChannel(channel);
|
|
106
|
+
};
|
|
107
|
+
}, [connectionId, tradeItemId]);
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
@@ -2,12 +2,19 @@ export interface FloridayCustomer {
|
|
|
2
2
|
id: string;
|
|
3
3
|
name: string;
|
|
4
4
|
hasRealName: boolean;
|
|
5
|
+
city: string | null;
|
|
6
|
+
country: string | null;
|
|
7
|
+
commercialName: string | null;
|
|
8
|
+
logoUrl: string | null;
|
|
9
|
+
gln: string | null;
|
|
5
10
|
}
|
|
6
11
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
12
|
+
* Buyer organisations available on the current supplier connection.
|
|
13
|
+
*
|
|
14
|
+
* Primary source: `floriday_connections_cache` (which buyers this supplier
|
|
15
|
+
* is actually connected to). We enrich every buyer with data from
|
|
16
|
+
* `floriday_customers_cache` (28k+ orgs) — that's where the real company
|
|
17
|
+
* name, city, country, and logo live.
|
|
11
18
|
*/
|
|
12
19
|
export declare function useFlorydayCustomers(connectionId: string | null): {
|
|
13
20
|
customers: FloridayCustomer[];
|
|
@@ -1 +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;
|
|
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;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAMD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;EA6G/D"}
|
|
@@ -4,10 +4,12 @@ function shortId(id) {
|
|
|
4
4
|
return `Klant ${id.slice(0, 8)}…${id.slice(-4)}`;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Buyer organisations available on the current supplier connection.
|
|
8
|
+
*
|
|
9
|
+
* Primary source: `floriday_connections_cache` (which buyers this supplier
|
|
10
|
+
* is actually connected to). We enrich every buyer with data from
|
|
11
|
+
* `floriday_customers_cache` (28k+ orgs) — that's where the real company
|
|
12
|
+
* name, city, country, and logo live.
|
|
11
13
|
*/
|
|
12
14
|
export function useFlorydayCustomers(connectionId) {
|
|
13
15
|
const [customers, setCustomers] = useState([]);
|
|
@@ -21,42 +23,87 @@ export function useFlorydayCustomers(connectionId) {
|
|
|
21
23
|
}
|
|
22
24
|
setLoading(true);
|
|
23
25
|
setError(null);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
26
|
+
(async () => {
|
|
27
|
+
try {
|
|
28
|
+
// 1) Buyer IDs op deze connectie
|
|
29
|
+
const { data: conns, error: connErr } = await supabase
|
|
30
|
+
.from("floriday_connections_cache")
|
|
31
|
+
.select("buyer_organization_id,buyer_organization_name")
|
|
32
|
+
.eq("connection_id", connectionId)
|
|
33
|
+
.eq("is_deleted", false);
|
|
34
|
+
if (connErr)
|
|
35
|
+
throw new Error(connErr.message);
|
|
36
|
+
const seen = new Set();
|
|
37
|
+
const buyerRows = [];
|
|
38
|
+
for (const row of conns ?? []) {
|
|
39
|
+
const id = row.buyer_organization_id;
|
|
40
|
+
if (!id || seen.has(id))
|
|
41
|
+
continue;
|
|
42
|
+
seen.add(id);
|
|
43
|
+
buyerRows.push({
|
|
44
|
+
id,
|
|
45
|
+
fallbackName: (row.buyer_organization_name ?? "").trim() || null,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// 2) Verrijk met naam/adres/logo uit de globale klantencache.
|
|
49
|
+
const enrichment = new Map();
|
|
50
|
+
const ids = buyerRows.map((r) => r.id);
|
|
51
|
+
const CHUNK = 500;
|
|
52
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
53
|
+
const slice = ids.slice(i, i + CHUNK);
|
|
54
|
+
const { data: rows, error: cErr } = await supabase
|
|
55
|
+
.from("floriday_customers_cache")
|
|
56
|
+
.select("organization_id,name,gln_code,data")
|
|
57
|
+
.in("organization_id", slice);
|
|
58
|
+
if (cErr)
|
|
59
|
+
throw new Error(cErr.message);
|
|
60
|
+
for (const r of rows ?? []) {
|
|
61
|
+
const d = (r.data ?? {});
|
|
62
|
+
const addr = d.mailingAddress ?? d.physicalAddress ?? {};
|
|
63
|
+
enrichment.set(r.organization_id, {
|
|
64
|
+
name: (r.name ?? "").trim() || (d.name ?? "").trim() || null,
|
|
65
|
+
city: addr.city ? String(addr.city).trim() : null,
|
|
66
|
+
country: addr.countryCode ? String(addr.countryCode).trim() : null,
|
|
67
|
+
commercialName: d.commercialName ? String(d.commercialName).trim() : null,
|
|
68
|
+
logoUrl: d.logoUrl ? String(d.logoUrl) : null,
|
|
69
|
+
gln: r.gln_code ?? d.companyGln ?? null,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const out = buyerRows.map(({ id, fallbackName }) => {
|
|
74
|
+
const e = enrichment.get(id);
|
|
75
|
+
const real = (e?.name ?? fallbackName ?? "").trim();
|
|
76
|
+
return {
|
|
77
|
+
id,
|
|
78
|
+
name: real.length > 0 ? real : shortId(id),
|
|
79
|
+
hasRealName: real.length > 0,
|
|
80
|
+
city: e?.city ?? null,
|
|
81
|
+
country: e?.country ?? null,
|
|
82
|
+
commercialName: e?.commercialName ?? null,
|
|
83
|
+
logoUrl: e?.logoUrl ?? null,
|
|
84
|
+
gln: e?.gln ?? null,
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
// Echte namen eerst (alfabetisch), fallback-labels erachter.
|
|
88
|
+
out.sort((a, b) => {
|
|
89
|
+
if (a.hasRealName !== b.hasRealName)
|
|
90
|
+
return a.hasRealName ? -1 : 1;
|
|
91
|
+
return a.name.localeCompare(b.name);
|
|
49
92
|
});
|
|
93
|
+
if (mounted)
|
|
94
|
+
setCustomers(out);
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
if (mounted) {
|
|
98
|
+
setError(e.message);
|
|
99
|
+
setCustomers([]);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
if (mounted)
|
|
104
|
+
setLoading(false);
|
|
50
105
|
}
|
|
51
|
-
|
|
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));
|
|
106
|
+
})();
|
|
60
107
|
return () => {
|
|
61
108
|
mounted = false;
|
|
62
109
|
};
|