@flowselections/floriday-klanten-module 1.0.45 → 1.0.48
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/klanten/BewerkKlant.d.ts.map +1 -1
- package/dist-lib/components/klanten/BewerkKlant.js +1 -1
- package/dist-lib/components/klanten/CustomerAnalyticsTab.d.ts.map +1 -1
- package/dist-lib/components/klanten/CustomerAnalyticsTab.js +2 -2
- package/dist-lib/components/klanten/FloridayNetworkStatus.d.ts +5 -0
- package/dist-lib/components/klanten/FloridayNetworkStatus.d.ts.map +1 -0
- package/dist-lib/components/klanten/FloridayNetworkStatus.js +18 -0
- package/dist-lib/components/klanten/KlantDetailLayout.d.ts +2 -0
- package/dist-lib/components/klanten/KlantDetailLayout.d.ts.map +1 -1
- package/dist-lib/components/klanten/KlantDetailLayout.js +6 -1
- package/dist-lib/components/klanten/KlantFormulier.d.ts +3 -1
- package/dist-lib/components/klanten/KlantFormulier.d.ts.map +1 -1
- package/dist-lib/components/klanten/KlantFormulier.js +16 -4
- package/dist-lib/components/klanten/KlantenOverzicht.d.ts.map +1 -1
- package/dist-lib/components/klanten/KlantenOverzicht.js +6 -5
- package/dist-lib/components/klanten/NetwerkPagina.d.ts.map +1 -1
- package/dist-lib/components/klanten/NetwerkPagina.js +9 -5
- package/dist-lib/components/klanten/NieuweKlant.d.ts.map +1 -1
- package/dist-lib/components/klanten/NieuweKlant.js +10 -7
- package/dist-lib/components/klanten/pricegroups/CustomerPickerDialog.d.ts.map +1 -1
- package/dist-lib/components/klanten/pricegroups/CustomerPickerDialog.js +10 -2
- package/dist-lib/components/klanten/pricegroups/PriceGroupsPage.d.ts.map +1 -1
- package/dist-lib/components/klanten/pricegroups/PriceGroupsPage.js +4 -7
- package/dist-lib/components/klanten/pricegroups/UnknownFloridayMembers.d.ts +11 -0
- package/dist-lib/components/klanten/pricegroups/UnknownFloridayMembers.d.ts.map +1 -0
- package/dist-lib/components/klanten/pricegroups/UnknownFloridayMembers.js +43 -0
- package/dist-lib/index.js +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +1470 -2
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/customer-schemas.d.ts +2 -0
- package/dist-lib/lib/customer-schemas.d.ts.map +1 -1
- package/dist-lib/lib/customer-schemas.js +2 -0
- package/dist-lib/lib/customers.functions.d.ts +37 -0
- package/dist-lib/lib/customers.functions.d.ts.map +1 -1
- package/dist-lib/lib/customers.functions.js +49 -4
- package/dist-lib/lib/floriday-network-status.functions.d.ts +18 -0
- package/dist-lib/lib/floriday-network-status.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-network-status.functions.js +41 -0
- package/dist-lib/lib/price-groups-local.functions.d.ts +42 -0
- package/dist-lib/lib/price-groups-local.functions.d.ts.map +1 -1
- package/dist-lib/lib/price-groups-local.functions.js +120 -1
- package/dist-lib/lib/twinfield-adopt.functions.d.ts +2 -0
- package/dist-lib/lib/twinfield-adopt.functions.d.ts.map +1 -1
- package/dist-lib/lib/vat-format.d.ts +17 -0
- package/dist-lib/lib/vat-format.d.ts.map +1 -0
- package/dist-lib/lib/vat-format.js +64 -0
- package/package.json +5 -5
|
@@ -5,14 +5,17 @@ import { useServerFn } from "@tanstack/react-start";
|
|
|
5
5
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, Button, Input, Checkbox, Badge, } from "@flowselections/core";
|
|
6
6
|
import { Search } from "lucide-react";
|
|
7
7
|
import { listExternalCustomers } from "../../../lib/external-customers.functions";
|
|
8
|
-
import { setPriceGroupMembers, getCustomerPriceGroup, } from "../../../lib/price-groups-local.functions";
|
|
8
|
+
import { setPriceGroupMembers, getCustomerPriceGroup, listUnknownFloridayMembers, } from "../../../lib/price-groups-local.functions";
|
|
9
9
|
import { decodeDeep } from "../../../lib/decode-html";
|
|
10
10
|
import { countryNameToFlag } from "../../../lib/countries";
|
|
11
|
+
import { formatDateTime } from "../../../lib/format-date";
|
|
12
|
+
import { UnknownFloridayMembers } from "./UnknownFloridayMembers";
|
|
11
13
|
export function CustomerPickerDialog({ priceGroupId, open, onOpenChange, value, onChange, }) {
|
|
12
14
|
const qc = useQueryClient();
|
|
13
15
|
const listCustomers = useServerFn(listExternalCustomers);
|
|
14
16
|
const getGroup = useServerFn(getCustomerPriceGroup);
|
|
15
17
|
const setMembers = useServerFn(setPriceGroupMembers);
|
|
18
|
+
const listUnknown = useServerFn(listUnknownFloridayMembers);
|
|
16
19
|
const [search, setSearch] = useState("");
|
|
17
20
|
const [selected, setSelected] = useState(new Set());
|
|
18
21
|
const isControlled = onChange !== undefined;
|
|
@@ -26,6 +29,11 @@ export function CustomerPickerDialog({ priceGroupId, open, onOpenChange, value,
|
|
|
26
29
|
queryFn: () => getGroup({ data: { id: priceGroupId } }).then(decodeDeep),
|
|
27
30
|
enabled: open && !!priceGroupId && !isControlled,
|
|
28
31
|
});
|
|
32
|
+
const { data: unknown } = useQuery({
|
|
33
|
+
queryKey: ["unknown-floriday-members", priceGroupId],
|
|
34
|
+
queryFn: () => listUnknown({ data: { priceGroupId: priceGroupId } }).then(decodeDeep),
|
|
35
|
+
enabled: open && !!priceGroupId && !isControlled,
|
|
36
|
+
});
|
|
29
37
|
useEffect(() => {
|
|
30
38
|
if (!open)
|
|
31
39
|
return;
|
|
@@ -73,5 +81,5 @@ export function CustomerPickerDialog({ priceGroupId, open, onOpenChange, value,
|
|
|
73
81
|
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-[720px]", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Klanten toewijzen" }) }), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), _jsx(Input, { placeholder: "Zoek op naam, plaats of BTW-nummer\u2026", value: search, onChange: (e) => setSearch(e.target.value), className: "pl-9" })] }), _jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [_jsxs("span", { children: [filtered.length, " klanten"] }), _jsxs("span", { children: [_jsx("strong", { className: "text-foreground", children: selected.size }), " geselecteerd"] })] }), _jsx("div", { className: "max-h-[380px] overflow-y-auto border rounded-md divide-y", children: isLoading ? (_jsx("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "Laden\u2026" })) : filtered.length === 0 ? (_jsx("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "Geen klanten gevonden." })) : filtered.map((c) => {
|
|
74
82
|
const checked = selected.has(c.group_key);
|
|
75
83
|
return (_jsxs("label", { className: "flex items-center gap-3 p-2.5 hover:bg-muted/50 cursor-pointer", children: [_jsx(Checkbox, { checked: checked, onCheckedChange: () => toggle(c.group_key) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-sm font-medium truncate", children: c.display_name }), _jsx("div", { className: "text-xs text-muted-foreground truncate", children: c.city ? (_jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx("span", { children: c.city }), c.country && (_jsxs(_Fragment, { children: [_jsx("span", { children: "\u00B7" }), _jsx("span", { className: "text-base", "aria-hidden": "true", children: countryNameToFlag(c.country) ?? "🌐" }), _jsx("span", { children: c.country })] }))] })) : c.country ? (_jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx("span", { className: "text-base", "aria-hidden": "true", children: countryNameToFlag(c.country) ?? "🌐" }), _jsx("span", { children: c.country })] })) : "—" })] }), _jsx("div", { className: "flex gap-1", children: c.providers.slice(0, 3).map((p) => (_jsx(Badge, { variant: "secondary", className: "text-[10px]", children: p }, p))) })] }, c.group_key));
|
|
76
|
-
}) }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), children: "Annuleren" }), _jsx(Button, { onClick: handleSave, disabled: !isControlled && saveMut.isPending, children: !isControlled && saveMut.isPending ? "Opslaan…" : "Selectie opslaan" })] })] }) }));
|
|
84
|
+
}) }), unknown?.lastModifiedInFloriday && (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Laatst gewijzigd in Floriday: ", formatDateTime(unknown.lastModifiedInFloriday)] })), priceGroupId && unknown && unknown.members.length > 0 && (_jsx(UnknownFloridayMembers, { members: unknown.members, priceGroupIdFor: () => priceGroupId })), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), children: "Annuleren" }), _jsx(Button, { onClick: handleSave, disabled: !isControlled && saveMut.isPending, children: !isControlled && saveMut.isPending ? "Opslaan…" : "Selectie opslaan" })] })] }) }));
|
|
77
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PriceGroupsPage.d.ts","sourceRoot":"","sources":["../../../../src/components/klanten/pricegroups/PriceGroupsPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PriceGroupsPage.d.ts","sourceRoot":"","sources":["../../../../src/components/klanten/pricegroups/PriceGroupsPage.tsx"],"names":[],"mappings":"AA2HA,wBAAgB,eAAe,gCAsV9B"}
|
|
@@ -12,6 +12,7 @@ import { SortableContext, sortableKeyboardCoordinates, verticalListSortingStrate
|
|
|
12
12
|
import { CSS } from "@dnd-kit/utilities";
|
|
13
13
|
import { listCustomerPriceGroups, deleteCustomerPriceGroup, reorderCustomerPriceGroups, updateCustomerPriceGroup, createCustomerPriceGroup, importFloridayPriceGroups, } from "../../../lib/price-groups-local.functions";
|
|
14
14
|
import { CustomerPickerDialog } from "./CustomerPickerDialog";
|
|
15
|
+
import { UnknownFloridayMembers } from "./UnknownFloridayMembers";
|
|
15
16
|
import { friendlyError } from "../../../lib/errors";
|
|
16
17
|
import { toast } from "sonner";
|
|
17
18
|
function unitLabel(u) {
|
|
@@ -34,7 +35,7 @@ function calcSummary(g) {
|
|
|
34
35
|
function SortableRow({ g, onEdit, onMembers, onDelete, onDuplicate, onToggleActive }) {
|
|
35
36
|
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: g.id });
|
|
36
37
|
const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.6 : 1 };
|
|
37
|
-
return (_jsxs(TableRow, { ref: setNodeRef, style: style, className: isDragging ? "bg-muted/50" : undefined, children: [_jsx(TableCell, { className: "w-[36px] p-0 pl-2", children: _jsx("button", { type: "button", className: "cursor-grab touch-none text-muted-foreground hover:text-foreground p-2", "aria-label": "Verslepen", ...attributes, ...listeners, children: _jsx(GripVertical, { className: "h-4 w-4" }) }) }), _jsxs(TableCell, { children: [_jsxs("div", { className: "font-medium flex items-center gap-2", children: [g.name, g.source === "floriday" && _jsx(Badge, { variant: "outline", className: "text-[10px]", children: "Floriday" }), !g.is_active && _jsx(Badge, { variant: "secondary", className: "text-[10px]", children: "Inactief" })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Laatst gewijzigd: ", formatDateTime(g.updated_at)] })] }), _jsx(TableCell, { children: _jsx(Badge, { variant: g.pricing_mode === "calculated" ? "default" : "secondary", children: g.pricing_mode === "calculated" ? "Berekende prijzen" : "Handmatige prijzen" }) }), _jsxs(TableCell, { className: "tabular-nums", children: [g.member_count, " klanten"] }), _jsxs(TableCell, { className: "text-sm", children: [g.price_scope === "incl_delivery" ? "Levering en transport" : "Exclusief levering", g.include_stickers && _jsx("div", { className: "text-xs text-muted-foreground", children: "Incl. stickers" })] }), _jsx(TableCell, { className: "text-sm", children: unitLabel(g.unit) }), _jsx(TableCell, { className: "text-sm", children: g.currency }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: calcSummary(g) }), _jsx(TableCell, { className: "w-[52px] text-right pr-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Acties", children: _jsx(MoreVertical, { className: "h-4 w-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { onClick: onEdit, children: [_jsx(Pencil, { className: "h-4 w-4 mr-2" }), "Bewerken"] }), _jsxs(DropdownMenuItem, { onClick: onMembers, children: [_jsx(Users, { className: "h-4 w-4 mr-2" }), "Klanten toewijzen"] }), _jsxs(DropdownMenuItem, { onClick: onDuplicate, children: [_jsx(Copy, { className: "h-4 w-4 mr-2" }), "Dupliceren"] }), _jsx(DropdownMenuItem, { onClick: onToggleActive, children: g.is_active
|
|
38
|
+
return (_jsxs(TableRow, { ref: setNodeRef, style: style, className: isDragging ? "bg-muted/50" : undefined, children: [_jsx(TableCell, { className: "w-[36px] p-0 pl-2", children: _jsx("button", { type: "button", className: "cursor-grab touch-none text-muted-foreground hover:text-foreground p-2", "aria-label": "Verslepen", ...attributes, ...listeners, children: _jsx(GripVertical, { className: "h-4 w-4" }) }) }), _jsxs(TableCell, { children: [_jsxs("div", { className: "font-medium flex items-center gap-2", children: [g.name, g.source === "floriday" && _jsx(Badge, { variant: "outline", className: "text-[10px]", children: "Floriday" }), g.source === "floriday" && g.external_synced_at && (_jsxs("span", { className: "text-[10px] text-muted-foreground", children: ["Ge\u00EFmporteerd op ", formatDateTime(g.external_synced_at)] })), !g.is_active && _jsx(Badge, { variant: "secondary", className: "text-[10px]", children: "Inactief" })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Laatst gewijzigd: ", formatDateTime(g.updated_at)] })] }), _jsx(TableCell, { children: _jsx(Badge, { variant: g.pricing_mode === "calculated" ? "default" : "secondary", children: g.pricing_mode === "calculated" ? "Berekende prijzen" : "Handmatige prijzen" }) }), _jsxs(TableCell, { className: "tabular-nums", children: [g.member_count, " klanten"] }), _jsxs(TableCell, { className: "text-sm", children: [g.price_scope === "incl_delivery" ? "Levering en transport" : "Exclusief levering", g.include_stickers && _jsx("div", { className: "text-xs text-muted-foreground", children: "Incl. stickers" })] }), _jsx(TableCell, { className: "text-sm", children: unitLabel(g.unit) }), _jsx(TableCell, { className: "text-sm", children: g.currency }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: calcSummary(g) }), _jsx(TableCell, { className: "w-[52px] text-right pr-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Acties", children: _jsx(MoreVertical, { className: "h-4 w-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { onClick: onEdit, children: [_jsx(Pencil, { className: "h-4 w-4 mr-2" }), "Bewerken"] }), _jsxs(DropdownMenuItem, { onClick: onMembers, children: [_jsx(Users, { className: "h-4 w-4 mr-2" }), "Klanten toewijzen"] }), _jsxs(DropdownMenuItem, { onClick: onDuplicate, children: [_jsx(Copy, { className: "h-4 w-4 mr-2" }), "Dupliceren"] }), _jsx(DropdownMenuItem, { onClick: onToggleActive, children: g.is_active
|
|
38
39
|
? (_jsxs(_Fragment, { children: [_jsx(EyeOff, { className: "h-4 w-4 mr-2" }), "Op inactief zetten"] }))
|
|
39
40
|
: (_jsxs(_Fragment, { children: [_jsx(Eye, { className: "h-4 w-4 mr-2" }), "Activeren"] })) }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onClick: onDelete, className: "text-destructive focus:text-destructive", children: [_jsx(Trash2, { className: "h-4 w-4 mr-2" }), "Verwijderen"] })] })] }) })] }));
|
|
40
41
|
}
|
|
@@ -69,13 +70,9 @@ export function PriceGroupsPage() {
|
|
|
69
70
|
mutationFn: () => importFn({ data: { preview: false } }),
|
|
70
71
|
onSuccess: (res) => {
|
|
71
72
|
const r = res;
|
|
72
|
-
|
|
73
|
-
setPreview(null);
|
|
73
|
+
setPreview(r);
|
|
74
74
|
qc.invalidateQueries({ queryKey: ["customer-price-groups"] });
|
|
75
75
|
toast.success(`Import klaar: ${r.created} nieuw, ${r.updated} bijgewerkt, ${r.deactivated} op inactief, ${r.membersLinked} klantkoppelingen.`);
|
|
76
|
-
if (r.unmatchedOrganizations.length > 0) {
|
|
77
|
-
toast.warning(`${r.unmatchedOrganizations.length} Floriday-klant(en) zijn hier nog niet bekend en overgeslagen.`);
|
|
78
|
-
}
|
|
79
76
|
},
|
|
80
77
|
onError: (e) => toast.error(friendlyError(e)),
|
|
81
78
|
});
|
|
@@ -158,5 +155,5 @@ export function PriceGroupsPage() {
|
|
|
158
155
|
setDeleteTarget(null); }, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsxs(DialogTitle, { children: ["Prijsgroep \"", deleteTarget?.name, "\" verwijderen?"] }) }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => setDeleteTarget(null), children: "Annuleren" }), _jsx(Button, { variant: "destructive", onClick: () => { if (deleteTarget)
|
|
159
156
|
deleteMut.mutate(deleteTarget.id); setDeleteTarget(null); }, children: "Verwijderen" })] })] }) }), membersFor && (_jsx(CustomerPickerDialog, { priceGroupId: membersFor, open: !!membersFor, onOpenChange: (o) => { if (!o)
|
|
160
157
|
setMembersFor(null); } })), _jsx(Dialog, { open: importOpen, onOpenChange: (o) => { setImportOpen(o); if (!o)
|
|
161
|
-
setPreview(null); }, children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Prijsgroepen importeren uit Floriday" }) }), preview && (_jsxs("div", { className: "space-y-3 text-sm", children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Badge, { variant: "default", children: [preview.created, " nieuw"] }), _jsxs(Badge, { variant: "secondary", children: [preview.updated, " bijwerken"] }), _jsxs(Badge, { variant: "outline", children: [preview.deactivated, " op inactief"] }), _jsxs(Badge, { variant: "outline", children: [preview.membersLinked, " klantkoppelingen"] })] }), preview.items.length === 0 ? (_jsx("p", { className: "text-muted-foreground", children: "Er zijn geen prijsgroepen uit Floriday om te importeren." })) : (_jsx("div", { className: "max-h-64 overflow-y-auto rounded-md border divide-y", children: preview.items.map((it) => (_jsxs("div", { className: "flex items-center justify-between gap-3 px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "font-medium truncate", children: it.name }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [it.customers, " klant(en) in Floriday"] })] }), _jsx(Badge, { variant: it.action === "create" ? "default" : it.action === "update" ? "secondary" : "outline", children: it.action === "create" ? "Nieuw" : it.action === "update" ? "Bijwerken" : "Inactief" })] }, it.external_id))) })), preview.
|
|
158
|
+
setPreview(null); }, children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: preview && !preview.preview ? "Uitkomst import uit Floriday" : "Prijsgroepen importeren uit Floriday" }) }), preview && (_jsxs("div", { className: "space-y-3 text-sm", children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Badge, { variant: "default", children: [preview.created, " nieuw"] }), _jsxs(Badge, { variant: "secondary", children: [preview.updated, " bijwerken"] }), _jsxs(Badge, { variant: "outline", children: [preview.deactivated, " op inactief"] }), _jsxs(Badge, { variant: "outline", children: [preview.membersLinked, " klantkoppelingen"] })] }), preview.items.length === 0 ? (_jsx("p", { className: "text-muted-foreground", children: "Er zijn geen prijsgroepen uit Floriday om te importeren." })) : (_jsx("div", { className: "max-h-64 overflow-y-auto rounded-md border divide-y", children: preview.items.map((it) => (_jsxs("div", { className: "flex items-center justify-between gap-3 px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "font-medium truncate", children: it.name }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [it.customers, " klant(en) in Floriday", it.last_modified_in_floriday && _jsxs(_Fragment, { children: [" \u00B7 laatst gewijzigd in Floriday ", formatDateTime(it.last_modified_in_floriday)] })] })] }), _jsx(Badge, { variant: it.action === "create" ? "default" : it.action === "update" ? "secondary" : "outline", children: it.action === "create" ? "Nieuw" : it.action === "update" ? "Bijwerken" : "Inactief" })] }, it.external_id))) })), preview.unmatchedDetails.length > 0 && (preview.preview ? (_jsxs("p", { className: "text-xs text-muted-foreground", children: [preview.unmatchedDetails.length, " Floriday-klant(en) zijn nog geen klant in het ERP. Na het importeren kun je ze per klant toevoegen."] })) : (_jsx(UnknownFloridayMembers, { members: preview.unmatchedDetails, priceGroupIdFor: (ext) => groups.find((g) => g.source === "floriday" && g.external_id === ext)?.id ?? null }))), _jsx("p", { className: "text-xs text-muted-foreground", children: "Kortingen, toeslagen en afrondingsregels blijven onaangeroerd; prijsgroepen die je zelf hebt gemaakt blijven ongewijzigd." })] })), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => setImportOpen(false), children: preview && !preview.preview ? "Sluiten" : "Annuleren" }), (!preview || preview.preview) && (_jsx(Button, { onClick: () => importMut.mutate(), disabled: importMut.isPending || !preview || preview.items.length === 0, children: importMut.isPending ? "Bezig…" : "Importeren" }))] })] }) })] }));
|
|
162
159
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type UnknownFloridayMember } from "../../../lib/price-groups-local.functions";
|
|
2
|
+
/**
|
|
3
|
+
* Floriday-leden van een prijsgroep die nog geen ERP-klant zijn. Er wordt niets vastgelegd
|
|
4
|
+
* tot iemand op "Toevoegen" klikt; dan ontstaat een klant zonder Twinfield-debiteur.
|
|
5
|
+
*/
|
|
6
|
+
export declare function UnknownFloridayMembers({ members, priceGroupIdFor, }: {
|
|
7
|
+
members: UnknownFloridayMember[];
|
|
8
|
+
/** Geeft het ERP-prijsgroep-id voor een Floriday-prijsgroep, of null als die nog niet geïmporteerd is. */
|
|
9
|
+
priceGroupIdFor: (externalId: string) => string | null;
|
|
10
|
+
}): import("react").JSX.Element | null;
|
|
11
|
+
//# sourceMappingURL=UnknownFloridayMembers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UnknownFloridayMembers.d.ts","sourceRoot":"","sources":["../../../../src/components/klanten/pricegroups/UnknownFloridayMembers.tsx"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,2CAA2C,CAAC;AAGnD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,eAAe,GAChB,EAAE;IACD,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,0GAA0G;IAC1G,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACxD,sCAoEA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
4
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
+
import { Button, Badge } from "@flowselections/core";
|
|
6
|
+
import { toast } from "sonner";
|
|
7
|
+
import { addFloridayMemberToPriceGroup, } from "../../../lib/price-groups-local.functions";
|
|
8
|
+
import { friendlyError } from "../../../lib/errors";
|
|
9
|
+
/**
|
|
10
|
+
* Floriday-leden van een prijsgroep die nog geen ERP-klant zijn. Er wordt niets vastgelegd
|
|
11
|
+
* tot iemand op "Toevoegen" klikt; dan ontstaat een klant zonder Twinfield-debiteur.
|
|
12
|
+
*/
|
|
13
|
+
export function UnknownFloridayMembers({ members, priceGroupIdFor, }) {
|
|
14
|
+
const qc = useQueryClient();
|
|
15
|
+
const addFn = useServerFn(addFloridayMemberToPriceGroup);
|
|
16
|
+
const [done, setDone] = useState(new Set());
|
|
17
|
+
const addMut = useMutation({
|
|
18
|
+
mutationFn: async (m) => {
|
|
19
|
+
for (const g of m.groups) {
|
|
20
|
+
const id = priceGroupIdFor(g.external_id);
|
|
21
|
+
if (id)
|
|
22
|
+
await addFn({ data: { organizationId: m.organization_id, priceGroupId: id } });
|
|
23
|
+
}
|
|
24
|
+
return m;
|
|
25
|
+
},
|
|
26
|
+
onSuccess: (m) => {
|
|
27
|
+
setDone((prev) => new Set(prev).add(m.organization_id));
|
|
28
|
+
qc.invalidateQueries({ queryKey: ["customer-price-groups"] });
|
|
29
|
+
qc.invalidateQueries({ queryKey: ["unknown-floriday-members"] });
|
|
30
|
+
qc.invalidateQueries({ queryKey: ["customer-price-group"] });
|
|
31
|
+
qc.invalidateQueries({ queryKey: ["external-customers-picker"] });
|
|
32
|
+
toast.success(`${m.commercial_name ?? m.name} is toegevoegd als klant (zonder debiteur in Twinfield).`);
|
|
33
|
+
},
|
|
34
|
+
onError: (e) => toast.error(friendlyError(e)),
|
|
35
|
+
});
|
|
36
|
+
if (members.length === 0)
|
|
37
|
+
return null;
|
|
38
|
+
return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("p", { className: "text-xs font-medium", children: ["Onbekend in ERP (", members.length, ")"] }), _jsx("div", { className: "max-h-56 overflow-y-auto rounded-md border divide-y", children: members.map((m) => {
|
|
39
|
+
const added = done.has(m.organization_id);
|
|
40
|
+
const canAdd = m.groups.some((g) => priceGroupIdFor(g.external_id));
|
|
41
|
+
return (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 px-3 py-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-sm font-medium truncate", children: m.commercial_name ?? m.name }), _jsxs("div", { className: "text-xs text-muted-foreground truncate", children: [m.commercial_name ? `${m.name} · ` : "", m.city ?? "—", " \u00B7 ", m.reason] }), m.groups.length > 0 && (_jsxs("div", { className: "text-xs text-muted-foreground truncate", children: ["In Floriday: ", m.groups.map((g) => g.name).join(", ")] }))] }), added ? (_jsx(Badge, { variant: "secondary", children: "Toegevoegd" })) : (_jsx(Button, { size: "sm", variant: "outline", disabled: !canAdd || addMut.isPending, title: canAdd ? undefined : "Importeer eerst de prijsgroep", onClick: () => addMut.mutate(m), children: "Toevoegen" }))] }, m.organization_id));
|
|
42
|
+
}) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Toevoegen maakt een klant aan op organisatie-id, zonder debiteur in Twinfield, en deelt die in bij de prijsgroep." })] }));
|
|
43
|
+
}
|
package/dist-lib/index.js
CHANGED