@flowselections/mailbox-orders 1.0.13 → 1.0.15

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.
@@ -0,0 +1,31 @@
1
+ /** State die bewaard blijft in localStorage (per pagina-sleutel). */
2
+ export declare function usePersistedState<T>(key: string, initial: T): readonly [T, import("react").Dispatch<import("react").SetStateAction<T>>];
3
+ export type PeriodValue = "all" | "today" | "7d" | "30d";
4
+ export type SortOrderValue = "date-desc" | "date-asc";
5
+ /** Hoofdletter- en accent-ongevoelig normaliseren voor zoeken. */
6
+ export declare function normalizeText(value: unknown): string;
7
+ /** Valt een datum binnen de gekozen periode? */
8
+ export declare function matchesPeriod(date: unknown, period: PeriodValue): boolean;
9
+ interface Props {
10
+ search: string;
11
+ onSearchChange: (value: string) => void;
12
+ period: PeriodValue;
13
+ onPeriodChange: (value: PeriodValue) => void;
14
+ sortOrder: SortOrderValue;
15
+ onSortOrderChange: (value: SortOrderValue) => void;
16
+ status?: string;
17
+ onStatusChange?: (value: string) => void;
18
+ statusOptions?: {
19
+ value: string;
20
+ label: string;
21
+ }[];
22
+ filteredCount: number;
23
+ totalCount: number;
24
+ countLabel?: string;
25
+ onClear: () => void;
26
+ hasActiveFilters: boolean;
27
+ searchPlaceholder?: string;
28
+ }
29
+ export declare function MailboxFilterBar({ search, onSearchChange, period, onPeriodChange, sortOrder, onSortOrderChange, status, onStatusChange, statusOptions, filteredCount, totalCount, countLabel, onClear, hasActiveFilters, searchPlaceholder, }: Props): import("react").JSX.Element;
30
+ export {};
31
+ //# sourceMappingURL=MailboxFilterBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MailboxFilterBar.d.ts","sourceRoot":"","sources":["../../src/components/MailboxFilterBar.tsx"],"names":[],"mappings":"AAOA,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,6EAkB3D;AAED,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK,CAAC;AACzD,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,CAAC;AAEtD,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKpD;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAYzE;AAED,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB,cAAc,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,cAAc,CAAC;IAC1B,iBAAiB,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,aAAa,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAoBD,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,cAAc,EAAE,aAAa,EACrC,aAAa,EAAE,UAAU,EAAE,UAA0B,EACrD,OAAO,EAAE,gBAAgB,EACzB,iBAAkE,GACnE,EAAE,KAAK,+BA6FP"}
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
3
+ import { Search, X, ArrowDown, ArrowUp } from "lucide-react";
4
+ import { useEffect, useState } from "react";
5
+ /** State die bewaard blijft in localStorage (per pagina-sleutel). */
6
+ export function usePersistedState(key, initial) {
7
+ const [value, setValue] = useState(initial);
8
+ const [hydrated, setHydrated] = useState(false);
9
+ useEffect(() => {
10
+ try {
11
+ const raw = window.localStorage.getItem(key);
12
+ if (raw !== null)
13
+ setValue(JSON.parse(raw));
14
+ }
15
+ catch { /* negeer */ }
16
+ setHydrated(true);
17
+ }, [key]);
18
+ useEffect(() => {
19
+ if (!hydrated)
20
+ return;
21
+ try {
22
+ window.localStorage.setItem(key, JSON.stringify(value));
23
+ }
24
+ catch { /* negeer */ }
25
+ }, [key, value, hydrated]);
26
+ return [value, setValue];
27
+ }
28
+ /** Hoofdletter- en accent-ongevoelig normaliseren voor zoeken. */
29
+ export function normalizeText(value) {
30
+ return String(value ?? "")
31
+ .normalize("NFD")
32
+ .replace(/[\u0300-\u036f]/g, "")
33
+ .toLowerCase();
34
+ }
35
+ /** Valt een datum binnen de gekozen periode? */
36
+ export function matchesPeriod(date, period) {
37
+ if (period === "all")
38
+ return true;
39
+ if (!date)
40
+ return false;
41
+ const d = new Date(date);
42
+ if (Number.isNaN(d.getTime()))
43
+ return false;
44
+ const now = new Date();
45
+ if (period === "today") {
46
+ return d.toDateString() === now.toDateString();
47
+ }
48
+ const days = period === "7d" ? 7 : 30;
49
+ const from = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
50
+ return d.getTime() >= from.getTime();
51
+ }
52
+ function Chip({ label, onRemove }) {
53
+ return (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full border bg-muted/40 px-2.5 py-1 text-xs", children: [label, _jsx("button", { type: "button", "aria-label": `${label} verwijderen`, onClick: onRemove, className: "text-muted-foreground hover:text-foreground", children: _jsx(X, { className: "h-3 w-3" }) })] }));
54
+ }
55
+ const PERIOD_LABELS = {
56
+ all: "Alle periodes",
57
+ today: "Vandaag",
58
+ "7d": "Laatste 7 dagen",
59
+ "30d": "Laatste 30 dagen",
60
+ };
61
+ export function MailboxFilterBar({ search, onSearchChange, period, onPeriodChange, sortOrder, onSortOrderChange, status, onStatusChange, statusOptions, filteredCount, totalCount, countLabel = "voorstellen", onClear, hasActiveFilters, searchPlaceholder = "Zoek op klant, afzender, onderwerp of tekst…", }) {
62
+ const sortIcon = sortOrder === "date-desc"
63
+ ? _jsx(ArrowDown, { className: "h-4 w-4 text-muted-foreground" })
64
+ : _jsx(ArrowUp, { className: "h-4 w-4 text-muted-foreground" });
65
+ const statusLabel = statusOptions?.find((o) => o.value === status)?.label;
66
+ return (_jsxs("div", { className: "flex flex-col gap-2 shrink-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("div", { className: "relative min-w-[240px] flex-1 max-w-md", children: [_jsx(Search, { className: "pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { value: search, onChange: (e) => onSearchChange(e.target.value), placeholder: searchPlaceholder, className: "h-9 pl-8 pr-8" }), search && (_jsx("button", { type: "button", "aria-label": "Zoekopdracht wissen", className: "absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground", onClick: () => onSearchChange(""), children: _jsx(X, { className: "h-4 w-4" }) }))] }), _jsxs(Select, { value: period, onValueChange: (v) => onPeriodChange(v), children: [_jsx(SelectTrigger, { className: "h-9 w-[170px]", children: _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" })] })] }), _jsxs(Select, { value: sortOrder, onValueChange: (v) => onSortOrderChange(v), children: [_jsxs(SelectTrigger, { className: "h-9 w-[210px] flex items-center gap-2", children: [sortIcon, _jsx(SelectValue, {})] }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "date-desc", children: "Datum: nieuwste eerst" }), _jsx(SelectItem, { value: "date-asc", children: "Datum: oudste eerst" })] })] }), statusOptions && onStatusChange && (_jsxs(Select, { value: status ?? "all", onValueChange: onStatusChange, children: [_jsx(SelectTrigger, { className: "h-9 w-[160px]", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: statusOptions.map((o) => (_jsx(SelectItem, { value: o.value, children: o.label }, o.value))) })] })), _jsxs("div", { className: "ml-auto flex items-center gap-2", children: [_jsxs("span", { className: "text-sm text-muted-foreground", children: [filteredCount, " van ", totalCount, " ", countLabel] }), hasActiveFilters && (_jsx(Button, { size: "sm", variant: "ghost", onClick: onClear, children: "Filters wissen" }))] })] }), hasActiveFilters && (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [search && _jsx(Chip, { label: `Zoeken: ${search}`, onRemove: () => onSearchChange("") }), period !== "all" && _jsx(Chip, { label: `Periode: ${PERIOD_LABELS[period]}`, onRemove: () => onPeriodChange("all") }), status && status !== "all" && onStatusChange && (_jsx(Chip, { label: `Status: ${statusLabel ?? status}`, onRemove: () => onStatusChange("all") })), sortOrder !== "date-desc" && (_jsx(Chip, { label: "Sortering: oudste eerst", onRemove: () => onSortOrderChange("date-desc") })), _jsx("button", { type: "button", onClick: onClear, className: "text-xs text-primary underline underline-offset-2", children: "Alles wissen" })] }))] }));
67
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"MailboxProcessedPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProcessedPage.tsx"],"names":[],"mappings":"AAYA,wBAAgB,oBAAoB,gCA6GnC"}
1
+ {"version":3,"file":"MailboxProcessedPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProcessedPage.tsx"],"names":[],"mappings":"AAaA,wBAAgB,oBAAoB,gCA4KnC"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import { useEffect, useMemo, useState } from "react";
3
3
  import { useQuery, useQueryClient } from "@tanstack/react-query";
4
4
  import { useServerFn } from "@tanstack/react-start";
5
5
  import { toast } from "sonner";
@@ -7,6 +7,7 @@ import { Badge, Button, Card, CardContent, Table, TableBody, TableCell, TableHea
7
7
  import { listProposals, reopenProposal, getActiveOrdersMailbox } from "../lib/mailbox.functions";
8
8
  import { MailboxAuthBanner } from "./MailboxAuthBanner";
9
9
  import { TablePagination } from "./TablePagination";
10
+ import { MailboxFilterBar, usePersistedState, normalizeText, matchesPeriod } from "./MailboxFilterBar";
10
11
  export function MailboxProcessedPage() {
11
12
  const fetchList = useServerFn(listProposals);
12
13
  const reopen = useServerFn(reopenProposal);
@@ -29,13 +30,44 @@ export function MailboxProcessedPage() {
29
30
  const items = [
30
31
  ...(Array.isArray(approved.data?.items) ? approved.data.items : []),
31
32
  ...(Array.isArray(rejected.data?.items) ? rejected.data.items : []),
32
- ].sort((a, b) => (b.reviewed_at ?? "").localeCompare(a.reviewed_at ?? ""));
33
+ ];
33
34
  const [busyId, setBusyId] = useState(null);
34
35
  const [page, setPage] = useState(1);
35
36
  const [pageSize, setPageSize] = useState(25);
36
- const pageCount = Math.max(1, Math.ceil(items.length / pageSize));
37
+ const [search, setSearch] = usePersistedState("mailbox-processed:search", "");
38
+ const [period, setPeriod] = usePersistedState("mailbox-processed:period", "all");
39
+ const [sortOrder, setSortOrder] = usePersistedState("mailbox-processed:sort", "date-desc");
40
+ const [statusFilter, setStatusFilter] = usePersistedState("mailbox-processed:status", "all");
41
+ const customerNameFor = (p) => p.mailbox_messages?.from_name || p.mailbox_messages?.from_email || "Onbekend";
42
+ const filteredItems = useMemo(() => {
43
+ const q = normalizeText(search).trim();
44
+ const filtered = items.filter((p) => {
45
+ if (statusFilter !== "all" && p.status !== statusFilter)
46
+ return false;
47
+ if (!matchesPeriod(p.reviewed_at, period))
48
+ return false;
49
+ if (!q)
50
+ return true;
51
+ const haystack = normalizeText([
52
+ customerNameFor(p),
53
+ p.mailbox_messages?.from_email,
54
+ p.mailbox_messages?.subject,
55
+ p.mailbox_messages?.preview,
56
+ ].join(" "));
57
+ return q.split(/\s+/).every((token) => haystack.includes(token));
58
+ });
59
+ return filtered.sort((a, b) => {
60
+ const aDate = a.reviewed_at ?? "";
61
+ const bDate = b.reviewed_at ?? "";
62
+ return sortOrder === "date-desc" ? bDate.localeCompare(aDate) : aDate.localeCompare(bDate);
63
+ });
64
+ }, [items, search, period, sortOrder, statusFilter]);
65
+ const hasActiveFilters = !!search || period !== "all" || sortOrder !== "date-desc" || statusFilter !== "all";
66
+ 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(filteredItems.length / pageSize));
37
69
  const currentPage = Math.min(page, pageCount);
38
- const pagedItems = items.slice((currentPage - 1) * pageSize, currentPage * pageSize);
70
+ const pagedItems = filteredItems.slice((currentPage - 1) * pageSize, currentPage * pageSize);
39
71
  const handleReopen = async (proposalId) => {
40
72
  setBusyId(proposalId);
41
73
  try {
@@ -50,5 +82,9 @@ export function MailboxProcessedPage() {
50
82
  setBusyId(null);
51
83
  }
52
84
  };
53
- return (_jsxs("div", { className: "p-6 flex flex-col gap-4 flex-1 min-h-0 overflow-hidden", children: [_jsx(MailboxAuthBanner, { active: activeMailbox }), _jsx("h1", { className: "text-2xl font-semibold shrink-0", children: "Verwerkt" }), _jsx("div", { className: "flex-1 min-h-0 overflow-y-auto overscroll-contain [scrollbar-gutter:stable]", children: _jsx(Card, { children: _jsxs(CardContent, { className: "p-0", children: [items.length === 0 ? (_jsx("div", { className: "p-8 text-center text-muted-foreground", children: "Nog geen verwerkte voorstellen." })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Status" }), _jsx(TableHead, { children: "Afzender" }), _jsx(TableHead, { children: "Onderwerp" }), _jsx(TableHead, { children: "Verwerkt op" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsx(TableBody, { children: pagedItems.map((p) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Badge, { variant: p.status === "approved" ? "default" : "destructive", children: p.status === "approved" ? "Goedgekeurd" : "Afgewezen" }) }), _jsx(TableCell, { children: p.mailbox_messages?.from_email ?? "-" }), _jsx(TableCell, { className: "max-w-md truncate", children: p.mailbox_messages?.subject ?? "-" }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: p.reviewed_at ? new Date(p.reviewed_at).toLocaleString("nl-NL") : "-" }), _jsx(TableCell, { className: "text-right space-x-2", children: p.status === "rejected" && (_jsx(Button, { size: "sm", variant: "outline", disabled: busyId === p.id, onClick: () => handleReopen(p.id), children: busyId === p.id ? "Bezig..." : "Terugzetten" })) })] }, p.id))) })] })), items.length > 0 && (_jsx(TablePagination, { total: items.length, page: currentPage, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize }))] }) }) })] }));
85
+ return (_jsxs("div", { className: "p-6 flex flex-col gap-4 flex-1 min-h-0 overflow-hidden", children: [_jsx(MailboxAuthBanner, { active: activeMailbox }), _jsx("h1", { className: "text-2xl font-semibold shrink-0", children: "Verwerkt" }), items.length > 0 && (_jsx(MailboxFilterBar, { search: search, onSearchChange: setSearch, period: period, onPeriodChange: setPeriod, sortOrder: sortOrder, onSortOrderChange: setSortOrder, status: statusFilter, onStatusChange: setStatusFilter, statusOptions: [
86
+ { value: "all", label: "Alle statussen" },
87
+ { value: "approved", label: "Goedgekeurd" },
88
+ { value: "rejected", label: "Afgewezen" },
89
+ ], filteredCount: filteredItems.length, totalCount: items.length, countLabel: "mails", onClear: clearFilters, hasActiveFilters: hasActiveFilters })), _jsx("div", { className: "flex-1 min-h-0 overflow-y-auto overscroll-contain [scrollbar-gutter:stable]", children: _jsx(Card, { children: _jsxs(CardContent, { className: "p-0", children: [items.length === 0 ? (_jsx("div", { className: "p-8 text-center text-muted-foreground", children: "Nog geen verwerkte voorstellen." })) : filteredItems.length === 0 ? (_jsx("div", { className: "p-8 text-center text-muted-foreground", children: "Geen mails gevonden voor deze zoekopdracht." })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Status" }), _jsx(TableHead, { children: "Afzender" }), _jsx(TableHead, { children: "Onderwerp" }), _jsx(TableHead, { children: "Verwerkt op" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsx(TableBody, { children: pagedItems.map((p) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Badge, { variant: p.status === "approved" ? "default" : "destructive", children: p.status === "approved" ? "Goedgekeurd" : "Afgewezen" }) }), _jsx(TableCell, { children: p.mailbox_messages?.from_email ?? "-" }), _jsxs(TableCell, { className: "max-w-md", children: [_jsx("div", { className: "truncate", children: p.mailbox_messages?.subject ?? "-" }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: p.mailbox_messages?.preview || "" })] }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: p.reviewed_at ? new Date(p.reviewed_at).toLocaleString("nl-NL") : "-" }), _jsx(TableCell, { className: "text-right space-x-2", children: p.status === "rejected" && (_jsx(Button, { size: "sm", variant: "outline", disabled: busyId === p.id, onClick: () => handleReopen(p.id), children: busyId === p.id ? "Bezig..." : "Terugzetten" })) })] }, p.id))) })] })), items.length > 0 && (_jsx(TablePagination, { total: filteredItems.length, page: currentPage, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize }))] }) }) })] }));
54
90
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MailboxProposalsPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProposalsPage.tsx"],"names":[],"mappings":"AA2FA,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,gCAqbnC"}
1
+ {"version":3,"file":"MailboxProposalsPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProposalsPage.tsx"],"names":[],"mappings":"AA6FA,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,gCA8bnC"}
@@ -5,13 +5,14 @@ import { useServerFn } from "@tanstack/react-start";
5
5
  import { Button, Badge, Card, CardContent, CardHeader, CardTitle, Input, Label, Textarea, Switch, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Dialog, DialogContent, DialogHeader, DialogTitle, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, toast, } from "@flowselections/core";
6
6
  import { Check, X, Trash2, Plus, AlertTriangle, RefreshCw } from "lucide-react";
7
7
  import { computeEarliestDelivery, isValidDeliveryDate } from "../lib/delivery-date";
8
- import { listProposals, getProposalDetail, approveProposal, rejectProposal, listCustomersForPicker, createCustomerFromGroup, listProductsForPicker, listDeliveryLocationsForCustomer, listPickupLocations, listCarriersForPicker, getOrderPickDays, getActiveOrdersMailbox, syncMailboxNow, getLastIngestRun, refreshProposalsForAgentChange, reparseProposalNow, listBeladingOptionsForProducts, listAllowedLoadCarriers, } from "../lib/mailbox.functions";
8
+ import { listProposals, getProposalDetail, approveProposal, rejectProposal, listCustomersForPicker, createCustomerFromGroup, listProductsForPicker, listDeliveryLocationsForCustomer, listPickupLocations, listCarriersForPicker, getOrderPickDays, getActiveOrdersMailbox, syncMailboxNow, refreshProposalsForAgentChange, reparseProposalNow, listBeladingOptionsForProducts, listAllowedLoadCarriers, } from "../lib/mailbox.functions";
9
9
  import { enabledLoadCarriers, normalizeAllowedLoadCarriers, EMPTY_LOAD_CARRIERS } from "../lib/load-carriers";
10
10
  import { listTemplateFields, listPlantTypesForPicker, listSuppliersForPicker, } from "../lib/mailbox-template.functions";
11
11
  import { SearchableSelect } from "./SearchableSelect";
12
12
  import { MailboxAuthBanner } from "./MailboxAuthBanner";
13
13
  import { EmailPreview } from "./EmailPreview";
14
14
  import { TablePagination } from "./TablePagination";
15
+ import { MailboxFilterBar, usePersistedState, normalizeText, matchesPeriod } from "./MailboxFilterBar";
15
16
  import { supabase } from "../integrations/supabase/client";
16
17
  const beladingKey = (b) => `${b.plants_per_crate}x${b.crates_per_layer}x${b.layers_per_cart}|${b.crate_code ?? ""}|${b.carrier_code ?? ""}`;
17
18
  const beladingLabel = (b) => `${b.plants_per_crate} planten/fust · ${b.crates_per_layer} fusten/laag · ${b.layers_per_cart} lagen`;
@@ -88,7 +89,6 @@ export function MailboxProposalsPage() {
88
89
  const fetchPickupLocations = useServerFn(listPickupLocations);
89
90
  const fetchActive = useServerFn(getActiveOrdersMailbox);
90
91
  const fetchSync = useServerFn(syncMailboxNow);
91
- const fetchLastRun = useServerFn(getLastIngestRun);
92
92
  // Server fns met requireSupabaseAuth gooien een raw Response bij een stale
93
93
  // bearer-token. Die bubbelt op als "[object Response]" en blankt het scherm.
94
94
  // Vang elke fout en geef een lege fallback terug — UI blijft bruikbaar.
@@ -105,6 +105,9 @@ export function MailboxProposalsPage() {
105
105
  const [activeId, setActiveId] = useState(null);
106
106
  const [page, setPage] = useState(1);
107
107
  const [pageSize, setPageSize] = useState(25);
108
+ const [search, setSearch] = usePersistedState("mailbox-proposals:search", "");
109
+ const [period, setPeriod] = usePersistedState("mailbox-proposals:period", "all");
110
+ const [sortOrder, setSortOrder] = usePersistedState("mailbox-proposals:sort", "date-desc");
108
111
  const [refsEnabled, setRefsEnabled] = useState(false);
109
112
  useEffect(() => { if (activeId)
110
113
  setRefsEnabled(true); }, [activeId]);
@@ -168,22 +171,9 @@ export function MailboxProposalsPage() {
168
171
  onSuccess: (res) => {
169
172
  if (res?.ok && ((res.inserted ?? 0) > 0 || (res.processed ?? 0) > 0)) {
170
173
  qc.invalidateQueries({ queryKey: ["mailbox-proposals"] });
171
- qc.invalidateQueries({ queryKey: ["mailbox-last-ingest-run"] });
172
174
  }
173
175
  },
174
176
  });
175
- const handleManualSync = () => {
176
- const p = syncMut.mutateAsync("manual");
177
- toast.promise(p, {
178
- loading: "Mailbox synchroniseren...",
179
- success: (res) => res?.ok
180
- ? (res.inserted ?? 0) > 0
181
- ? `${res.inserted} nieuwe bestelling(en) opgehaald`
182
- : "Geen nieuwe bestellingen"
183
- : `Sync mislukt: ${res?.error ?? "onbekende fout"}`,
184
- error: "Sync mislukt",
185
- });
186
- };
187
177
  // Realtime hint: zodra er een nieuw event binnenkomt vragen we de server om
188
178
  // het meteen te verwerken (zelfde pipeline). Cron is de garantiestrook.
189
179
  useEffect(() => {
@@ -212,13 +202,6 @@ export function MailboxProposalsPage() {
212
202
  return () => clearInterval(t);
213
203
  // eslint-disable-next-line react-hooks/exhaustive-deps
214
204
  }, [activeMailboxId]);
215
- // Laatste ingest-run tonen voor observability.
216
- const { data: lastRunData } = useQuery({
217
- queryKey: ["mailbox-last-ingest-run"],
218
- queryFn: () => safe(() => fetchLastRun()),
219
- refetchInterval: 60000,
220
- });
221
- const lastRun = lastRunData?.run ?? null;
222
205
  // AI-agent gewijzigd? Dan worden openstaande voorstellen automatisch opnieuw
223
206
  // geanalyseerd met de nieuwste agent. Server-side draait dit ook elke
224
207
  // cron-run; hier reageren we direct op wijzigingen in de AI-module.
@@ -283,9 +266,6 @@ export function MailboxProposalsPage() {
283
266
  // eslint-disable-next-line react-hooks/exhaustive-deps
284
267
  }, []);
285
268
  const items = Array.isArray(data?.items) ? data.items : [];
286
- const pageCount = Math.max(1, Math.ceil(items.length / pageSize));
287
- const currentPage = Math.min(page, pageCount);
288
- const pagedItems = items.slice((currentPage - 1) * pageSize, currentPage * pageSize);
289
269
  const template = Array.isArray(templateData?.items) ? templateData.items : [];
290
270
  const customers = Array.isArray(customersData?.items) ? customersData.items : [];
291
271
  const products = Array.isArray(productsData?.items) ? productsData.items : [];
@@ -310,12 +290,42 @@ export function MailboxProposalsPage() {
310
290
  }
311
291
  return p.mailbox_messages?.from_name || p.mailbox_messages?.from_email || "Onbekend";
312
292
  };
313
- return (_jsxs("div", { className: "p-6 flex flex-col gap-4 flex-1 min-h-0 overflow-hidden", children: [_jsx(MailboxAuthBanner, { active: activeMailbox }), _jsxs("div", { className: "flex items-center justify-between shrink-0", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Bestelvoorstellen" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Nieuw binnengekomen bestellingen die nog handmatig gecontroleerd moeten worden." })] }), _jsxs("div", { className: "flex items-center gap-3", children: [lastRun?.finished_at && (_jsxs("span", { className: "text-xs text-muted-foreground", children: ["Laatste sync: ", new Date(lastRun.finished_at).toLocaleTimeString("nl-NL"), " \u2014 ", lastRun.processed, " verwerkt", lastRun.errors > 0 ? `, ${lastRun.errors} fouten` : ""] })), _jsxs(Button, { onClick: handleManualSync, disabled: syncMut.isPending, variant: "outline", children: [_jsx(RefreshCw, { className: `h-4 w-4 mr-2 ${syncMut.isPending ? "animate-spin" : ""}` }), "Sync nu"] })] })] }), _jsx("div", { className: "flex-1 min-h-0 overflow-y-auto overscroll-contain [scrollbar-gutter:stable]", children: isLoading ? (_jsx("div", { className: "text-muted-foreground", children: "Laden..." })) : listError ? (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 p-4 text-sm", children: [_jsx("p", { className: "font-medium text-destructive", children: "Bestellingen konden niet worden opgehaald." }), _jsxs("p", { className: "text-muted-foreground mt-1", children: [listError?.message ?? "Onbekende fout", " \u2014 de lijst is niet leeg, alleen niet geladen."] }), _jsx(Button, { size: "sm", variant: "outline", className: "mt-3", onClick: () => void refetchList(), children: "Opnieuw proberen" })] })) : items.length === 0 ? (_jsx("p", { className: "text-muted-foreground", children: "Geen bestellingen te controleren." })) : (_jsx(Card, { children: _jsxs(CardContent, { className: "p-0", children: [_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Klantnaam" }), _jsx(TableHead, { children: "Orderdatum" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { className: "text-right", children: "Orderwaarde" })] }) }), _jsx(TableBody, { children: pagedItems.map((p) => {
293
+ // --- Zoeken, filteren en sorteren --------------------------------------
294
+ const filteredItems = useMemo(() => {
295
+ const q = normalizeText(search).trim();
296
+ const filtered = items.filter((p) => {
297
+ const name = customerNameFor(p);
298
+ if (!matchesPeriod(p.mailbox_messages?.received_at ?? p.created_at, period))
299
+ return false;
300
+ if (!q)
301
+ return true;
302
+ const haystack = normalizeText([
303
+ name,
304
+ p.mailbox_messages?.from_email,
305
+ p.mailbox_messages?.from_name,
306
+ p.mailbox_messages?.subject,
307
+ p.mailbox_messages?.preview,
308
+ ].join(" "));
309
+ return q.split(/\s+/).every((token) => haystack.includes(token));
310
+ });
311
+ return filtered.sort((a, b) => {
312
+ const aDate = a.mailbox_messages?.received_at ?? a.created_at ?? "";
313
+ const bDate = b.mailbox_messages?.received_at ?? b.created_at ?? "";
314
+ return sortOrder === "date-desc" ? bDate.localeCompare(aDate) : aDate.localeCompare(bDate);
315
+ });
316
+ }, [items, customers, search, sortOrder, period]);
317
+ const hasActiveFilters = !!search || period !== "all" || sortOrder !== "date-desc";
318
+ const clearFilters = () => { setSearch(""); setPeriod("all"); setSortOrder("date-desc"); };
319
+ useEffect(() => { setPage(1); }, [search, period, sortOrder]);
320
+ const pageCount = Math.max(1, Math.ceil(filteredItems.length / pageSize));
321
+ const currentPage = Math.min(page, pageCount);
322
+ const pagedItems = filteredItems.slice((currentPage - 1) * pageSize, currentPage * pageSize);
323
+ return (_jsxs("div", { className: "p-6 flex flex-col gap-4 flex-1 min-h-0 overflow-hidden", children: [_jsx(MailboxAuthBanner, { active: activeMailbox }), _jsx("div", { className: "flex items-center justify-between shrink-0", children: _jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Bestelvoorstellen" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Nieuw binnengekomen bestellingen die nog handmatig gecontroleerd moeten worden." })] }) }), items.length > 0 && (_jsx(MailboxFilterBar, { search: search, onSearchChange: setSearch, period: period, onPeriodChange: setPeriod, sortOrder: sortOrder, onSortOrderChange: setSortOrder, filteredCount: filteredItems.length, totalCount: items.length, countLabel: "voorstellen", onClear: clearFilters, hasActiveFilters: hasActiveFilters })), _jsx("div", { className: "flex-1 min-h-0 overflow-y-auto overscroll-contain [scrollbar-gutter:stable]", children: isLoading ? (_jsx("div", { className: "text-muted-foreground", children: "Laden..." })) : listError ? (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 p-4 text-sm", children: [_jsx("p", { className: "font-medium text-destructive", children: "Bestellingen konden niet worden opgehaald." }), _jsxs("p", { className: "text-muted-foreground mt-1", children: [listError?.message ?? "Onbekende fout", " \u2014 de lijst is niet leeg, alleen niet geladen."] }), _jsx(Button, { size: "sm", variant: "outline", className: "mt-3", onClick: () => void refetchList(), children: "Opnieuw proberen" })] })) : items.length === 0 ? (_jsx("p", { className: "text-muted-foreground", children: "Geen bestellingen te controleren." })) : filteredItems.length === 0 ? (_jsx("p", { className: "text-muted-foreground", children: "Geen voorstellen gevonden voor deze zoekopdracht." })) : (_jsx(Card, { children: _jsxs(CardContent, { className: "p-0", children: [_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Klantnaam" }), _jsx(TableHead, { children: "Bericht" }), _jsx(TableHead, { children: "Orderdatum" }), _jsx(TableHead, { children: "Status" })] }) }), _jsx(TableBody, { children: pagedItems.map((p) => {
314
324
  const fvs = Array.isArray(p.mailbox_proposal_field_values) ? p.mailbox_proposal_field_values : [];
315
325
  const needsReview = fvs.some((v) => v.needs_review);
316
326
  const date = p.mailbox_messages?.received_at ?? p.created_at;
317
- return (_jsxs(TableRow, { className: "cursor-pointer hover:bg-muted/50", onClick: () => setActiveId(p.id), children: [_jsx(TableCell, { className: "font-medium", children: customerNameFor(p) }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: date ? new Date(date).toLocaleDateString("nl-NL") : "-" }), _jsx(TableCell, { children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Badge, { variant: statusVariant(p.status), children: statusLabel(p.status) }), String(p.ai_ok) === "true" && (_jsx(Badge, { variant: "outline", className: "text-xs border-sky-500 text-sky-700", children: "AI" })), needsReview && (_jsxs(Badge, { variant: "outline", className: "text-xs border-yellow-500 text-yellow-700", children: [_jsx(AlertTriangle, { className: "h-3 w-3 mr-1" }), "Controleren"] }))] }) }), _jsx(TableCell, { className: "text-right text-sm text-muted-foreground", children: "\u2014" })] }, p.id));
318
- }) })] }), _jsx(TablePagination, { total: items.length, page: currentPage, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize })] }) })) }), _jsx(Dialog, { open: !!activeId, onOpenChange: (o) => { if (!o) {
327
+ return (_jsxs(TableRow, { className: "cursor-pointer hover:bg-muted/50", onClick: () => setActiveId(p.id), children: [_jsx(TableCell, { className: "font-medium", children: customerNameFor(p) }), _jsxs(TableCell, { className: "max-w-sm", children: [_jsx("div", { className: "truncate text-sm 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" })] }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: date ? new Date(date).toLocaleDateString("nl-NL") : "-" }), _jsx(TableCell, { children: _jsx(Badge, { variant: "secondary", children: "Te controleren" }) })] }, p.id));
328
+ }) })] }), _jsx(TablePagination, { total: filteredItems.length, page: currentPage, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize })] }) })) }), _jsx(Dialog, { open: !!activeId, onOpenChange: (o) => { if (!o) {
319
329
  setActiveId(null);
320
330
  setReparseError(null);
321
331
  } }, children: _jsx(DialogContent, { className: "max-w-[95vw] w-[95vw] h-[92vh] max-h-[92vh] p-0 flex flex-col overflow-hidden", children: !active ? (_jsxs("div", { className: "flex-1 flex flex-col items-center justify-center gap-2 text-sm text-muted-foreground", children: [_jsx(DialogTitle, { className: "text-base", children: "Bestelling" }), detailLoading ? "Bestelling laden…" : "Bestelling niet gevonden."] })) : (_jsxs(_Fragment, { children: [_jsxs(DialogHeader, { className: "px-6 pt-6 pb-3 shrink-0 border-b", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsx(DialogTitle, { children: customerNameFor(activeSummary ?? active) }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "mr-8", disabled: reparseMutation.isPending, onClick: () => reparseMutation.mutate(active.id), children: [_jsx(RefreshCw, { className: `h-4 w-4 mr-2 ${reparseMutation.isPending ? "animate-spin" : ""}` }), reparseMutation.isPending ? "Analyseren…" : "Mail opnieuw analyseren"] })] }), reparseError && (_jsxs("div", { className: "mt-2 flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "h-4 w-4 mt-0.5 shrink-0" }), _jsx("span", { children: reparseError })] }))] }), _jsx("div", { className: "flex-1 min-h-0 overflow-hidden p-6", children: _jsx(ProposalEditor, { proposal: active, template: template, customers: customers, products: products, allowBackorder: allowBackorder, plantTypes: plantTypes, suppliers: suppliers, carriers: carriers, pickupLocations: pickupLocations, onApprove: async (payload) => {
@@ -5,5 +5,6 @@ export { SearchableSelect } from "./components/SearchableSelect";
5
5
  export { MailboxProcessedPage } from "./components/MailboxProcessedPage";
6
6
  export { EmailPreview } from "./components/EmailPreview";
7
7
  export { TablePagination } from "./components/TablePagination";
8
+ export { MailboxFilterBar } from "./components/MailboxFilterBar";
8
9
  export declare const mailboxOrdersModule: FlowModule;
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIvD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,eAAO,MAAM,mBAAmB,EAAE,UAmBjC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIvD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE,eAAO,MAAM,mBAAmB,EAAE,UAmBjC,CAAC"}
package/dist-lib/index.js CHANGED
@@ -10,6 +10,7 @@ export { SearchableSelect } from "./components/SearchableSelect";
10
10
  export { MailboxProcessedPage } from "./components/MailboxProcessedPage";
11
11
  export { EmailPreview } from "./components/EmailPreview";
12
12
  export { TablePagination } from "./components/TablePagination";
13
+ export { MailboxFilterBar } from "./components/MailboxFilterBar";
13
14
  export const mailboxOrdersModule = {
14
15
  id: "mailbox_orders",
15
16
  name: "Mailbox bestellingen",
@@ -6479,6 +6479,7 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
6479
6479
  Row: {
6480
6480
  buyer_organization_id: string | null;
6481
6481
  connection_id: string;
6482
+ controlled_at: string | null;
6482
6483
  created_at: string;
6483
6484
  data: import("./types").Json;
6484
6485
  floriday_id: string;
@@ -6490,6 +6491,7 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
6490
6491
  Insert: {
6491
6492
  buyer_organization_id?: string | null;
6492
6493
  connection_id: string;
6494
+ controlled_at?: string | null;
6493
6495
  created_at?: string;
6494
6496
  data: import("./types").Json;
6495
6497
  floriday_id: string;
@@ -6501,6 +6503,7 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
6501
6503
  Update: {
6502
6504
  buyer_organization_id?: string | null;
6503
6505
  connection_id?: string;
6506
+ controlled_at?: string | null;
6504
6507
  created_at?: string;
6505
6508
  data?: import("./types").Json;
6506
6509
  floriday_id?: string;
@@ -7402,6 +7405,54 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
7402
7405
  };
7403
7406
  Relationships: [];
7404
7407
  };
7408
+ invoice_timing_settings: {
7409
+ Row: {
7410
+ anchor: string;
7411
+ business_days_only: boolean;
7412
+ created_at: string;
7413
+ enabled: boolean;
7414
+ id: string;
7415
+ offset_days: number;
7416
+ pickup_anchor: string;
7417
+ pickup_business_days_only: boolean;
7418
+ pickup_offset_days: number;
7419
+ pickup_time_of_day: string;
7420
+ singleton: boolean;
7421
+ time_of_day: string;
7422
+ updated_at: string;
7423
+ };
7424
+ Insert: {
7425
+ anchor?: string;
7426
+ business_days_only?: boolean;
7427
+ created_at?: string;
7428
+ enabled?: boolean;
7429
+ id?: string;
7430
+ offset_days?: number;
7431
+ pickup_anchor?: string;
7432
+ pickup_business_days_only?: boolean;
7433
+ pickup_offset_days?: number;
7434
+ pickup_time_of_day?: string;
7435
+ singleton?: boolean;
7436
+ time_of_day?: string;
7437
+ updated_at?: string;
7438
+ };
7439
+ Update: {
7440
+ anchor?: string;
7441
+ business_days_only?: boolean;
7442
+ created_at?: string;
7443
+ enabled?: boolean;
7444
+ id?: string;
7445
+ offset_days?: number;
7446
+ pickup_anchor?: string;
7447
+ pickup_business_days_only?: boolean;
7448
+ pickup_offset_days?: number;
7449
+ pickup_time_of_day?: string;
7450
+ singleton?: boolean;
7451
+ time_of_day?: string;
7452
+ updated_at?: string;
7453
+ };
7454
+ Relationships: [];
7455
+ };
7405
7456
  itk_contact_persons: {
7406
7457
  Row: {
7407
7458
  created_at: string;
@@ -10978,6 +11029,42 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
10978
11029
  };
10979
11030
  Relationships: [];
10980
11031
  };
11032
+ order_invoice_links: {
11033
+ Row: {
11034
+ attempts: number;
11035
+ created_at: string;
11036
+ error_message: string | null;
11037
+ id: string;
11038
+ invoice_number: string | null;
11039
+ order_id: string;
11040
+ processed_at: string | null;
11041
+ status: string;
11042
+ updated_at: string;
11043
+ };
11044
+ Insert: {
11045
+ attempts?: number;
11046
+ created_at?: string;
11047
+ error_message?: string | null;
11048
+ id?: string;
11049
+ invoice_number?: string | null;
11050
+ order_id: string;
11051
+ processed_at?: string | null;
11052
+ status?: string;
11053
+ updated_at?: string;
11054
+ };
11055
+ Update: {
11056
+ attempts?: number;
11057
+ created_at?: string;
11058
+ error_message?: string | null;
11059
+ id?: string;
11060
+ invoice_number?: string | null;
11061
+ order_id?: string;
11062
+ processed_at?: string | null;
11063
+ status?: string;
11064
+ updated_at?: string;
11065
+ };
11066
+ Relationships: [];
11067
+ };
10981
11068
  order_items: {
10982
11069
  Row: {
10983
11070
  crates_per_layer: number | null;
@@ -11160,6 +11247,7 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
11160
11247
  delivery_date: string | null;
11161
11248
  floriday_sales_order_id: string | null;
11162
11249
  id: string;
11250
+ invoice_due_at: string | null;
11163
11251
  is_reservation: boolean;
11164
11252
  notes: string | null;
11165
11253
  order_date: string;
@@ -11181,6 +11269,7 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
11181
11269
  delivery_date?: string | null;
11182
11270
  floriday_sales_order_id?: string | null;
11183
11271
  id?: string;
11272
+ invoice_due_at?: string | null;
11184
11273
  is_reservation?: boolean;
11185
11274
  notes?: string | null;
11186
11275
  order_date?: string;
@@ -11202,6 +11291,7 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
11202
11291
  delivery_date?: string | null;
11203
11292
  floriday_sales_order_id?: string | null;
11204
11293
  id?: string;
11294
+ invoice_due_at?: string | null;
11205
11295
  is_reservation?: boolean;
11206
11296
  notes?: string | null;
11207
11297
  order_date?: string;
@@ -15396,6 +15486,8 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
15396
15486
  };
15397
15487
  twinfield_invoice_settings: {
15398
15488
  Row: {
15489
+ auto_invoice_enabled: boolean;
15490
+ auto_invoice_trigger_statuses: string[];
15399
15491
  created_at: string;
15400
15492
  debtor_gl_account: string;
15401
15493
  default_credit_invoice_type: string | null;
@@ -15416,6 +15508,8 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
15416
15508
  vat_code_export: string | null;
15417
15509
  };
15418
15510
  Insert: {
15511
+ auto_invoice_enabled?: boolean;
15512
+ auto_invoice_trigger_statuses?: string[];
15419
15513
  created_at?: string;
15420
15514
  debtor_gl_account?: string;
15421
15515
  default_credit_invoice_type?: string | null;
@@ -15436,6 +15530,8 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
15436
15530
  vat_code_export?: string | null;
15437
15531
  };
15438
15532
  Update: {
15533
+ auto_invoice_enabled?: boolean;
15534
+ auto_invoice_trigger_statuses?: string[];
15439
15535
  created_at?: string;
15440
15536
  debtor_gl_account?: string;
15441
15537
  default_credit_invoice_type?: string | null;
@@ -18358,6 +18454,10 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
18358
18454
  processed_items: number;
18359
18455
  }[];
18360
18456
  };
18457
+ backfill_order_auto_invoice_queue: {
18458
+ Args: never;
18459
+ Returns: number;
18460
+ };
18361
18461
  calculate_layer_stock: {
18362
18462
  Args: {
18363
18463
  p_product_id: string;
@@ -18588,6 +18688,10 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
18588
18688
  Args: never;
18589
18689
  Returns: undefined;
18590
18690
  };
18691
+ cleanup_voorraad_module_history: {
18692
+ Args: never;
18693
+ Returns: undefined;
18694
+ };
18591
18695
  complete_floriday_stock_queue: {
18592
18696
  Args: {
18593
18697
  p_attempt_id?: string;
@@ -20312,6 +20416,12 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
20312
20416
  };
20313
20417
  Returns: undefined;
20314
20418
  };
20419
+ reset_stalled_floriday_stock_queue: {
20420
+ Args: {
20421
+ p_include_failed?: boolean;
20422
+ };
20423
+ Returns: number;
20424
+ };
20315
20425
  resolve_group_allocation: {
20316
20426
  Args: {
20317
20427
  _needed: number;
@@ -20366,6 +20476,10 @@ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<Da
20366
20476
  Args: never;
20367
20477
  Returns: undefined;
20368
20478
  };
20479
+ run_floriday_stock_queue_process: {
20480
+ Args: never;
20481
+ Returns: undefined;
20482
+ };
20369
20483
  run_logistics_tasks_dispatch: {
20370
20484
  Args: never;
20371
20485
  Returns: undefined;