@flowselections/mailbox-orders 1.0.55 → 1.0.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist-lib/components/EmailPreview.d.ts.map +1 -1
  2. package/dist-lib/components/EmailPreview.js +2 -1
  3. package/dist-lib/components/MailboxAuthBanner.d.ts +3 -3
  4. package/dist-lib/components/MailboxAuthBanner.d.ts.map +1 -1
  5. package/dist-lib/components/MailboxAuthBanner.js +18 -6
  6. package/dist-lib/components/MailboxPageFrame.d.ts +11 -5
  7. package/dist-lib/components/MailboxPageFrame.d.ts.map +1 -1
  8. package/dist-lib/components/MailboxPageFrame.js +24 -16
  9. package/dist-lib/components/MailboxProcessedPage.d.ts.map +1 -1
  10. package/dist-lib/components/MailboxProcessedPage.js +30 -21
  11. package/dist-lib/components/MailboxProposalsPage.d.ts.map +1 -1
  12. package/dist-lib/components/MailboxProposalsPage.js +38 -30
  13. package/dist-lib/components/MailboxSkippedPage.d.ts.map +1 -1
  14. package/dist-lib/components/MailboxSkippedPage.js +35 -23
  15. package/dist-lib/components/MailboxStatusLine.d.ts +7 -3
  16. package/dist-lib/components/MailboxStatusLine.d.ts.map +1 -1
  17. package/dist-lib/components/MailboxStatusLine.js +42 -19
  18. package/dist-lib/components/TablePagination.d.ts +2 -2
  19. package/dist-lib/components/TablePagination.d.ts.map +1 -1
  20. package/dist-lib/components/TablePagination.js +8 -12
  21. package/dist-lib/components/fs-ui/DataTable.d.ts +12 -6
  22. package/dist-lib/components/fs-ui/DataTable.d.ts.map +1 -1
  23. package/dist-lib/components/fs-ui/DataTable.js +26 -19
  24. package/dist-lib/components/fs-ui/FilterChips.d.ts +1 -1
  25. package/dist-lib/components/fs-ui/FilterChips.d.ts.map +1 -1
  26. package/dist-lib/components/fs-ui/FilterChips.js +3 -3
  27. package/dist-lib/components/fs-ui/FilterPanel.d.ts +32 -0
  28. package/dist-lib/components/fs-ui/FilterPanel.d.ts.map +1 -0
  29. package/dist-lib/components/fs-ui/FilterPanel.js +20 -0
  30. package/dist-lib/components/fs-ui/InlineAlert.d.ts +2 -2
  31. package/dist-lib/components/fs-ui/InlineAlert.d.ts.map +1 -1
  32. package/dist-lib/components/fs-ui/InlineAlert.js +4 -12
  33. package/dist-lib/components/fs-ui/KpiRow.js +1 -1
  34. package/dist-lib/components/fs-ui/NoticeBar.d.ts +18 -0
  35. package/dist-lib/components/fs-ui/NoticeBar.d.ts.map +1 -0
  36. package/dist-lib/components/fs-ui/NoticeBar.js +24 -0
  37. package/dist-lib/components/fs-ui/PageHeader.d.ts +1 -1
  38. package/dist-lib/components/fs-ui/PageHeader.d.ts.map +1 -1
  39. package/dist-lib/components/fs-ui/PageHeader.js +2 -2
  40. package/dist-lib/components/fs-ui/PillTabs.d.ts +3 -2
  41. package/dist-lib/components/fs-ui/PillTabs.d.ts.map +1 -1
  42. package/dist-lib/components/fs-ui/PillTabs.js +26 -11
  43. package/dist-lib/components/fs-ui/RowMenu.d.ts +13 -0
  44. package/dist-lib/components/fs-ui/RowMenu.d.ts.map +1 -0
  45. package/dist-lib/components/fs-ui/RowMenu.js +10 -0
  46. package/dist-lib/components/fs-ui/SearchInput.d.ts +2 -2
  47. package/dist-lib/components/fs-ui/SearchInput.d.ts.map +1 -1
  48. package/dist-lib/components/fs-ui/SearchInput.js +11 -6
  49. package/dist-lib/components/fs-ui/ShortcutHelp.d.ts +3 -3
  50. package/dist-lib/components/fs-ui/ShortcutHelp.d.ts.map +1 -1
  51. package/dist-lib/components/fs-ui/ShortcutHelp.js +2 -2
  52. package/dist-lib/components/fs-ui/TableSkeleton.d.ts +2 -2
  53. package/dist-lib/components/fs-ui/TableSkeleton.d.ts.map +1 -1
  54. package/dist-lib/components/fs-ui/TableSkeleton.js +2 -2
  55. package/dist-lib/components/fs-ui/Toolbar.d.ts +8 -3
  56. package/dist-lib/components/fs-ui/Toolbar.d.ts.map +1 -1
  57. package/dist-lib/components/fs-ui/Toolbar.js +8 -3
  58. package/dist-lib/components/fs-ui/UpdatedAt.d.ts +5 -4
  59. package/dist-lib/components/fs-ui/UpdatedAt.d.ts.map +1 -1
  60. package/dist-lib/components/fs-ui/UpdatedAt.js +12 -4
  61. package/dist-lib/integrations/supabase/types.d.ts +76 -0
  62. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  63. package/dist-lib/lib/format-date.d.ts +5 -0
  64. package/dist-lib/lib/format-date.d.ts.map +1 -0
  65. package/dist-lib/lib/format-date.js +30 -0
  66. package/dist-lib/lib/labels.d.ts +15 -0
  67. package/dist-lib/lib/labels.d.ts.map +1 -0
  68. package/dist-lib/lib/labels.js +57 -0
  69. package/dist-lib/lib/mailbox-list.functions.d.ts.map +1 -1
  70. package/dist-lib/lib/mailbox-list.functions.js +0 -2
  71. package/dist-lib/lib/mailbox.functions.js +3 -3
  72. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"EmailPreview.d.ts","sourceRoot":"","sources":["../../src/components/EmailPreview.tsx"],"names":[],"mappings":"AAIA,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC;IACtB,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAsEF,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,QAAQ,EACR,SAAS,EACT,UAAU,EACV,EAAO,EACP,EAAO,EACP,QAAQ,EACR,QAAQ,EACR,WAAgB,EAChB,cAAc,GACf,EAAE,KAAK,+BAsHP"}
1
+ {"version":3,"file":"EmailPreview.d.ts","sourceRoot":"","sources":["../../src/components/EmailPreview.tsx"],"names":[],"mappings":"AAKA,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC;IACtB,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAsEF,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,QAAQ,EACR,SAAS,EACT,UAAU,EACV,EAAO,EACP,EAAO,EACP,QAAQ,EACR,QAAQ,EACR,WAAgB,EAChB,cAAc,GACf,EAAE,KAAK,+BAsHP"}
@@ -1,4 +1,5 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { fmtDayTime } from "../lib/format-date.js";
2
3
  import { useEffect, useMemo, useState } from "react";
3
4
  import { Button, Badge } from "@flowselections/core";
4
5
  import { Paperclip, Download, Code, FileText, ShieldOff, Shield } from "lucide-react";
@@ -52,5 +53,5 @@ export function EmailPreview({ subject, fromName, fromEmail, receivedAt, to = []
52
53
  const rendered = blockRemoteContent ? blockRemote(html) : html;
53
54
  const safeAttachments = Array.isArray(attachments) ? attachments : [];
54
55
  const inlineOnly = safeAttachments.every((a) => !!a.contentId);
55
- return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsxs("div", { className: "shrink-0 space-y-1 border-b pb-3", children: [_jsx("div", { className: "text-base font-semibold leading-snug", children: subject || "(geen onderwerp)" }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [_jsx("span", { className: "font-medium text-foreground", children: fromName || fromEmail }), fromName && fromEmail ? ` <${fromEmail}>` : "", receivedAt ? ` · ${new Date(receivedAt).toLocaleString("nl-NL")}` : ""] }), _jsx(AddressLine, { label: "Aan", list: to }), _jsx(AddressLine, { label: "CC", list: cc }), (safeAttachments.length > 0 || hasAttachments) && (_jsxs("div", { className: "flex flex-wrap items-center gap-2 pt-2", children: [safeAttachments.length === 0 ? (_jsxs(Badge, { variant: "outline", className: "gap-1 font-normal", children: [_jsx(Paperclip, { className: "h-3 w-3" }), " Deze mail bevat bijlagen (nog niet opgehaald)"] })) : (safeAttachments.map((a, i) => (_jsxs("span", { className: "inline-flex items-center gap-1 rounded border bg-muted/40 px-2 py-1 text-xs", children: [_jsx(Paperclip, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "max-w-[16rem] truncate", children: a.name }), formatSize(a.size) && (_jsx("span", { className: "text-muted-foreground", children: formatSize(a.size) })), a.url && (_jsx("a", { href: a.url, target: "_blank", rel: "noopener noreferrer", className: "text-primary", "aria-label": `Download ${a.name}`, children: _jsx(Download, { className: "h-3 w-3" }) }))] }, `${a.name}-${i}`)))), safeAttachments.length > 0 && inlineOnly && (_jsx("span", { className: "text-[11px] text-muted-foreground", children: "(in de mail ingesloten afbeeldingen)" }))] })), _jsxs("div", { className: "flex flex-wrap items-center gap-2 pt-2", children: [_jsx(Button, { type: "button", size: "sm", variant: "outline", onClick: () => setMode(mode === "html" ? "text" : "html"), disabled: !html, children: mode === "html" ? (_jsxs(_Fragment, { children: [_jsx(FileText, { className: "mr-1 h-3.5 w-3.5" }), " Platte tekst"] })) : (_jsxs(_Fragment, { children: [_jsx(Code, { className: "mr-1 h-3.5 w-3.5" }), " Opgemaakte mail"] })) }), _jsx(Button, { type: "button", size: "sm", variant: "ghost", disabled: mode !== "html" || !html, onClick: () => setBlockRemoteContent((v) => !v), children: blockRemoteContent ? (_jsxs(_Fragment, { children: [_jsx(Shield, { className: "mr-1 h-3.5 w-3.5" }), " Externe inhoud tonen"] })) : (_jsxs(_Fragment, { children: [_jsx(ShieldOff, { className: "mr-1 h-3.5 w-3.5" }), " Externe inhoud blokkeren"] })) })] })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden pt-3", children: mode === "html" && html ? (_jsx(EmailFrame, { html: rendered })) : (_jsx("div", { className: "h-full w-full overflow-y-auto overscroll-contain rounded border bg-white p-3", children: _jsx("pre", { className: "whitespace-pre-wrap break-words font-sans text-sm leading-relaxed text-[#111]", children: bodyText || "(geen tekst)" }) })) })] }));
56
+ return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsxs("div", { className: "shrink-0 space-y-1 border-b pb-3", children: [_jsx("div", { className: "text-base font-semibold leading-snug", children: subject || "(geen onderwerp)" }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [_jsx("span", { className: "font-medium text-foreground", children: fromName || fromEmail }), fromName && fromEmail ? ` <${fromEmail}>` : "", receivedAt ? ` · ${fmtDayTime(receivedAt)}` : ""] }), _jsx(AddressLine, { label: "Aan", list: to }), _jsx(AddressLine, { label: "CC", list: cc }), (safeAttachments.length > 0 || hasAttachments) && (_jsxs("div", { className: "flex flex-wrap items-center gap-2 pt-2", children: [safeAttachments.length === 0 ? (_jsxs(Badge, { variant: "outline", className: "gap-1 font-normal", children: [_jsx(Paperclip, { className: "h-3 w-3" }), " Deze mail bevat bijlagen (nog niet opgehaald)"] })) : (safeAttachments.map((a, i) => (_jsxs("span", { className: "inline-flex items-center gap-1 rounded border bg-muted/40 px-2 py-1 text-xs", children: [_jsx(Paperclip, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "max-w-[16rem] truncate", children: a.name }), formatSize(a.size) && (_jsx("span", { className: "text-muted-foreground", children: formatSize(a.size) })), a.url && (_jsx("a", { href: a.url, target: "_blank", rel: "noopener noreferrer", className: "text-primary", "aria-label": `Download ${a.name}`, children: _jsx(Download, { className: "h-3 w-3" }) }))] }, `${a.name}-${i}`)))), safeAttachments.length > 0 && inlineOnly && (_jsx("span", { className: "text-[11px] text-muted-foreground", children: "(in de mail ingesloten afbeeldingen)" }))] })), _jsxs("div", { className: "flex flex-wrap items-center gap-2 pt-2", children: [_jsx(Button, { type: "button", size: "sm", variant: "outline", onClick: () => setMode(mode === "html" ? "text" : "html"), disabled: !html, children: mode === "html" ? (_jsxs(_Fragment, { children: [_jsx(FileText, { className: "mr-1 h-3.5 w-3.5" }), " Platte tekst"] })) : (_jsxs(_Fragment, { children: [_jsx(Code, { className: "mr-1 h-3.5 w-3.5" }), " Opgemaakte mail"] })) }), _jsx(Button, { type: "button", size: "sm", variant: "ghost", disabled: mode !== "html" || !html, onClick: () => setBlockRemoteContent((v) => !v), children: blockRemoteContent ? (_jsxs(_Fragment, { children: [_jsx(Shield, { className: "mr-1 h-3.5 w-3.5" }), " Externe inhoud tonen"] })) : (_jsxs(_Fragment, { children: [_jsx(ShieldOff, { className: "mr-1 h-3.5 w-3.5" }), " Externe inhoud blokkeren"] })) })] })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden pt-3", children: mode === "html" && html ? (_jsx(EmailFrame, { html: rendered })) : (_jsx("div", { className: "h-full w-full overflow-y-auto overscroll-contain rounded border bg-white p-3", children: _jsx("pre", { className: "whitespace-pre-wrap break-words font-sans text-sm leading-relaxed text-[#111]", children: bodyText || "(geen tekst)" }) })) })] }));
56
57
  }
@@ -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
- export declare function MailboxAuthBanner({ active }: {
16
- active: ActiveMailbox;
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":"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
+ {"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,18 +1,30 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { bannerKind } from "../lib/mailbox-active.js";
3
- import { InlineAlert } from "./fs-ui/InlineAlert.js";
4
3
  const settingsLink = (label) => (_jsx("a", { href: "/e-mail-authenticatie", className: "text-sm font-medium underline underline-offset-2", children: label }));
5
- export function MailboxAuthBanner({ active }) {
4
+ /** Meldingen over de koppeling van de mailbox (voor de NoticeBar onder de kop). */
5
+ export function mailboxAuthNotices(active) {
6
6
  const kind = bannerKind(active);
7
7
  if (kind === "unknown") {
8
- return (_jsx("div", { className: "shrink-0 text-xs text-muted-foreground", children: "De status van de mailbox kon niet worden opgehaald." }));
8
+ return [{ key: "auth-unknown", tone: "info", title: "De status van de mailbox kon niet worden opgehaald." }];
9
9
  }
10
10
  if (kind === "no_mailbox") {
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
+ 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
+ }];
12
18
  }
13
19
  if (kind === "reauth") {
14
20
  const a = active;
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." }));
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
+ }];
16
28
  }
17
- return null;
29
+ return [];
18
30
  }
@@ -1,18 +1,24 @@
1
1
  import { type ReactNode } from "react";
2
+ import { type Notice } from "./fs-ui/NoticeBar.js";
2
3
  export type MailboxTab = "voorstellen" | "verwerkt" | "overgeslagen";
4
+ export type MailboxKpiKey = "pending" | "today" | "approved_today" | "customer_unknown";
3
5
  export declare const browserTz: () => string;
4
6
  /** Zet een bewaard filter van de voorstellenlijst vóór het navigeren. */
5
7
  export declare function setProposalFilter(key: "period" | "filter", value: unknown): void;
6
- export declare const SHORTCUTS: Array<[string, string]>;
8
+ export declare const SHORTCUTS: Array<[string[], string]>;
7
9
  /**
8
- * Gezamenlijke opbouw van de drie mailboxpagina's: kop, meldingen, KPI's en
9
- * tabbladen. De lijst zelf komt als children.
10
+ * Gezamenlijke opbouw van de drie mailboxpagina's, in de vaste volgorde:
11
+ * kop → meldingen → 4 KPI's → tabbladen → (children: werkbalk, tabel, paginering).
10
12
  */
11
- export declare function MailboxPageFrame({ tab, children, onKpi, helpOpen, onHelpOpenChange, }: {
13
+ export declare function MailboxPageFrame({ tab, children, onKpi, activeKpi, notices, helpOpen, onHelpOpenChange, }: {
12
14
  tab: MailboxTab;
13
15
  children: ReactNode;
14
16
  /** Pagina handelt een KPI-klik zelf af (bijv. filter zetten); anders navigeren. */
15
- onKpi?: (key: "pending" | "today" | "approved_today" | "customer_unknown") => boolean | void;
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[];
16
22
  helpOpen?: boolean;
17
23
  onHelpOpenChange?: (v: boolean) => void;
18
24
  }): import("react").JSX.Element;
@@ -1 +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"}
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"}
@@ -1,19 +1,20 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import { useEffect, useState } from "react";
3
3
  import { useQuery } from "@tanstack/react-query";
4
4
  import { useServerFn } from "@tanstack/react-start";
5
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";
6
+ import { CalendarClock, CheckCircle2, ClipboardCheck, MailX, UserX, Inbox } from "lucide-react";
7
+ import { ensureMailboxDefaultsFn, getActiveOrdersMailbox } from "../lib/mailbox.functions.js";
9
8
  import { getMailboxKpis } from "../lib/mailbox-list.functions.js";
10
- import { MailboxAuthBanner } from "./MailboxAuthBanner.js";
11
- import { MailboxStatusLine, MailboxStatusMeta } from "./MailboxStatusLine.js";
9
+ import { mailboxAuthNotices } from "./MailboxAuthBanner.js";
10
+ import { statusInfo, useMailboxStatus, useMailboxStatusNotices } from "./MailboxStatusLine.js";
12
11
  import { PageHeader } from "./fs-ui/PageHeader.js";
12
+ import { UpdatedAt } from "./fs-ui/UpdatedAt.js";
13
13
  import { KpiRow } from "./fs-ui/KpiRow.js";
14
14
  import { KpiTile } from "./fs-ui/KpiTile.js";
15
15
  import { PillTabs } from "./fs-ui/PillTabs.js";
16
16
  import { ShortcutHelp } from "./fs-ui/ShortcutHelp.js";
17
+ import { NoticeBar } from "./fs-ui/NoticeBar.js";
17
18
  const TAB_PATH = {
18
19
  voorstellen: "/mailbox-orders/voorstellen",
19
20
  verwerkt: "/mailbox-orders/verwerkt",
@@ -35,24 +36,28 @@ export function setProposalFilter(key, value) {
35
36
  catch { /* negeer */ }
36
37
  }
37
38
  export const SHORTCUTS = [
38
- ["/", "Zoeken"],
39
- ["J", "Volgende rij"],
40
- ["K", "Vorige rij"],
41
- ["Enter", "Openen"],
42
- ["Esc", "Sluiten of wissen"],
43
- ["?", "Dit overzicht"],
39
+ [["/"], "Zoeken"],
40
+ [["J", "K"], "Volgende / vorige rij"],
41
+ [["Enter"], "Geselecteerde rij openen"],
42
+ [["Esc"], "Zoeken wissen / sluiten"],
43
+ [["?"], "Dit overzicht"],
44
44
  ];
45
45
  /**
46
- * Gezamenlijke opbouw van de drie mailboxpagina's: kop, meldingen, KPI's en
47
- * tabbladen. De lijst zelf komt als children.
46
+ * Gezamenlijke opbouw van de drie mailboxpagina's, in de vaste volgorde:
47
+ * kop → meldingen → 4 KPI's → tabbladen → (children: werkbalk, tabel, paginering).
48
48
  */
49
- export function MailboxPageFrame({ tab, children, onKpi, helpOpen, onHelpOpenChange, }) {
49
+ export function MailboxPageFrame({ tab, children, onKpi, activeKpi, notices = [], helpOpen, onHelpOpenChange, }) {
50
50
  const navigate = useNavigate();
51
51
  const fetchActive = useServerFn(getActiveOrdersMailbox);
52
52
  const fetchKpis = useServerFn(getMailboxKpis);
53
+ const ensureDefaults = useServerFn(ensureMailboxDefaultsFn);
53
54
  const [localHelp, setLocalHelp] = useState(false);
54
55
  const help = helpOpen ?? localHelp;
55
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
56
61
  const { data: activeMailbox } = useQuery({
57
62
  queryKey: ["mailbox-active-account"],
58
63
  queryFn: () => fetchActive(),
@@ -65,8 +70,11 @@ export function MailboxPageFrame({ tab, children, onKpi, helpOpen, onHelpOpenCha
65
70
  refetchInterval: 60000,
66
71
  placeholderData: (prev) => prev,
67
72
  });
73
+ const status = useMailboxStatus();
74
+ const statusNotices = useMailboxStatusNotices(status);
68
75
  const k = (kpiQ.data ?? null);
69
76
  const loading = kpiQ.isLoading;
77
+ const allNotices = [...mailboxAuthNotices(activeMailbox), ...statusNotices, ...notices];
70
78
  const go = (t) => { if (t !== tab)
71
79
  void navigate({ to: TAB_PATH[t] }); };
72
80
  const kpi = (key) => {
@@ -87,7 +95,7 @@ export function MailboxPageFrame({ tab, children, onKpi, helpOpen, onHelpOpenCha
87
95
  if (tab !== "voorstellen")
88
96
  go("voorstellen");
89
97
  };
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: [
98
+ return (_jsxs("main", { className: "flex w-full min-w-0 flex-col gap-4 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: [
91
99
  { key: "voorstellen", label: "Te controleren", icon: _jsx(Inbox, {}), count: k ? k.pending : null },
92
100
  { key: "verwerkt", label: "Verwerkt", icon: _jsx(CheckCircle2, {}), count: k ? k.processed : null },
93
101
  { key: "overgeslagen", label: "Overgeslagen", icon: _jsx(MailX, {}), count: k ? k.skipped : null },
@@ -1 +1 @@
1
- {"version":3,"file":"MailboxProcessedPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProcessedPage.tsx"],"names":[],"mappings":"AAwBA,wBAAgB,oBAAoB,gCAuMnC"}
1
+ {"version":3,"file":"MailboxProcessedPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProcessedPage.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,oBAAoB,gCAmLnC"}
@@ -1,26 +1,30 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
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
5
  import { useNavigate } from "@tanstack/react-router";
6
6
  import { toast } from "sonner";
7
- import { CalendarClock, CheckCircle2, Filter, Search, Undo2 } from "lucide-react";
8
- import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@flowselections/core";
7
+ import { CalendarClock, CheckCircle2, Search } from "lucide-react";
8
+ import { Button } from "@flowselections/core";
9
9
  import { reopenProposal } from "../lib/mailbox.functions.js";
10
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";
11
13
  import { TablePagination } from "./TablePagination.js";
12
14
  import { usePersistedState } from "./MailboxFilterBar.js";
13
15
  import { MailboxPageFrame, browserTz } from "./MailboxPageFrame.js";
14
- import { DataTable, InitialsAvatar } from "./fs-ui/DataTable.js";
16
+ import { DataTable, InitialsAvatar, CellText } from "./fs-ui/DataTable.js";
15
17
  import { StatusIcon } from "./fs-ui/StatusIcon.js";
16
18
  import { EmptyState } from "./fs-ui/EmptyState.js";
17
- import { InlineAlert } from "./fs-ui/InlineAlert.js";
18
19
  import { TableSkeleton } from "./fs-ui/TableSkeleton.js";
19
20
  import { Toolbar } from "./fs-ui/Toolbar.js";
20
21
  import { SearchInput } from "./fs-ui/SearchInput.js";
21
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";
22
25
  import { useListHotkeys } from "./fs-ui/useListHotkeys.js";
23
26
  const PERIOD_LABEL = { today: "Vandaag", "7d": "Laatste 7 dagen", "30d": "Laatste 30 dagen" };
27
+ const COLS = [220, 300, 130, 140, 120];
24
28
  export function MailboxProcessedPage() {
25
29
  const fetchList = useServerFn(listProposalsPage);
26
30
  const reopen = useServerFn(reopenProposal);
@@ -35,6 +39,7 @@ export function MailboxProcessedPage() {
35
39
  const [statusFilter, setStatusFilter] = usePersistedState("mailbox-processed:status", "all");
36
40
  const [cursor, setCursor] = useState(null);
37
41
  const [helpOpen, setHelpOpen] = useState(false);
42
+ const [filtersOpen, setFiltersOpen] = useState(false);
38
43
  const searchRef = useRef(null);
39
44
  const params = {
40
45
  statuses: statusFilter === "approved" ? ["approved"] : statusFilter === "rejected" ? ["rejected"] : ["approved", "rejected"],
@@ -80,7 +85,7 @@ export function MailboxProcessedPage() {
80
85
  }
81
86
  };
82
87
  useListHotkeys({
83
- disabled: helpOpen,
88
+ disabled: helpOpen || filtersOpen,
84
89
  onSearch: () => searchRef.current?.focus(),
85
90
  onNext: () => setCursor((c) => (items.length ? Math.min((c ?? -1) + 1, items.length - 1) : null)),
86
91
  onPrev: () => setCursor((c) => (items.length ? Math.max((c ?? 1) - 1, 0) : null)),
@@ -89,34 +94,38 @@ export function MailboxProcessedPage() {
89
94
  onHelp: () => setHelpOpen(true),
90
95
  });
91
96
  const nameOf = (p) => p.customer_name || p.from_name || p.from_email || "Onbekend";
97
+ const statusText = (p) => label(PROPOSAL_STATUS, p.status);
92
98
  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;
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
+ ] }));
96
105
  const columns = [
97
106
  {
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 ?? "" })] })] })),
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 })] })),
100
109
  },
101
110
  {
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) })] })),
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) }),
104
113
  },
105
- { key: "order", header: "Order", width: "130px", cell: (p) => _jsx("span", { className: "tabular-nums", children: p.order_number || "–" }) },
114
+ { key: "order", header: "Order", width: COLS[2], cell: (p) => _jsx("span", { className: "block truncate tabular-nums", children: p.order_number || "–" }) },
106
115
  {
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" }) : "–" }),
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) }),
109
118
  },
110
119
  {
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" })] })),
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) })] })),
113
122
  },
114
123
  ];
115
124
  const chips = [
116
125
  ...(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") }] : []),
126
+ ...(statusFilter !== "all" ? [{ key: "status", label: label(PROPOSAL_STATUS, statusFilter), icon: _jsx(CheckCircle2, {}), onRemove: () => setStatusFilter("all") }] : []),
118
127
  ];
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
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
120
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" }) })
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 }) }))] }));
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 }) }))] }));
122
131
  }
@@ -1 +1 @@
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"}
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"}
@@ -4,7 +4,7 @@ import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";
4
4
  import { useServerFn } from "@tanstack/react-start";
5
5
  import { useNavigate } from "@tanstack/react-router";
6
6
  import { Button, Badge, Card, CardContent, CardHeader, CardTitle, Input, Label, Textarea, Switch, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Dialog, DialogContent, DialogHeader, DialogTitle, toast, } from "@flowselections/core";
7
- import { Check, X, Trash2, Plus, AlertTriangle, RefreshCw, CalendarClock, UserX, Filter, Search, Inbox, ClipboardCheck } from "lucide-react";
7
+ import { Check, X, Trash2, Plus, AlertTriangle, RefreshCw, CalendarClock, UserX, Search, Inbox, ClipboardCheck } from "lucide-react";
8
8
  import { getProposalDetail, approveProposal, rejectProposal, getStickerDefaults, listCustomersForPicker, createCustomerFromGroup, listProductsForPicker, listDeliveryLocationsForCustomer, listPickupLocations, listCarriersForPicker, getActiveOrdersMailbox, syncMailboxNow, refreshProposalsForAgentChange, reparseProposalNow, listBeladingOptionsForProducts, listAllowedLoadCarriers, getDeparturePreview, getAgreementPrices, countOutdatedProposals, } from "../lib/mailbox.functions.js";
9
9
  import { normalizeUnitKind, toPlants, describeConversion, lineTotal, UNIT_KIND_LABEL, } from "../lib/mailbox-units.js";
10
10
  import { enabledLoadCarriers, normalizeAllowedLoadCarriers, EMPTY_LOAD_CARRIERS } from "../lib/load-carriers.js";
@@ -13,10 +13,11 @@ import { SearchableSelect } from "./SearchableSelect.js";
13
13
  import { AI_AUTH_PATH } from "./MailboxStatusLine.js";
14
14
  import { listProposalsPage } from "../lib/mailbox-list.functions.js";
15
15
  import { MailboxPageFrame, browserTz } from "./MailboxPageFrame.js";
16
- import { DataTable, InitialsAvatar } from "./fs-ui/DataTable.js";
16
+ import { DataTable, InitialsAvatar, CellText } from "./fs-ui/DataTable.js";
17
+ import { FilterPanel, FilterOptions, PERIOD_OPTIONS } from "./fs-ui/FilterPanel.js";
18
+ import { fmtDay, fmtDayTime } from "../lib/format-date.js";
17
19
  import { StatusIcon } from "./fs-ui/StatusIcon.js";
18
20
  import { EmptyState } from "./fs-ui/EmptyState.js";
19
- import { InlineAlert } from "./fs-ui/InlineAlert.js";
20
21
  import { TableSkeleton } from "./fs-ui/TableSkeleton.js";
21
22
  import { Toolbar } from "./fs-ui/Toolbar.js";
22
23
  import { SearchInput } from "./fs-ui/SearchInput.js";
@@ -130,8 +131,14 @@ export function MailboxProposalsPage() {
130
131
  const [listFilter, setListFilter] = usePersistedState("mailbox-proposals:filter", null);
131
132
  const [cursor, setCursor] = useState(null);
132
133
  const [helpOpen, setHelpOpen] = useState(false);
134
+ const [filtersOpen, setFiltersOpen] = useState(false);
133
135
  const searchRef = useRef(null);
134
- const refsEnabled = true;
136
+ // Zware keuzelijsten (klanten, artikelen, …) pas laden zodra een voorstel
137
+ // voor het eerst geopend wordt; daarna blijven ze in de cache.
138
+ const [refsWanted, setRefsWanted] = useState(false);
139
+ useEffect(() => { if (activeId)
140
+ setRefsWanted(true); }, [activeId]);
141
+ const refsEnabled = refsWanted;
135
142
  const refOpts = {
136
143
  enabled: refsEnabled,
137
144
  staleTime: 5 * 60000,
@@ -349,7 +356,7 @@ export function MailboxProposalsPage() {
349
356
  }
350
357
  };
351
358
  useListHotkeys({
352
- disabled: !!activeId || helpOpen,
359
+ disabled: !!activeId || helpOpen || filtersOpen,
353
360
  onSearch: () => searchRef.current?.focus(),
354
361
  onNext: () => setCursor((c) => (items.length ? Math.min((c ?? -1) + 1, items.length - 1) : null)),
355
362
  onPrev: () => setCursor((c) => (items.length ? Math.max((c ?? 1) - 1, 0) : null)),
@@ -362,37 +369,41 @@ export function MailboxProposalsPage() {
362
369
  ...(period !== "all" ? [{ key: "period", label: periodLabel[period] ?? period, icon: _jsx(CalendarClock, {}), onRemove: () => setPeriod("all") }] : []),
363
370
  ...(listFilter === "klant_onbekend" ? [{ key: "klant", label: "Klant onbekend", icon: _jsx(UserX, {}), onRemove: () => setListFilter(null) }] : []),
364
371
  ];
372
+ const activeKpi = listFilter === "klant_onbekend" ? "customer_unknown" : period === "today" ? "today" : null;
365
373
  const columns = [
366
374
  {
367
- key: "klant", header: "Klant", width: "minmax(180px,1.4fr)",
375
+ key: "klant", header: "Klant", width: 220,
368
376
  cell: (p) => {
369
377
  const name = customerNameFor(p);
370
- return (_jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [_jsx(InitialsAvatar, { name: name }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-medium", children: name }), !p.customer_name && _jsx("div", { className: "truncate text-xs text-muted-foreground", children: "Klant nog niet herkend" })] })] }));
378
+ return (_jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [_jsx(InitialsAvatar, { name: name }), _jsx(CellText, { primary: name, secondary: p.customer_name ? undefined : "Klant nog niet herkend", strong: true })] }));
371
379
  },
372
380
  },
373
381
  {
374
- key: "bericht", header: "Bericht", width: "minmax(240px,2.2fr)",
375
- cell: (p) => (_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-medium", children: p.mailbox_messages?.subject || "(geen onderwerp)" }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: p.mailbox_messages?.preview || "Geen voorbeeldtekst" })] })),
382
+ key: "bericht", header: "Bericht", width: 320,
383
+ cell: (p) => _jsx(CellText, { primary: p.mailbox_messages?.subject || "(geen onderwerp)", secondary: p.mailbox_messages?.preview || "Geen voorbeeldtekst" }),
376
384
  },
377
385
  {
378
- key: "ontvangen_op", header: "Ontvangen op", width: "minmax(140px,1fr)",
379
- cell: (p) => _jsx("span", { className: "block truncate text-xs text-muted-foreground", children: p.mailbox_messages?.account_email || "–" }),
386
+ key: "ontvangen_op", header: "Mailadres", width: 180,
387
+ cell: (p) => _jsx(CellText, { primary: p.mailbox_messages?.account_email || "–" }),
380
388
  },
381
389
  {
382
- key: "datum", header: "Ontvangen", width: "120px", sortable: true,
383
- cell: (p) => {
384
- const d = p.mailbox_messages?.received_at ?? p.created_at;
385
- return _jsx("span", { className: "tabular-nums text-muted-foreground", children: d ? new Date(d).toLocaleDateString("nl-NL") : "–" });
386
- },
390
+ key: "datum", header: "Ontvangen", width: 132, sortable: true,
391
+ cell: (p) => _jsx("span", { className: "block truncate tabular-nums", children: fmtDayTime(p.mailbox_messages?.received_at ?? p.created_at) }),
387
392
  },
388
393
  {
389
- key: "status", header: "Status", width: "150px",
394
+ key: "status", header: "Status", width: 120,
390
395
  cell: (p) => (_jsxs("div", { className: "flex items-center gap-2", children: [p.readiness === "klaar"
391
396
  ? _jsx(StatusIcon, { tone: "done", label: "Klaar om te bevestigen" })
392
- : _jsx(StatusIcon, { tone: "open", label: "Te controleren", detail: "Controleer de gegevens en bevestig de bestelling." }), _jsx("span", { className: "truncate text-xs text-muted-foreground", children: p.readiness === "klaar" ? "Klaar" : "Controleren" }), p.duplicate && _jsx(StatusIcon, { tone: "busy", label: "Mogelijk dubbel", detail: "Deze mail lijkt op een eerdere bestelling." })] })),
397
+ : _jsx(StatusIcon, { tone: "open", label: "Te controleren", detail: "Controleer de gegevens en bevestig de bestelling." }), p.duplicate && _jsx(StatusIcon, { tone: "busy", label: "Mogelijk dubbel", detail: "Deze mail lijkt op een eerdere bestelling." })] })),
393
398
  },
394
399
  ];
395
- return (_jsxs(MailboxPageFrame, { tab: "voorstellen", helpOpen: helpOpen, onHelpOpenChange: setHelpOpen, onKpi: (k) => {
400
+ const pageNotices = outdatedCount > 0 ? [{
401
+ key: "outdated",
402
+ tone: "warning",
403
+ title: `${outdatedCount} ${outdatedCount === 1 ? "bestelling is" : "bestellingen zijn"} met de vorige instelling uitgelezen.`,
404
+ action: (_jsx(Button, { size: "sm", variant: "outline", disabled: agentRefreshMut.isPending, onClick: () => agentRefreshMut.mutate(), children: agentRefreshMut.isPending ? "Bezig…" : "Opnieuw uitlezen" })),
405
+ }] : [];
406
+ return (_jsxs(MailboxPageFrame, { tab: "voorstellen", helpOpen: helpOpen, onHelpOpenChange: setHelpOpen, activeKpi: activeKpi, notices: pageNotices, onKpi: (k) => {
396
407
  if (k === "today") {
397
408
  setListFilter(null);
398
409
  setPeriod("today");
@@ -408,11 +419,11 @@ export function MailboxProposalsPage() {
408
419
  return true;
409
420
  }
410
421
  return false;
411
- }, children: [outdatedCount > 0 && (_jsx(InlineAlert, { tone: "warning", title: `${outdatedCount} bestelling(en) zijn met de vorige instelling uitgelezen.`, action: _jsx(Button, { size: "sm", variant: "outline", disabled: agentRefreshMut.isPending, onClick: () => agentRefreshMut.mutate(), children: agentRefreshMut.isPending ? "Bezig…" : "Opnieuw uitlezen" }) })), _jsx(Toolbar, { chips: _jsx(FilterChips, { chips: chips, onClearAll: clearFilters }), right: _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", "1fr", "120px", "150px"] })) : listError && !data ? (_jsx(InlineAlert, { tone: "error", title: "De lijst kon niet worden geladen.", action: _jsx(Button, { size: "sm", variant: "outline", onClick: () => void refetchList(), children: "Opnieuw proberen" }), children: "Je bestellingen zijn er nog; ze worden alleen nu niet getoond. Probeer het opnieuw." })) : total === 0 ? (_jsx("div", { className: "rounded-xl border border-border bg-card shadow-sm", children: hasActiveFilters ? (_jsx(EmptyState, { icon: _jsx(Search, { className: "h-6 w-6" }), title: "Niets gevonden", text: "Er zijn geen bestellingen die bij je zoekopdracht of filters passen.", action: _jsx(Button, { size: "sm", variant: "outline", onClick: clearFilters, children: "Filters wissen" }) })) : (_jsx(EmptyState, { icon: _jsx(Inbox, { className: "h-6 w-6" }), title: "Geen bestellingen om te controleren", text: "Nieuwe bestellingen uit je mailbox verschijnen hier vanzelf." })) })) : (_jsx(DataTable, { rows: items, columns: columns, rowKey: (p) => p.id, activeIndex: cursor, onRowClick: (p, i) => { setCursor(i); setActiveId(p.id); }, sort: { key: "datum", dir: sortOrder === "date-asc" ? "asc" : "desc" }, onSortChange: () => setSortOrder(sortOrder === "date-asc" ? "date-desc" : "date-asc"), mobileCard: (p) => {
422
+ }, 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: "Klant", value: listFilter ?? "all", options: [{ value: "all", label: "Alle klanten" }, { value: "klant_onbekend", label: "Klant onbekend" }], onChange: (v) => setListFilter(v === "klant_onbekend" ? "klant_onbekend" : null) })] }), isLoading && !data ? (_jsx(TableSkeleton, { columns: [220, 320, 180, 132, 120] })) : listError && !data ? (_jsx("div", { className: "rounded-xl border border-border bg-card shadow-sm", children: _jsx(EmptyState, { icon: _jsx(Inbox, { className: "h-6 w-6" }), title: "De lijst kon niet worden geladen", text: "Je bestellingen zijn er nog; ze worden alleen nu niet getoond.", action: _jsx(Button, { size: "sm", variant: "outline", onClick: () => void refetchList(), children: "Opnieuw proberen" }) }) })) : total === 0 ? (_jsx("div", { className: "rounded-xl border border-border bg-card shadow-sm", children: hasActiveFilters ? (_jsx(EmptyState, { icon: _jsx(Search, { className: "h-6 w-6" }), title: "Niets gevonden", text: "Er zijn geen bestellingen die bij je zoekopdracht of filters passen.", action: _jsx(Button, { size: "sm", variant: "outline", onClick: clearFilters, children: "Filters wissen" }) })) : (_jsx(EmptyState, { icon: _jsx(Inbox, { className: "h-6 w-6" }), title: "Geen bestellingen om te controleren", text: "Nieuwe bestellingen uit je mailbox verschijnen hier vanzelf." })) })) : (_jsx(DataTable, { rows: items, columns: columns, rowKey: (p) => p.id, activeIndex: cursor, onRowClick: (p, i) => { setCursor(i); setActiveId(p.id); }, sort: { key: "datum", dir: sortOrder === "date-asc" ? "asc" : "desc" }, onSortChange: () => setSortOrder(sortOrder === "date-asc" ? "date-desc" : "date-asc"), mobileCard: (p) => {
412
423
  const d = p.mailbox_messages?.received_at ?? p.created_at;
413
424
  return (_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: customerNameFor(p) }), p.readiness === "klaar"
414
425
  ? _jsx(StatusIcon, { tone: "done", label: "Klaar om te bevestigen" })
415
- : _jsx(StatusIcon, { tone: "open", label: "Te controleren" })] }), _jsx("div", { className: "truncate text-muted-foreground", children: p.mailbox_messages?.subject || "(geen onderwerp)" }), _jsxs("div", { className: "text-xs tabular-nums text-muted-foreground", children: [d ? new Date(d).toLocaleDateString("nl-NL") : "–", p.duplicate ? " · mogelijk dubbel" : ""] })] }));
426
+ : _jsx(StatusIcon, { tone: "open", label: "Te controleren" })] }), _jsx("div", { className: "truncate text-muted-foreground", children: p.mailbox_messages?.subject || "(geen onderwerp)" }), _jsxs("div", { className: "text-xs tabular-nums text-muted-foreground", children: [fmtDayTime(d), p.duplicate ? " · mogelijk dubbel" : ""] })] }));
416
427
  }, footer: _jsx(TablePagination, { total: total, page: currentPage, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize }) })), _jsx("span", { className: "sr-only", "aria-live": "polite", children: dataUpdatedAt ? `${total} bestellingen` : "" }), _jsx(MobilePrimaryAction, { label: "Volgende controleren", icon: _jsx(ClipboardCheck, {}), onClick: () => void openOldest(), hidden: !!activeId || total === 0 }), _jsx(Dialog, { open: !!activeId, onOpenChange: (o) => { if (!o) {
417
428
  setActiveId(null);
418
429
  setReparseError(null);
@@ -694,8 +705,8 @@ function ProposalEditor({ proposal, template, customers, products, allowBackorde
694
705
  const preview = (previewData?.ok ? previewData.preview : null);
695
706
  const previewError = previewData?.ok === false ? String(previewData.error ?? "") : null;
696
707
  const dateFeasible = preview?.ok === true && preview?.deliveryDateFeasible === true;
697
- const fmtDate = (iso) => iso ? new Date(`${iso}T12:00:00`).toLocaleDateString("nl-NL", { weekday: "long", day: "numeric", month: "long", year: "numeric" }) : "";
698
- const fmtDateTime = (iso) => iso ? new Date(iso).toLocaleString("nl-NL", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }) : "";
708
+ const fmtDate = (iso) => iso ? fmtDay(iso) : "";
709
+ const fmtDateTime = (iso) => iso ? fmtDayTime(iso) : "";
699
710
  // ─── Prijsafspraak ter vergelijking ───────────────────────────────────────
700
711
  const fetchAgreement = useServerFn(getAgreementPrices);
701
712
  const agreementKey = lines.map((l) => `${l.product_id}:${l.quantity}`).join(",");
@@ -1127,7 +1138,7 @@ function NewCustomerDialog({ candidate, onClose, onCreated, }) {
1127
1138
  }
1128
1139
  function DynamicField({ field, value, meta, onChange, customers, products, plantTypes, suppliers, onSelectCustomer, }) {
1129
1140
  const reviewClass = meta?.needs_review ? "border-warning/30 ring-1 ring-warning/40 rounded-md p-2" : "";
1130
- const label = (_jsxs(Label, { className: "flex items-center gap-2", children: [field.label, field.required && _jsx("span", { className: "text-destructive", children: "*" }), meta?.needs_review && (_jsx(Badge, { variant: "outline", className: "text-xs border-warning/30 text-warning-soft-foreground", children: "Controleren" })), typeof meta?.ai_confidence === "number" && (_jsxs("span", { className: "text-xs text-muted-foreground", children: [Math.round(meta.ai_confidence * 100), "%"] }))] }));
1141
+ const label = (_jsxs(Label, { className: "flex items-center gap-2", children: [field.label, field.required && _jsx("span", { className: "text-destructive", children: "*" }), meta?.needs_review && (_jsx(StatusIcon, { tone: "busy", label: "Controleren", detail: "Dit veld is niet zeker uit de mail gehaald." })), typeof meta?.ai_confidence === "number" && (_jsxs("span", { className: "text-xs text-muted-foreground", children: [Math.round(meta.ai_confidence * 100), "%"] }))] }));
1131
1142
  const renderControl = () => {
1132
1143
  switch (field.field_type) {
1133
1144
  case "text":
@@ -1172,12 +1183,9 @@ function ConfBadge({ meta, thresholds, }) {
1172
1183
  if (!meta)
1173
1184
  return null;
1174
1185
  const c = Math.max(0, Math.min(1, Number(meta.confidence ?? 0)));
1175
- const cls = c >= thresholds.green
1176
- ? "border-primary/30 bg-primary/10 text-primary"
1177
- : c >= thresholds.orange
1178
- ? "border-warning/30 bg-warning-soft text-warning-soft-foreground"
1179
- : "border-destructive/40 bg-destructive/5 text-destructive";
1180
- return (_jsxs("span", { className: `inline-flex items-center rounded border px-1.5 py-0.5 text-[11px] ${cls}`, children: [Math.round(c * 100), "% \u00B7 ", meta.source] }));
1186
+ const tone = c >= thresholds.green ? "done" : c >= thresholds.orange ? "busy" : "error";
1187
+ const text = c >= thresholds.green ? "Zeker" : c >= thresholds.orange ? "Controleren" : "Onzeker";
1188
+ return (_jsxs("span", { className: "inline-flex items-center gap-1 text-[11px] font-normal text-muted-foreground", children: [_jsx(StatusIcon, { tone: tone, label: text, detail: `${Math.round(c * 100)}% zeker · ${meta.source}` }), text] }));
1181
1189
  }
1182
1190
  function LateSignupChoice({ open, setOpen, reason, setReason }) {
1183
1191
  if (!open) {
@@ -1 +1 @@
1
- {"version":3,"file":"MailboxSkippedPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxSkippedPage.tsx"],"names":[],"mappings":"AAuCA,wBAAgB,kBAAkB,gCAyLjC"}
1
+ {"version":3,"file":"MailboxSkippedPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxSkippedPage.tsx"],"names":[],"mappings":"AA0CA,wBAAgB,kBAAkB,gCAoKjC"}