@flowselections/mailbox-orders 1.0.53 → 1.0.57
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 +3 -3
- package/dist-lib/components/MailboxAuthBanner.d.ts.map +1 -1
- package/dist-lib/components/MailboxAuthBanner.js +20 -7
- package/dist-lib/components/MailboxPageFrame.d.ts +25 -0
- package/dist-lib/components/MailboxPageFrame.d.ts.map +1 -0
- package/dist-lib/components/MailboxPageFrame.js +103 -0
- package/dist-lib/components/MailboxProcessedPage.d.ts.map +1 -1
- package/dist-lib/components/MailboxProcessedPage.js +102 -61
- package/dist-lib/components/MailboxProposalsPage.d.ts.map +1 -1
- package/dist-lib/components/MailboxProposalsPage.js +191 -76
- package/dist-lib/components/MailboxSkippedPage.d.ts.map +1 -1
- package/dist-lib/components/MailboxSkippedPage.js +97 -19
- package/dist-lib/components/MailboxStatusLine.d.ts +8 -2
- package/dist-lib/components/MailboxStatusLine.d.ts.map +1 -1
- package/dist-lib/components/MailboxStatusLine.js +54 -8
- package/dist-lib/components/TablePagination.d.ts +2 -2
- package/dist-lib/components/TablePagination.d.ts.map +1 -1
- package/dist-lib/components/TablePagination.js +8 -12
- package/dist-lib/components/fs-ui/DataTable.d.ts +42 -0
- package/dist-lib/components/fs-ui/DataTable.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/DataTable.js +40 -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/FilterPanel.d.ts +32 -0
- package/dist-lib/components/fs-ui/FilterPanel.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/FilterPanel.js +20 -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 +6 -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/NoticeBar.d.ts +18 -0
- package/dist-lib/components/fs-ui/NoticeBar.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/NoticeBar.js +24 -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 +16 -0
- package/dist-lib/components/fs-ui/PillTabs.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/PillTabs.js +29 -0
- package/dist-lib/components/fs-ui/RowMenu.d.ts +13 -0
- package/dist-lib/components/fs-ui/RowMenu.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/RowMenu.js +10 -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 +38 -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 +13 -0
- package/dist-lib/components/fs-ui/Toolbar.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/Toolbar.js +10 -0
- package/dist-lib/components/fs-ui/UpdatedAt.d.ts +8 -0
- package/dist-lib/components/fs-ui/UpdatedAt.d.ts.map +1 -0
- package/dist-lib/components/fs-ui/UpdatedAt.js +17 -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/format-date.d.ts +5 -0
- package/dist-lib/lib/format-date.d.ts.map +1 -0
- package/dist-lib/lib/format-date.js +30 -0
- package/dist-lib/lib/labels.d.ts +15 -0
- package/dist-lib/lib/labels.d.ts.map +1 -0
- package/dist-lib/lib/labels.js +57 -0
- 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 +61 -0
- package/dist-lib/lib/mailbox.functions.js +3 -3
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Notice } from "./fs-ui/NoticeBar.js";
|
|
1
2
|
type ActiveMailbox = {
|
|
2
3
|
connected: null;
|
|
3
4
|
error?: string;
|
|
@@ -12,8 +13,7 @@ type ActiveMailbox = {
|
|
|
12
13
|
display_name: string | null;
|
|
13
14
|
needs_reauth: boolean;
|
|
14
15
|
} | undefined | null;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}): import("react").JSX.Element | null;
|
|
16
|
+
/** Meldingen over de koppeling van de mailbox (voor de NoticeBar onder de kop). */
|
|
17
|
+
export declare function mailboxAuthNotices(active: ActiveMailbox): Notice[];
|
|
18
18
|
export {};
|
|
19
19
|
//# sourceMappingURL=MailboxAuthBanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MailboxAuthBanner.d.ts","sourceRoot":"","sources":["../../src/components/MailboxAuthBanner.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MailboxAuthBanner.d.ts","sourceRoot":"","sources":["../../src/components/MailboxAuthBanner.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,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,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAyBlE"}
|
|
@@ -1,17 +1,30 @@
|
|
|
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";
|
|
4
|
-
|
|
3
|
+
const settingsLink = (label) => (_jsx("a", { href: "/e-mail-authenticatie", className: "text-sm font-medium underline underline-offset-2", children: label }));
|
|
4
|
+
/** Meldingen over de koppeling van de mailbox (voor de NoticeBar onder de kop). */
|
|
5
|
+
export function mailboxAuthNotices(active) {
|
|
5
6
|
const kind = bannerKind(active);
|
|
6
7
|
if (kind === "unknown") {
|
|
7
|
-
return
|
|
8
|
+
return [{ key: "auth-unknown", tone: "info", title: "De status van de mailbox kon niet worden opgehaald." }];
|
|
8
9
|
}
|
|
9
10
|
if (kind === "no_mailbox") {
|
|
10
|
-
return
|
|
11
|
+
return [{
|
|
12
|
+
key: "auth-none",
|
|
13
|
+
tone: "warning",
|
|
14
|
+
title: "Er is nog geen mailbox gekoppeld voor bestellingen.",
|
|
15
|
+
details: "Koppel een mailadres voor het ontvangen van bestellingen bij Instellingen.",
|
|
16
|
+
action: settingsLink("Naar Instellingen"),
|
|
17
|
+
}];
|
|
11
18
|
}
|
|
12
19
|
if (kind === "reauth") {
|
|
13
20
|
const a = active;
|
|
14
|
-
return
|
|
21
|
+
return [{
|
|
22
|
+
key: "auth-reauth",
|
|
23
|
+
tone: "error",
|
|
24
|
+
title: `De koppeling met ${a.account_email} is verlopen.`,
|
|
25
|
+
details: "Er komen geen nieuwe bestellingen binnen tot je de koppeling vernieuwt.",
|
|
26
|
+
action: settingsLink("Opnieuw koppelen"),
|
|
27
|
+
}];
|
|
15
28
|
}
|
|
16
|
-
return
|
|
29
|
+
return [];
|
|
17
30
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type Notice } from "./fs-ui/NoticeBar.js";
|
|
3
|
+
export type MailboxTab = "voorstellen" | "verwerkt" | "overgeslagen";
|
|
4
|
+
export type MailboxKpiKey = "pending" | "today" | "approved_today" | "customer_unknown";
|
|
5
|
+
export declare const browserTz: () => string;
|
|
6
|
+
/** Zet een bewaard filter van de voorstellenlijst vóór het navigeren. */
|
|
7
|
+
export declare function setProposalFilter(key: "period" | "filter", value: unknown): void;
|
|
8
|
+
export declare const SHORTCUTS: Array<[string[], string]>;
|
|
9
|
+
/**
|
|
10
|
+
* Gezamenlijke opbouw van de drie mailboxpagina's, in de vaste volgorde:
|
|
11
|
+
* kop → meldingen → 4 KPI's → tabbladen → (children: werkbalk, tabel, paginering).
|
|
12
|
+
*/
|
|
13
|
+
export declare function MailboxPageFrame({ tab, children, onKpi, activeKpi, notices, helpOpen, onHelpOpenChange, }: {
|
|
14
|
+
tab: MailboxTab;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
/** Pagina handelt een KPI-klik zelf af (bijv. filter zetten); anders navigeren. */
|
|
17
|
+
onKpi?: (key: MailboxKpiKey) => boolean | void;
|
|
18
|
+
/** Tegel waarop de gebruiker zelf gefilterd heeft (alleen die krijgt de rand). */
|
|
19
|
+
activeKpi?: MailboxKpiKey | null;
|
|
20
|
+
/** Meldingen van de pagina zelf; komen bij de andere meldingen onder de kop. */
|
|
21
|
+
notices?: Notice[];
|
|
22
|
+
helpOpen?: boolean;
|
|
23
|
+
onHelpOpenChange?: (v: boolean) => void;
|
|
24
|
+
}): import("react").JSX.Element;
|
|
25
|
+
//# 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,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAe5D,OAAO,EAAa,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,UAAU,GAAG,cAAc,CAAC;AACrE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAQxF,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,EAAE,MAAM,CAAC,CAM/C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,QAAQ,EACR,KAAK,EACL,SAAS,EACT,OAAY,EACZ,QAAQ,EACR,gBAAgB,GACjB,EAAE;IACD,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;IACpB,mFAAmF;IACnF,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,GAAG,IAAI,CAAC;IAC/C,kFAAkF;IAClF,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC,+BA+EA"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, 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, MailX, UserX, Inbox } from "lucide-react";
|
|
7
|
+
import { ensureMailboxDefaultsFn, getActiveOrdersMailbox } from "../lib/mailbox.functions.js";
|
|
8
|
+
import { getMailboxKpis } from "../lib/mailbox-list.functions.js";
|
|
9
|
+
import { mailboxAuthNotices } from "./MailboxAuthBanner.js";
|
|
10
|
+
import { statusInfo, useMailboxStatus, useMailboxStatusNotices } from "./MailboxStatusLine.js";
|
|
11
|
+
import { PageHeader } from "./fs-ui/PageHeader.js";
|
|
12
|
+
import { UpdatedAt } from "./fs-ui/UpdatedAt.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
|
+
import { NoticeBar } from "./fs-ui/NoticeBar.js";
|
|
18
|
+
const TAB_PATH = {
|
|
19
|
+
voorstellen: "/mailbox-orders/voorstellen",
|
|
20
|
+
verwerkt: "/mailbox-orders/verwerkt",
|
|
21
|
+
overgeslagen: "/mailbox-orders/overgeslagen",
|
|
22
|
+
};
|
|
23
|
+
export const browserTz = () => {
|
|
24
|
+
try {
|
|
25
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return "UTC";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/** Zet een bewaard filter van de voorstellenlijst vóór het navigeren. */
|
|
32
|
+
export function setProposalFilter(key, value) {
|
|
33
|
+
try {
|
|
34
|
+
window.localStorage.setItem(`mailbox-proposals:${key}`, JSON.stringify(value));
|
|
35
|
+
}
|
|
36
|
+
catch { /* negeer */ }
|
|
37
|
+
}
|
|
38
|
+
export const SHORTCUTS = [
|
|
39
|
+
[["/"], "Zoeken"],
|
|
40
|
+
[["J", "K"], "Volgende / vorige rij"],
|
|
41
|
+
[["Enter"], "Geselecteerde rij openen"],
|
|
42
|
+
[["Esc"], "Zoeken wissen / sluiten"],
|
|
43
|
+
[["?"], "Dit overzicht"],
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Gezamenlijke opbouw van de drie mailboxpagina's, in de vaste volgorde:
|
|
47
|
+
* kop → meldingen → 4 KPI's → tabbladen → (children: werkbalk, tabel, paginering).
|
|
48
|
+
*/
|
|
49
|
+
export function MailboxPageFrame({ tab, children, onKpi, activeKpi, notices = [], helpOpen, onHelpOpenChange, }) {
|
|
50
|
+
const navigate = useNavigate();
|
|
51
|
+
const fetchActive = useServerFn(getActiveOrdersMailbox);
|
|
52
|
+
const fetchKpis = useServerFn(getMailboxKpis);
|
|
53
|
+
const ensureDefaults = useServerFn(ensureMailboxDefaultsFn);
|
|
54
|
+
const [localHelp, setLocalHelp] = useState(false);
|
|
55
|
+
const help = helpOpen ?? localHelp;
|
|
56
|
+
const setHelp = onHelpOpenChange ?? setLocalHelp;
|
|
57
|
+
// Standaardinstellingen één keer per paginabezoek aanvullen (niet bij elke lijstaanvraag).
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
void ensureDefaults().catch((e) => console.warn("[mailbox] standaardinstellingen", e));
|
|
60
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
61
|
+
const { data: activeMailbox } = useQuery({
|
|
62
|
+
queryKey: ["mailbox-active-account"],
|
|
63
|
+
queryFn: () => fetchActive(),
|
|
64
|
+
refetchInterval: 60000,
|
|
65
|
+
retry: 1,
|
|
66
|
+
});
|
|
67
|
+
const kpiQ = useQuery({
|
|
68
|
+
queryKey: ["mailbox-kpis"],
|
|
69
|
+
queryFn: () => fetchKpis({ data: { tz: browserTz() } }),
|
|
70
|
+
refetchInterval: 60000,
|
|
71
|
+
placeholderData: (prev) => prev,
|
|
72
|
+
});
|
|
73
|
+
const status = useMailboxStatus();
|
|
74
|
+
const statusNotices = useMailboxStatusNotices(status);
|
|
75
|
+
const k = (kpiQ.data ?? null);
|
|
76
|
+
const loading = kpiQ.isLoading;
|
|
77
|
+
const allNotices = [...mailboxAuthNotices(activeMailbox), ...statusNotices, ...notices];
|
|
78
|
+
const go = (t) => { if (t !== tab)
|
|
79
|
+
void navigate({ to: TAB_PATH[t] }); };
|
|
80
|
+
const kpi = (key) => {
|
|
81
|
+
if (onKpi && onKpi(key) === true)
|
|
82
|
+
return;
|
|
83
|
+
if (key === "approved_today") {
|
|
84
|
+
go("verwerkt");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (key === "today")
|
|
88
|
+
setProposalFilter("period", "today");
|
|
89
|
+
if (key === "customer_unknown")
|
|
90
|
+
setProposalFilter("filter", "klant_onbekend");
|
|
91
|
+
if (key === "pending") {
|
|
92
|
+
setProposalFilter("period", "all");
|
|
93
|
+
setProposalFilter("filter", null);
|
|
94
|
+
}
|
|
95
|
+
if (tab !== "voorstellen")
|
|
96
|
+
go("voorstellen");
|
|
97
|
+
};
|
|
98
|
+
return (_jsxs("main", { 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 min-w-0 flex-col gap-4 overflow-hidden overflow-x-clip p-4 pb-24 sm:p-6 md:pb-6", children: [_jsx(PageHeader, { title: "Mailbox bestellingen", meta: _jsx(UpdatedAt, { at: kpiQ.dataUpdatedAt || null, stale: kpiQ.isError, info: statusInfo(status) }) }), _jsx(NoticeBar, { notices: allNotices }), _jsxs(KpiRow, { children: [_jsx(KpiTile, { title: "Te controleren", value: k?.pending ?? 0, sub: "Bestellingen uit e-mail", icon: _jsx(ClipboardCheck, {}), loading: loading, active: activeKpi === "pending", onClick: () => kpi("pending") }), _jsx(KpiTile, { title: "Vandaag binnen", value: k?.pending_today ?? 0, sub: "Nog te controleren", icon: _jsx(CalendarClock, {}), loading: loading, active: activeKpi === "today", onClick: () => kpi("today") }), _jsx(KpiTile, { title: "Vandaag verwerkt", value: k?.approved_today ?? 0, sub: "Orders aangemaakt", icon: _jsx(CheckCircle2, {}), loading: loading, active: activeKpi === "approved_today", 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, active: activeKpi === "customer_unknown", onClick: () => kpi("customer_unknown") })] }), _jsx(PillTabs, { ariaLabel: "Mailbox", active: tab, onSelect: (t) => go(t), tabs: [
|
|
99
|
+
{ key: "voorstellen", label: "Te controleren", icon: _jsx(Inbox, {}), count: k ? k.pending : null },
|
|
100
|
+
{ key: "verwerkt", label: "Verwerkt", icon: _jsx(CheckCircle2, {}), count: k ? k.processed : null },
|
|
101
|
+
{ key: "overgeslagen", label: "Overgeslagen", icon: _jsx(MailX, {}), count: k ? k.skipped : null },
|
|
102
|
+
] }), children, _jsx(ShortcutHelp, { open: help, onOpenChange: setHelp, items: SHORTCUTS })] }));
|
|
103
|
+
}
|
|
@@ -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":"AA4BA,wBAAgB,oBAAoB,gCAmLnC"}
|
|
@@ -1,90 +1,131 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect,
|
|
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, Search } from "lucide-react";
|
|
8
|
+
import { Button } from "@flowselections/core";
|
|
9
|
+
import { reopenProposal } from "../lib/mailbox.functions.js";
|
|
10
|
+
import { listProposalsPage } from "../lib/mailbox-list.functions.js";
|
|
11
|
+
import { fmtDayTime } from "../lib/format-date.js";
|
|
12
|
+
import { label, PROPOSAL_STATUS } from "../lib/labels.js";
|
|
9
13
|
import { TablePagination } from "./TablePagination.js";
|
|
10
|
-
import {
|
|
14
|
+
import { usePersistedState } from "./MailboxFilterBar.js";
|
|
15
|
+
import { MailboxPageFrame, browserTz } from "./MailboxPageFrame.js";
|
|
16
|
+
import { DataTable, InitialsAvatar, CellText } from "./fs-ui/DataTable.js";
|
|
17
|
+
import { StatusIcon } from "./fs-ui/StatusIcon.js";
|
|
18
|
+
import { EmptyState } from "./fs-ui/EmptyState.js";
|
|
19
|
+
import { TableSkeleton } from "./fs-ui/TableSkeleton.js";
|
|
20
|
+
import { Toolbar } from "./fs-ui/Toolbar.js";
|
|
21
|
+
import { SearchInput } from "./fs-ui/SearchInput.js";
|
|
22
|
+
import { FilterChips } from "./fs-ui/FilterChips.js";
|
|
23
|
+
import { FilterPanel, FilterOptions, PERIOD_OPTIONS } from "./fs-ui/FilterPanel.js";
|
|
24
|
+
import { RowMenu } from "./fs-ui/RowMenu.js";
|
|
25
|
+
import { useListHotkeys } from "./fs-ui/useListHotkeys.js";
|
|
26
|
+
const PERIOD_LABEL = { today: "Vandaag", "7d": "Laatste 7 dagen", "30d": "Laatste 30 dagen" };
|
|
27
|
+
const COLS = [220, 300, 130, 140, 120];
|
|
11
28
|
export function MailboxProcessedPage() {
|
|
12
|
-
const fetchList = useServerFn(
|
|
29
|
+
const fetchList = useServerFn(listProposalsPage);
|
|
13
30
|
const reopen = useServerFn(reopenProposal);
|
|
14
|
-
const fetchActive = useServerFn(getActiveOrdersMailbox);
|
|
15
31
|
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
|
-
];
|
|
32
|
+
const navigate = useNavigate();
|
|
34
33
|
const [busyId, setBusyId] = useState(null);
|
|
35
34
|
const [page, setPage] = useState(1);
|
|
36
|
-
const [pageSize, setPageSize] = useState(
|
|
35
|
+
const [pageSize, setPageSize] = useState(50);
|
|
37
36
|
const [search, setSearch] = usePersistedState("mailbox-processed:search", "");
|
|
38
37
|
const [period, setPeriod] = usePersistedState("mailbox-processed:period", "all");
|
|
39
38
|
const [sortOrder, setSortOrder] = usePersistedState("mailbox-processed:sort", "date-desc");
|
|
40
39
|
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";
|
|
40
|
+
const [cursor, setCursor] = useState(null);
|
|
41
|
+
const [helpOpen, setHelpOpen] = useState(false);
|
|
42
|
+
const [filtersOpen, setFiltersOpen] = useState(false);
|
|
43
|
+
const searchRef = useRef(null);
|
|
44
|
+
const params = {
|
|
45
|
+
statuses: statusFilter === "approved" ? ["approved"] : statusFilter === "rejected" ? ["rejected"] : ["approved", "rejected"],
|
|
46
|
+
search,
|
|
47
|
+
period,
|
|
48
|
+
sort: sortOrder === "date-asc" ? "asc" : "desc",
|
|
49
|
+
dateField: "reviewed",
|
|
50
|
+
tz: browserTz(),
|
|
51
|
+
page,
|
|
52
|
+
pageSize,
|
|
53
|
+
};
|
|
54
|
+
const { data, isLoading, error, refetch } = useQuery({
|
|
55
|
+
queryKey: ["mailbox-proposals", "processed", params],
|
|
56
|
+
queryFn: () => fetchList({ data: params }),
|
|
57
|
+
placeholderData: (prev) => prev,
|
|
58
|
+
refetchInterval: 60000,
|
|
59
|
+
});
|
|
60
|
+
const items = Array.isArray(data?.items) ? data.items : [];
|
|
61
|
+
const total = Number(data?.total ?? 0);
|
|
62
|
+
const hasActiveFilters = !!search || period !== "all" || statusFilter !== "all";
|
|
66
63
|
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(
|
|
64
|
+
useEffect(() => { setPage(1); setCursor(null); }, [search, period, sortOrder, statusFilter]);
|
|
65
|
+
const pageCount = Math.max(1, Math.ceil(total / pageSize));
|
|
69
66
|
const currentPage = Math.min(page, pageCount);
|
|
70
|
-
const
|
|
67
|
+
const openOrder = (p) => {
|
|
68
|
+
if (p?.created_order_id)
|
|
69
|
+
void navigate({ to: `/floriday-verkoop/verkooporders/${p.created_order_id}` });
|
|
70
|
+
};
|
|
71
71
|
const handleReopen = async (proposalId) => {
|
|
72
72
|
setBusyId(proposalId);
|
|
73
73
|
try {
|
|
74
74
|
await reopen({ data: { proposalId } });
|
|
75
|
-
toast.success("
|
|
75
|
+
toast.success("Bestelling teruggezet naar 'Te controleren'.");
|
|
76
76
|
await qc.invalidateQueries({ queryKey: ["mailbox-proposals"] });
|
|
77
|
+
await qc.invalidateQueries({ queryKey: ["mailbox-kpis"] });
|
|
77
78
|
}
|
|
78
79
|
catch (e) {
|
|
79
|
-
|
|
80
|
+
console.warn("[mailbox] terugzetten", e);
|
|
81
|
+
toast.error("Terugzetten lukt niet. Probeer het opnieuw.");
|
|
80
82
|
}
|
|
81
83
|
finally {
|
|
82
84
|
setBusyId(null);
|
|
83
85
|
}
|
|
84
86
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
useListHotkeys({
|
|
88
|
+
disabled: helpOpen || filtersOpen,
|
|
89
|
+
onSearch: () => searchRef.current?.focus(),
|
|
90
|
+
onNext: () => setCursor((c) => (items.length ? Math.min((c ?? -1) + 1, items.length - 1) : null)),
|
|
91
|
+
onPrev: () => setCursor((c) => (items.length ? Math.max((c ?? 1) - 1, 0) : null)),
|
|
92
|
+
onOpen: cursor != null && items[cursor]?.created_order_id ? () => openOrder(items[cursor]) : undefined,
|
|
93
|
+
onEscape: hasActiveFilters ? clearFilters : undefined,
|
|
94
|
+
onHelp: () => setHelpOpen(true),
|
|
95
|
+
});
|
|
96
|
+
const nameOf = (p) => p.customer_name || p.from_name || p.from_email || "Onbekend";
|
|
97
|
+
const statusText = (p) => label(PROPOSAL_STATUS, p.status);
|
|
98
|
+
const statusOf = (p) => p.status === "approved"
|
|
99
|
+
? _jsx(StatusIcon, { tone: "done", label: statusText(p), detail: p.order_number ? `Order ${p.order_number}` : undefined })
|
|
100
|
+
: _jsx(StatusIcon, { tone: "rejected", label: statusText(p) });
|
|
101
|
+
const rowAction = (p) => (_jsx(RowMenu, { label: `Acties voor ${nameOf(p)}`, items: [
|
|
102
|
+
...(p.created_order_id ? [{ label: "Open order", onSelect: () => openOrder(p) }] : []),
|
|
103
|
+
...(p.status === "rejected" ? [{ label: busyId === p.id ? "Bezig…" : "Terugzetten naar te controleren", disabled: busyId === p.id, onSelect: () => void handleReopen(p.id) }] : []),
|
|
104
|
+
] }));
|
|
105
|
+
const columns = [
|
|
106
|
+
{
|
|
107
|
+
key: "klant", header: "Klant", width: COLS[0],
|
|
108
|
+
cell: (p) => (_jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [_jsx(InitialsAvatar, { name: nameOf(p) }), _jsx(CellText, { primary: nameOf(p), secondary: p.from_email ?? "", strong: true })] })),
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
key: "bericht", header: "Onderwerp", width: COLS[1],
|
|
112
|
+
cell: (p) => _jsx(CellText, { primary: p.subject || "(geen onderwerp)", secondary: String(p.preview ?? "").slice(0, 180) }),
|
|
113
|
+
},
|
|
114
|
+
{ key: "order", header: "Order", width: COLS[2], cell: (p) => _jsx("span", { className: "block truncate tabular-nums", children: p.order_number || "–" }) },
|
|
115
|
+
{
|
|
116
|
+
key: "datum", header: "Verwerkt op", width: COLS[3], sortable: true,
|
|
117
|
+
cell: (p) => _jsx("span", { className: "block truncate tabular-nums", children: fmtDayTime(p.reviewed_at) }),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
key: "status", header: "Status", width: COLS[4],
|
|
121
|
+
cell: (p) => (_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [statusOf(p), _jsx("span", { className: "truncate text-sm", children: statusText(p) })] })),
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
const chips = [
|
|
125
|
+
...(period !== "all" ? [{ key: "period", label: PERIOD_LABEL[period] ?? period, icon: _jsx(CalendarClock, {}), onRemove: () => setPeriod("all") }] : []),
|
|
126
|
+
...(statusFilter !== "all" ? [{ key: "status", label: label(PROPOSAL_STATUS, statusFilter), icon: _jsx(CheckCircle2, {}), onRemove: () => setStatusFilter("all") }] : []),
|
|
127
|
+
];
|
|
128
|
+
return (_jsxs(MailboxPageFrame, { tab: "verwerkt", helpOpen: helpOpen, onHelpOpenChange: setHelpOpen, activeKpi: period === "today" ? "approved_today" : null, children: [_jsx(Toolbar, { onOpenFilters: () => setFiltersOpen(true), filterCount: chips.length, chips: _jsx(FilterChips, { chips: chips, onClearAll: clearFilters }), children: _jsx(SearchInput, { ref: searchRef, value: search, onChange: setSearch, placeholder: "Zoek op klant, afzender of onderwerp" }) }), _jsxs(FilterPanel, { open: filtersOpen, onOpenChange: setFiltersOpen, onClear: clearFilters, children: [_jsx(FilterOptions, { label: "Periode", value: period, options: PERIOD_OPTIONS, onChange: (v) => setPeriod(v) }), _jsx(FilterOptions, { label: "Status", value: statusFilter, options: [{ value: "all", label: "Alle statussen" }, { value: "approved", label: "Goedgekeurd" }, { value: "rejected", label: "Afgewezen" }], onChange: setStatusFilter })] }), isLoading && !data ? (_jsx(TableSkeleton, { columns: COLS })) : error && !data ? (_jsx("div", { className: "rounded-xl border border-border bg-card shadow-sm", children: _jsx(EmptyState, { icon: _jsx(CheckCircle2, { className: "h-6 w-6" }), title: "De lijst kon niet worden geladen", text: "Probeer het opnieuw.", action: _jsx(Button, { size: "sm", variant: "outline", onClick: () => void refetch(), children: "Opnieuw proberen" }) }) })) : total === 0 ? (_jsx("div", { className: "rounded-xl border border-border bg-card shadow-sm", children: hasActiveFilters
|
|
129
|
+
? _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" }) })
|
|
130
|
+
: _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} · ` : "", fmtDayTime(p.reviewed_at)] })] })), footer: _jsx(TablePagination, { total: total, page: currentPage, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize }) }))] }));
|
|
90
131
|
}
|
|
@@ -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":"AA8HA,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,gCAsgBnC"}
|