@flowselections/mailbox-orders 1.0.53 → 1.0.55
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/MailboxAuthBanner.d.ts.map +1 -1
- package/dist-lib/components/MailboxAuthBanner.js +6 -5
- package/dist-lib/components/MailboxPageFrame.d.ts +19 -0
- package/dist-lib/components/MailboxPageFrame.d.ts.map +1 -0
- package/dist-lib/components/MailboxPageFrame.js +95 -0
- package/dist-lib/components/MailboxProcessedPage.d.ts.map +1 -1
- package/dist-lib/components/MailboxProcessedPage.js +94 -62
- package/dist-lib/components/MailboxProposalsPage.d.ts.map +1 -1
- package/dist-lib/components/MailboxProposalsPage.js +178 -71
- package/dist-lib/components/MailboxSkippedPage.d.ts.map +1 -1
- package/dist-lib/components/MailboxSkippedPage.js +80 -14
- package/dist-lib/components/MailboxStatusLine.d.ts +3 -1
- package/dist-lib/components/MailboxStatusLine.d.ts.map +1 -1
- package/dist-lib/components/MailboxStatusLine.js +31 -8
- package/dist-lib/components/fs-ui/DataTable.d.ts +36 -0
- package/dist-lib/components/fs-ui/DataTable.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/DataTable.js +33 -0
- package/dist-lib/components/fs-ui/EmptyState.d.ts +9 -0
- package/dist-lib/components/fs-ui/EmptyState.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/EmptyState.js +5 -0
- package/dist-lib/components/fs-ui/FilterChips.d.ts +13 -0
- package/dist-lib/components/fs-ui/FilterChips.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/FilterChips.js +8 -0
- package/dist-lib/components/fs-ui/HoverTip.d.ts +15 -0
- package/dist-lib/components/fs-ui/HoverTip.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/HoverTip.js +24 -0
- package/dist-lib/components/fs-ui/InlineAlert.d.ts +9 -0
- package/dist-lib/components/fs-ui/InlineAlert.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/InlineAlert.js +14 -0
- package/dist-lib/components/fs-ui/KpiRow.d.ts +6 -0
- package/dist-lib/components/fs-ui/KpiRow.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/KpiRow.js +7 -0
- package/dist-lib/components/fs-ui/KpiTile.d.ts +21 -0
- package/dist-lib/components/fs-ui/KpiTile.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/KpiTile.js +40 -0
- package/dist-lib/components/fs-ui/MobilePrimaryAction.d.ts +10 -0
- package/dist-lib/components/fs-ui/MobilePrimaryAction.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/MobilePrimaryAction.js +7 -0
- package/dist-lib/components/fs-ui/PageHeader.d.ts +8 -0
- package/dist-lib/components/fs-ui/PageHeader.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/PageHeader.js +5 -0
- package/dist-lib/components/fs-ui/PillTabs.d.ts +15 -0
- package/dist-lib/components/fs-ui/PillTabs.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/PillTabs.js +14 -0
- package/dist-lib/components/fs-ui/SearchInput.d.ts +12 -0
- package/dist-lib/components/fs-ui/SearchInput.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/SearchInput.js +33 -0
- package/dist-lib/components/fs-ui/ShortcutHelp.d.ts +7 -0
- package/dist-lib/components/fs-ui/ShortcutHelp.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/ShortcutHelp.js +6 -0
- package/dist-lib/components/fs-ui/StatusIcon.d.ts +8 -0
- package/dist-lib/components/fs-ui/StatusIcon.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/StatusIcon.js +16 -0
- package/dist-lib/components/fs-ui/TableSkeleton.d.ts +6 -0
- package/dist-lib/components/fs-ui/TableSkeleton.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/TableSkeleton.js +6 -0
- package/dist-lib/components/fs-ui/Toolbar.d.ts +8 -0
- package/dist-lib/components/fs-ui/Toolbar.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/Toolbar.js +5 -0
- package/dist-lib/components/fs-ui/UpdatedAt.d.ts +7 -0
- package/dist-lib/components/fs-ui/UpdatedAt.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/UpdatedAt.js +9 -0
- package/dist-lib/components/fs-ui/useListHotkeys.d.ts +18 -0
- package/dist-lib/components/fs-ui/useListHotkeys.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/useListHotkeys.js +48 -0
- package/dist-lib/components/settings/MailboxAiPromptCard.d.ts +2 -1
- package/dist-lib/components/settings/MailboxAiPromptCard.d.ts.map +1 -1
- package/dist-lib/components/settings/MailboxAiPromptCard.js +9 -1
- package/dist-lib/components/settings/MailboxFilterSettingsCard.js +1 -1
- package/dist-lib/components/settings/MailboxTestSetCard.d.ts +2 -1
- package/dist-lib/components/settings/MailboxTestSetCard.d.ts.map +1 -1
- package/dist-lib/components/settings/MailboxTestSetCard.js +10 -2
- package/dist-lib/integrations/supabase/types.d.ts +372 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/mailbox-list.functions.d.ts +67 -0
- package/dist-lib/lib/mailbox-list.functions.d.ts.map +1 -0
- package/dist-lib/lib/mailbox-list.functions.js +63 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MailboxAuthBanner.d.ts","sourceRoot":"","sources":["../../src/components/MailboxAuthBanner.tsx"],"names":[],"mappings":"AAGA,KAAK,aAAa,GACd;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACpC;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;CACvB,GACD,SAAS,GACT,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"MailboxAuthBanner.d.ts","sourceRoot":"","sources":["../../src/components/MailboxAuthBanner.tsx"],"names":[],"mappings":"AAGA,KAAK,aAAa,GACd;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACpC;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;CACvB,GACD,SAAS,GACT,IAAI,CAAC;AAMT,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,sCA6BtE"}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { AlertTriangle } from "lucide-react";
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
2
|
import { bannerKind } from "../lib/mailbox-active.js";
|
|
3
|
+
import { InlineAlert } from "./fs-ui/InlineAlert.js";
|
|
4
|
+
const settingsLink = (label) => (_jsx("a", { href: "/e-mail-authenticatie", className: "text-sm font-medium underline underline-offset-2", children: label }));
|
|
4
5
|
export function MailboxAuthBanner({ active }) {
|
|
5
6
|
const kind = bannerKind(active);
|
|
6
7
|
if (kind === "unknown") {
|
|
7
|
-
return (_jsx("div", { className: "shrink-0 text-xs text-muted-foreground", children: "De status van de
|
|
8
|
+
return (_jsx("div", { className: "shrink-0 text-xs text-muted-foreground", children: "De status van de mailbox kon niet worden opgehaald." }));
|
|
8
9
|
}
|
|
9
10
|
if (kind === "no_mailbox") {
|
|
10
|
-
return (
|
|
11
|
+
return (_jsx(InlineAlert, { tone: "warning", title: "Er is nog geen mailbox gekoppeld voor bestellingen.", action: settingsLink("Naar Instellingen"), children: "Koppel een mailadres voor het ontvangen van bestellingen bij Instellingen." }));
|
|
11
12
|
}
|
|
12
13
|
if (kind === "reauth") {
|
|
13
14
|
const a = active;
|
|
14
|
-
return (
|
|
15
|
+
return (_jsx(InlineAlert, { tone: "error", title: `De koppeling met ${a.account_email} is verlopen.`, action: settingsLink("Opnieuw koppelen"), children: "Er komen geen nieuwe bestellingen binnen tot je de koppeling vernieuwt." }));
|
|
15
16
|
}
|
|
16
17
|
return null;
|
|
17
18
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type MailboxTab = "voorstellen" | "verwerkt" | "overgeslagen";
|
|
3
|
+
export declare const browserTz: () => string;
|
|
4
|
+
/** Zet een bewaard filter van de voorstellenlijst vóór het navigeren. */
|
|
5
|
+
export declare function setProposalFilter(key: "period" | "filter", value: unknown): void;
|
|
6
|
+
export declare const SHORTCUTS: Array<[string, string]>;
|
|
7
|
+
/**
|
|
8
|
+
* Gezamenlijke opbouw van de drie mailboxpagina's: kop, meldingen, KPI's en
|
|
9
|
+
* tabbladen. De lijst zelf komt als children.
|
|
10
|
+
*/
|
|
11
|
+
export declare function MailboxPageFrame({ tab, children, onKpi, helpOpen, onHelpOpenChange, }: {
|
|
12
|
+
tab: MailboxTab;
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
/** Pagina handelt een KPI-klik zelf af (bijv. filter zetten); anders navigeren. */
|
|
15
|
+
onKpi?: (key: "pending" | "today" | "approved_today" | "customer_unknown") => boolean | void;
|
|
16
|
+
helpOpen?: boolean;
|
|
17
|
+
onHelpOpenChange?: (v: boolean) => void;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=MailboxPageFrame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MailboxPageFrame.d.ts","sourceRoot":"","sources":["../../src/components/MailboxPageFrame.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAgBjD,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,UAAU,GAAG,cAAc,CAAC;AAQrE,eAAO,MAAM,SAAS,cAErB,CAAC;AAEF,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,QAAQ,EAAE,KAAK,EAAE,OAAO,QAEzE;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAO7C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,gBAAgB,GACjB,EAAE;IACD,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;IACpB,mFAAmF;IACnF,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,GAAG,gBAAgB,GAAG,kBAAkB,KAAK,OAAO,GAAG,IAAI,CAAC;IAC7F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC,+BA2EA"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { useQuery } from "@tanstack/react-query";
|
|
4
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
+
import { useNavigate } from "@tanstack/react-router";
|
|
6
|
+
import { CalendarClock, CheckCircle2, ClipboardCheck, Keyboard, MailX, UserX, Inbox } from "lucide-react";
|
|
7
|
+
import { Button } from "@flowselections/core";
|
|
8
|
+
import { getActiveOrdersMailbox } from "../lib/mailbox.functions.js";
|
|
9
|
+
import { getMailboxKpis } from "../lib/mailbox-list.functions.js";
|
|
10
|
+
import { MailboxAuthBanner } from "./MailboxAuthBanner.js";
|
|
11
|
+
import { MailboxStatusLine, MailboxStatusMeta } from "./MailboxStatusLine.js";
|
|
12
|
+
import { PageHeader } from "./fs-ui/PageHeader.js";
|
|
13
|
+
import { KpiRow } from "./fs-ui/KpiRow.js";
|
|
14
|
+
import { KpiTile } from "./fs-ui/KpiTile.js";
|
|
15
|
+
import { PillTabs } from "./fs-ui/PillTabs.js";
|
|
16
|
+
import { ShortcutHelp } from "./fs-ui/ShortcutHelp.js";
|
|
17
|
+
const TAB_PATH = {
|
|
18
|
+
voorstellen: "/mailbox-orders/voorstellen",
|
|
19
|
+
verwerkt: "/mailbox-orders/verwerkt",
|
|
20
|
+
overgeslagen: "/mailbox-orders/overgeslagen",
|
|
21
|
+
};
|
|
22
|
+
export const browserTz = () => {
|
|
23
|
+
try {
|
|
24
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return "UTC";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/** Zet een bewaard filter van de voorstellenlijst vóór het navigeren. */
|
|
31
|
+
export function setProposalFilter(key, value) {
|
|
32
|
+
try {
|
|
33
|
+
window.localStorage.setItem(`mailbox-proposals:${key}`, JSON.stringify(value));
|
|
34
|
+
}
|
|
35
|
+
catch { /* negeer */ }
|
|
36
|
+
}
|
|
37
|
+
export const SHORTCUTS = [
|
|
38
|
+
["/", "Zoeken"],
|
|
39
|
+
["J", "Volgende rij"],
|
|
40
|
+
["K", "Vorige rij"],
|
|
41
|
+
["Enter", "Openen"],
|
|
42
|
+
["Esc", "Sluiten of wissen"],
|
|
43
|
+
["?", "Dit overzicht"],
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Gezamenlijke opbouw van de drie mailboxpagina's: kop, meldingen, KPI's en
|
|
47
|
+
* tabbladen. De lijst zelf komt als children.
|
|
48
|
+
*/
|
|
49
|
+
export function MailboxPageFrame({ tab, children, onKpi, helpOpen, onHelpOpenChange, }) {
|
|
50
|
+
const navigate = useNavigate();
|
|
51
|
+
const fetchActive = useServerFn(getActiveOrdersMailbox);
|
|
52
|
+
const fetchKpis = useServerFn(getMailboxKpis);
|
|
53
|
+
const [localHelp, setLocalHelp] = useState(false);
|
|
54
|
+
const help = helpOpen ?? localHelp;
|
|
55
|
+
const setHelp = onHelpOpenChange ?? setLocalHelp;
|
|
56
|
+
const { data: activeMailbox } = useQuery({
|
|
57
|
+
queryKey: ["mailbox-active-account"],
|
|
58
|
+
queryFn: () => fetchActive(),
|
|
59
|
+
refetchInterval: 60000,
|
|
60
|
+
retry: 1,
|
|
61
|
+
});
|
|
62
|
+
const kpiQ = useQuery({
|
|
63
|
+
queryKey: ["mailbox-kpis"],
|
|
64
|
+
queryFn: () => fetchKpis({ data: { tz: browserTz() } }),
|
|
65
|
+
refetchInterval: 60000,
|
|
66
|
+
placeholderData: (prev) => prev,
|
|
67
|
+
});
|
|
68
|
+
const k = (kpiQ.data ?? null);
|
|
69
|
+
const loading = kpiQ.isLoading;
|
|
70
|
+
const go = (t) => { if (t !== tab)
|
|
71
|
+
void navigate({ to: TAB_PATH[t] }); };
|
|
72
|
+
const kpi = (key) => {
|
|
73
|
+
if (onKpi && onKpi(key) === true)
|
|
74
|
+
return;
|
|
75
|
+
if (key === "approved_today") {
|
|
76
|
+
go("verwerkt");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (key === "today")
|
|
80
|
+
setProposalFilter("period", "today");
|
|
81
|
+
if (key === "customer_unknown")
|
|
82
|
+
setProposalFilter("filter", "klant_onbekend");
|
|
83
|
+
if (key === "pending") {
|
|
84
|
+
setProposalFilter("period", "all");
|
|
85
|
+
setProposalFilter("filter", null);
|
|
86
|
+
}
|
|
87
|
+
if (tab !== "voorstellen")
|
|
88
|
+
go("voorstellen");
|
|
89
|
+
};
|
|
90
|
+
return (_jsxs("div", { className: "flex h-[calc(100dvh-var(--app-header-height)-var(--core-topbar-h,0px))] max-h-[calc(100dvh-var(--app-header-height)-var(--core-topbar-h,0px))] min-h-0 w-full flex-col gap-4 overflow-hidden p-4 pb-24 sm:p-6 md:pb-6", children: [_jsx(PageHeader, { title: "Mailbox bestellingen", meta: _jsx(MailboxStatusMeta, {}), actions: _jsxs(Button, { variant: "outline", size: "sm", className: "hidden h-9 gap-2 md:inline-flex", onClick: () => setHelp(true), "aria-label": "Sneltoetsen", children: [_jsx(Keyboard, { className: "h-4 w-4" }), _jsx("kbd", { className: "rounded-sm border border-border px-1 text-[11px]", children: "?" })] }) }), _jsx(MailboxAuthBanner, { active: activeMailbox }), _jsx(MailboxStatusLine, {}), _jsxs(KpiRow, { children: [_jsx(KpiTile, { title: "Te controleren", value: k?.pending ?? 0, sub: "Bestellingen uit e-mail", icon: _jsx(ClipboardCheck, {}), loading: loading, onClick: () => kpi("pending") }), _jsx(KpiTile, { title: "Vandaag binnen", value: k?.pending_today ?? 0, sub: "Nog te controleren", icon: _jsx(CalendarClock, {}), loading: loading, onClick: () => kpi("today") }), _jsx(KpiTile, { title: "Vandaag verwerkt", value: k?.approved_today ?? 0, sub: "Orders aangemaakt", icon: _jsx(CheckCircle2, {}), loading: loading, onClick: () => kpi("approved_today") }), _jsx(KpiTile, { title: "Klant onbekend", value: k?.customer_unknown ?? 0, sub: (k?.customer_unknown ?? 0) > 0 ? _jsx("span", { className: "text-destructive", children: "Kies of maak de klant" }) : "Alles herkend", icon: _jsx(UserX, {}), tone: "warning", loading: loading, onClick: () => kpi("customer_unknown") })] }), _jsx(PillTabs, { ariaLabel: "Mailbox", active: tab, onSelect: (t) => go(t), tabs: [
|
|
91
|
+
{ key: "voorstellen", label: "Te controleren", icon: _jsx(Inbox, {}), count: k ? k.pending : null },
|
|
92
|
+
{ key: "verwerkt", label: "Verwerkt", icon: _jsx(CheckCircle2, {}), count: k ? k.processed : null },
|
|
93
|
+
{ key: "overgeslagen", label: "Overgeslagen", icon: _jsx(MailX, {}), count: k ? k.skipped : null },
|
|
94
|
+
] }), children, _jsx(ShortcutHelp, { open: help, onOpenChange: setHelp, items: SHORTCUTS })] }));
|
|
95
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MailboxProcessedPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProcessedPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MailboxProcessedPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProcessedPage.tsx"],"names":[],"mappings":"AAwBA,wBAAgB,oBAAoB,gCAuMnC"}
|
|
@@ -1,90 +1,122 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
+
import { useNavigate } from "@tanstack/react-router";
|
|
5
6
|
import { toast } from "sonner";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { CalendarClock, CheckCircle2, Filter, Search, Undo2 } from "lucide-react";
|
|
8
|
+
import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@flowselections/core";
|
|
9
|
+
import { reopenProposal } from "../lib/mailbox.functions.js";
|
|
10
|
+
import { listProposalsPage } from "../lib/mailbox-list.functions.js";
|
|
9
11
|
import { TablePagination } from "./TablePagination.js";
|
|
10
|
-
import {
|
|
12
|
+
import { usePersistedState } from "./MailboxFilterBar.js";
|
|
13
|
+
import { MailboxPageFrame, browserTz } from "./MailboxPageFrame.js";
|
|
14
|
+
import { DataTable, InitialsAvatar } from "./fs-ui/DataTable.js";
|
|
15
|
+
import { StatusIcon } from "./fs-ui/StatusIcon.js";
|
|
16
|
+
import { EmptyState } from "./fs-ui/EmptyState.js";
|
|
17
|
+
import { InlineAlert } from "./fs-ui/InlineAlert.js";
|
|
18
|
+
import { TableSkeleton } from "./fs-ui/TableSkeleton.js";
|
|
19
|
+
import { Toolbar } from "./fs-ui/Toolbar.js";
|
|
20
|
+
import { SearchInput } from "./fs-ui/SearchInput.js";
|
|
21
|
+
import { FilterChips } from "./fs-ui/FilterChips.js";
|
|
22
|
+
import { useListHotkeys } from "./fs-ui/useListHotkeys.js";
|
|
23
|
+
const PERIOD_LABEL = { today: "Vandaag", "7d": "Laatste 7 dagen", "30d": "Laatste 30 dagen" };
|
|
11
24
|
export function MailboxProcessedPage() {
|
|
12
|
-
const fetchList = useServerFn(
|
|
25
|
+
const fetchList = useServerFn(listProposalsPage);
|
|
13
26
|
const reopen = useServerFn(reopenProposal);
|
|
14
|
-
const fetchActive = useServerFn(getActiveOrdersMailbox);
|
|
15
27
|
const qc = useQueryClient();
|
|
16
|
-
const
|
|
17
|
-
queryKey: ["mailbox-active-account"],
|
|
18
|
-
queryFn: () => fetchActive(),
|
|
19
|
-
refetchInterval: 60000,
|
|
20
|
-
retry: 1,
|
|
21
|
-
});
|
|
22
|
-
const approved = useQuery({
|
|
23
|
-
queryKey: ["mailbox-proposals", "approved"],
|
|
24
|
-
queryFn: () => fetchList({ data: { status: "approved" } }),
|
|
25
|
-
});
|
|
26
|
-
const rejected = useQuery({
|
|
27
|
-
queryKey: ["mailbox-proposals", "rejected"],
|
|
28
|
-
queryFn: () => fetchList({ data: { status: "rejected" } }),
|
|
29
|
-
});
|
|
30
|
-
const items = [
|
|
31
|
-
...(Array.isArray(approved.data?.items) ? approved.data.items : []),
|
|
32
|
-
...(Array.isArray(rejected.data?.items) ? rejected.data.items : []),
|
|
33
|
-
];
|
|
28
|
+
const navigate = useNavigate();
|
|
34
29
|
const [busyId, setBusyId] = useState(null);
|
|
35
30
|
const [page, setPage] = useState(1);
|
|
36
|
-
const [pageSize, setPageSize] = useState(
|
|
31
|
+
const [pageSize, setPageSize] = useState(50);
|
|
37
32
|
const [search, setSearch] = usePersistedState("mailbox-processed:search", "");
|
|
38
33
|
const [period, setPeriod] = usePersistedState("mailbox-processed:period", "all");
|
|
39
34
|
const [sortOrder, setSortOrder] = usePersistedState("mailbox-processed:sort", "date-desc");
|
|
40
35
|
const [statusFilter, setStatusFilter] = usePersistedState("mailbox-processed:status", "all");
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
}, [items, search, period, sortOrder, statusFilter]);
|
|
65
|
-
const hasActiveFilters = !!search || period !== "all" || sortOrder !== "date-desc" || statusFilter !== "all";
|
|
36
|
+
const [cursor, setCursor] = useState(null);
|
|
37
|
+
const [helpOpen, setHelpOpen] = useState(false);
|
|
38
|
+
const searchRef = useRef(null);
|
|
39
|
+
const params = {
|
|
40
|
+
statuses: statusFilter === "approved" ? ["approved"] : statusFilter === "rejected" ? ["rejected"] : ["approved", "rejected"],
|
|
41
|
+
search,
|
|
42
|
+
period,
|
|
43
|
+
sort: sortOrder === "date-asc" ? "asc" : "desc",
|
|
44
|
+
dateField: "reviewed",
|
|
45
|
+
tz: browserTz(),
|
|
46
|
+
page,
|
|
47
|
+
pageSize,
|
|
48
|
+
};
|
|
49
|
+
const { data, isLoading, error, refetch } = useQuery({
|
|
50
|
+
queryKey: ["mailbox-proposals", "processed", params],
|
|
51
|
+
queryFn: () => fetchList({ data: params }),
|
|
52
|
+
placeholderData: (prev) => prev,
|
|
53
|
+
refetchInterval: 60000,
|
|
54
|
+
});
|
|
55
|
+
const items = Array.isArray(data?.items) ? data.items : [];
|
|
56
|
+
const total = Number(data?.total ?? 0);
|
|
57
|
+
const hasActiveFilters = !!search || period !== "all" || statusFilter !== "all";
|
|
66
58
|
const clearFilters = () => { setSearch(""); setPeriod("all"); setSortOrder("date-desc"); setStatusFilter("all"); };
|
|
67
|
-
useEffect(() => { setPage(1); }, [search, period, sortOrder, statusFilter]);
|
|
68
|
-
const pageCount = Math.max(1, Math.ceil(
|
|
59
|
+
useEffect(() => { setPage(1); setCursor(null); }, [search, period, sortOrder, statusFilter]);
|
|
60
|
+
const pageCount = Math.max(1, Math.ceil(total / pageSize));
|
|
69
61
|
const currentPage = Math.min(page, pageCount);
|
|
70
|
-
const
|
|
62
|
+
const openOrder = (p) => {
|
|
63
|
+
if (p?.created_order_id)
|
|
64
|
+
void navigate({ to: `/floriday-verkoop/verkooporders/${p.created_order_id}` });
|
|
65
|
+
};
|
|
71
66
|
const handleReopen = async (proposalId) => {
|
|
72
67
|
setBusyId(proposalId);
|
|
73
68
|
try {
|
|
74
69
|
await reopen({ data: { proposalId } });
|
|
75
|
-
toast.success("
|
|
70
|
+
toast.success("Bestelling teruggezet naar 'Te controleren'.");
|
|
76
71
|
await qc.invalidateQueries({ queryKey: ["mailbox-proposals"] });
|
|
72
|
+
await qc.invalidateQueries({ queryKey: ["mailbox-kpis"] });
|
|
77
73
|
}
|
|
78
74
|
catch (e) {
|
|
79
|
-
|
|
75
|
+
console.warn("[mailbox] terugzetten", e);
|
|
76
|
+
toast.error("Terugzetten lukt niet. Probeer het opnieuw.");
|
|
80
77
|
}
|
|
81
78
|
finally {
|
|
82
79
|
setBusyId(null);
|
|
83
80
|
}
|
|
84
81
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
useListHotkeys({
|
|
83
|
+
disabled: helpOpen,
|
|
84
|
+
onSearch: () => searchRef.current?.focus(),
|
|
85
|
+
onNext: () => setCursor((c) => (items.length ? Math.min((c ?? -1) + 1, items.length - 1) : null)),
|
|
86
|
+
onPrev: () => setCursor((c) => (items.length ? Math.max((c ?? 1) - 1, 0) : null)),
|
|
87
|
+
onOpen: cursor != null && items[cursor]?.created_order_id ? () => openOrder(items[cursor]) : undefined,
|
|
88
|
+
onEscape: hasActiveFilters ? clearFilters : undefined,
|
|
89
|
+
onHelp: () => setHelpOpen(true),
|
|
90
|
+
});
|
|
91
|
+
const nameOf = (p) => p.customer_name || p.from_name || p.from_email || "Onbekend";
|
|
92
|
+
const statusOf = (p) => p.status === "approved"
|
|
93
|
+
? _jsx(StatusIcon, { tone: "done", label: "Goedgekeurd", detail: p.order_number ? `Order ${p.order_number}` : undefined })
|
|
94
|
+
: _jsx(StatusIcon, { tone: "rejected", label: "Afgewezen" });
|
|
95
|
+
const rowAction = (p) => p.status === "rejected" ? (_jsxs(Button, { size: "sm", variant: "ghost", className: "h-8 gap-1", disabled: busyId === p.id, onClick: () => handleReopen(p.id), "aria-label": "Terugzetten naar te controleren", children: [_jsx(Undo2, { className: "h-4 w-4" }), _jsx("span", { className: "hidden lg:inline", children: busyId === p.id ? "Bezig…" : "Terugzetten" })] })) : p.created_order_id ? (_jsx(Button, { size: "sm", variant: "ghost", className: "h-8", onClick: () => openOrder(p), children: "Open order" })) : null;
|
|
96
|
+
const columns = [
|
|
97
|
+
{
|
|
98
|
+
key: "klant", header: "Klant", width: "minmax(180px,1.4fr)",
|
|
99
|
+
cell: (p) => (_jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [_jsx(InitialsAvatar, { name: nameOf(p) }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-medium", children: nameOf(p) }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: p.from_email ?? "" })] })] })),
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
key: "bericht", header: "Onderwerp", width: "minmax(240px,2.2fr)",
|
|
103
|
+
cell: (p) => (_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate", children: p.subject || "(geen onderwerp)" }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: String(p.preview ?? "").slice(0, 180) })] })),
|
|
104
|
+
},
|
|
105
|
+
{ key: "order", header: "Order", width: "130px", cell: (p) => _jsx("span", { className: "tabular-nums", children: p.order_number || "–" }) },
|
|
106
|
+
{
|
|
107
|
+
key: "datum", header: "Verwerkt op", width: "150px", sortable: true,
|
|
108
|
+
cell: (p) => _jsx("span", { className: "tabular-nums text-muted-foreground", children: p.reviewed_at ? new Date(p.reviewed_at).toLocaleString("nl-NL", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit" }) : "–" }),
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
key: "status", header: "Status", width: "120px",
|
|
112
|
+
cell: (p) => (_jsxs("div", { className: "flex items-center gap-2", children: [statusOf(p), _jsx("span", { className: "text-xs text-muted-foreground", children: p.status === "approved" ? "Goedgekeurd" : "Afgewezen" })] })),
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
const chips = [
|
|
116
|
+
...(period !== "all" ? [{ key: "period", label: PERIOD_LABEL[period] ?? period, icon: _jsx(CalendarClock, {}), onRemove: () => setPeriod("all") }] : []),
|
|
117
|
+
...(statusFilter !== "all" ? [{ key: "status", label: statusFilter === "approved" ? "Goedgekeurd" : "Afgewezen", icon: _jsx(CheckCircle2, {}), onRemove: () => setStatusFilter("all") }] : []),
|
|
118
|
+
];
|
|
119
|
+
return (_jsxs(MailboxPageFrame, { tab: "verwerkt", helpOpen: helpOpen, onHelpOpenChange: setHelpOpen, children: [_jsx(Toolbar, { chips: _jsx(FilterChips, { chips: chips, onClearAll: clearFilters }), right: _jsxs(_Fragment, { children: [_jsxs(Select, { value: statusFilter, onValueChange: setStatusFilter, children: [_jsx(SelectTrigger, { className: "h-9 w-[150px]", "aria-label": "Status", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "Alle statussen" }), _jsx(SelectItem, { value: "approved", children: "Goedgekeurd" }), _jsx(SelectItem, { value: "rejected", children: "Afgewezen" })] })] }), _jsxs(Select, { value: period, onValueChange: (v) => setPeriod(v), children: [_jsxs(SelectTrigger, { className: "h-9 w-[150px]", "aria-label": "Periode", children: [_jsx(Filter, { className: "mr-1 h-4 w-4" }), _jsx(SelectValue, {})] }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "Alle periodes" }), _jsx(SelectItem, { value: "today", children: "Vandaag" }), _jsx(SelectItem, { value: "7d", children: "Laatste 7 dagen" }), _jsx(SelectItem, { value: "30d", children: "Laatste 30 dagen" })] })] })] }), children: _jsx(SearchInput, { ref: searchRef, value: search, onChange: setSearch, placeholder: "Zoek op klant, afzender of onderwerp" }) }), isLoading && !data ? (_jsx(TableSkeleton, { columns: ["1.4fr", "2.2fr", "130px", "150px", "120px"] })) : error && !data ? (_jsx(InlineAlert, { tone: "error", title: "De lijst kon niet worden geladen.", action: _jsx(Button, { size: "sm", variant: "outline", onClick: () => void refetch(), children: "Opnieuw proberen" }), children: "Probeer het opnieuw." })) : total === 0 ? (_jsx("div", { className: "rounded-xl border border-border bg-card shadow-sm", children: hasActiveFilters
|
|
120
|
+
? _jsx(EmptyState, { icon: _jsx(Search, { className: "h-6 w-6" }), title: "Niets gevonden", text: "Er zijn geen verwerkte bestellingen die bij je zoekopdracht of filters passen.", action: _jsx(Button, { size: "sm", variant: "outline", onClick: clearFilters, children: "Filters wissen" }) })
|
|
121
|
+
: _jsx(EmptyState, { icon: _jsx(CheckCircle2, { className: "h-6 w-6" }), title: "Nog niets verwerkt", text: "Bevestigde en afgewezen bestellingen verschijnen hier." }) })) : (_jsx(DataTable, { rows: items, columns: columns, rowKey: (p) => p.id, activeIndex: cursor, rowAction: rowAction, sort: { key: "datum", dir: sortOrder === "date-asc" ? "asc" : "desc" }, onSortChange: () => setSortOrder(sortOrder === "date-asc" ? "date-desc" : "date-asc"), mobileCard: (p) => (_jsxs("div", { className: "min-w-0 space-y-1", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "truncate font-semibold", children: nameOf(p) }), statusOf(p)] }), _jsx("div", { className: "truncate text-muted-foreground", children: p.subject || "(geen onderwerp)" }), _jsxs("div", { className: "text-xs tabular-nums text-muted-foreground", children: [p.order_number ? `${p.order_number} · ` : "", p.reviewed_at ? new Date(p.reviewed_at).toLocaleDateString("nl-NL") : "–"] })] })), footer: _jsx(TablePagination, { total: total, page: currentPage, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize }) }))] }));
|
|
90
122
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MailboxProposalsPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProposalsPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MailboxProposalsPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProposalsPage.tsx"],"names":[],"mappings":"AA6HA,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AA2CD,wBAAgB,oBAAoB,gCA+gBnC"}
|