@flowselections/pick-schermen-kwekers 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist-lib/_core-safelist.d.ts +2 -0
- package/dist-lib/_core-safelist.d.ts.map +1 -0
- package/dist-lib/_core-safelist.js +15 -0
- package/dist-lib/components/PickBeheerPage.d.ts +2 -0
- package/dist-lib/components/PickBeheerPage.d.ts.map +1 -0
- package/dist-lib/components/PickBeheerPage.js +84 -0
- package/dist-lib/components/PickDashboardPage.d.ts +2 -0
- package/dist-lib/components/PickDashboardPage.d.ts.map +1 -0
- package/dist-lib/components/PickDashboardPage.js +54 -0
- package/dist-lib/components/PickKioskPage.d.ts +7 -0
- package/dist-lib/components/PickKioskPage.d.ts.map +1 -0
- package/dist-lib/components/PickKioskPage.js +18 -0
- package/dist-lib/components/PickstationDetailPage.d.ts +6 -0
- package/dist-lib/components/PickstationDetailPage.d.ts.map +1 -0
- package/dist-lib/components/PickstationDetailPage.js +25 -0
- package/dist-lib/components/PickstationsPage.d.ts +2 -0
- package/dist-lib/components/PickstationsPage.d.ts.map +1 -0
- package/dist-lib/components/PickstationsPage.js +18 -0
- package/dist-lib/components/TemplateModuleLogo.d.ts +6 -0
- package/dist-lib/components/TemplateModuleLogo.d.ts.map +1 -0
- package/dist-lib/components/TemplateModuleLogo.js +4 -0
- package/dist-lib/components/TemplateModulePage.d.ts +2 -0
- package/dist-lib/components/TemplateModulePage.d.ts.map +1 -0
- package/dist-lib/components/TemplateModulePage.js +44 -0
- package/dist-lib/components/TemplatePage.d.ts +2 -0
- package/dist-lib/components/TemplatePage.d.ts.map +1 -0
- package/dist-lib/components/TemplatePage.js +4 -0
- package/dist-lib/components/pick/ConfigCrud.d.ts +27 -0
- package/dist-lib/components/pick/ConfigCrud.d.ts.map +1 -0
- package/dist-lib/components/pick/ConfigCrud.js +64 -0
- package/dist-lib/components/pick/CountryTiles.d.ts +9 -0
- package/dist-lib/components/pick/CountryTiles.d.ts.map +1 -0
- package/dist-lib/components/pick/CountryTiles.js +13 -0
- package/dist-lib/components/pick/PickScherm.d.ts +10 -0
- package/dist-lib/components/pick/PickScherm.d.ts.map +1 -0
- package/dist-lib/components/pick/PickScherm.js +114 -0
- package/dist-lib/components/pick/QueueTable.d.ts +13 -0
- package/dist-lib/components/pick/QueueTable.d.ts.map +1 -0
- package/dist-lib/components/pick/QueueTable.js +29 -0
- package/dist-lib/components/settings/MijnModuleSettingsCard.d.ts +2 -0
- package/dist-lib/components/settings/MijnModuleSettingsCard.d.ts.map +1 -0
- package/dist-lib/components/settings/MijnModuleSettingsCard.js +42 -0
- package/dist-lib/hooks/useMijnModuleData.d.ts +13 -0
- package/dist-lib/hooks/useMijnModuleData.d.ts.map +1 -0
- package/dist-lib/hooks/useMijnModuleData.js +49 -0
- package/dist-lib/hooks/usePickConfig.d.ts +9 -0
- package/dist-lib/hooks/usePickConfig.d.ts.map +1 -0
- package/dist-lib/hooks/usePickConfig.js +29 -0
- package/dist-lib/hooks/usePickQueue.d.ts +34 -0
- package/dist-lib/hooks/usePickQueue.d.ts.map +1 -0
- package/dist-lib/hooks/usePickQueue.js +105 -0
- package/dist-lib/index.d.ts +20 -0
- package/dist-lib/index.d.ts.map +1 -0
- package/dist-lib/index.js +53 -0
- package/dist-lib/integrations/supabase/auth-attacher.d.ts +2 -0
- package/dist-lib/integrations/supabase/auth-attacher.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/auth-attacher.js +12 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +15877 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/auth-middleware.js +52 -0
- package/dist-lib/integrations/supabase/client.d.ts +15873 -0
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/client.js +13 -0
- package/dist-lib/integrations/supabase/client.server.d.ts +15873 -0
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/client.server.js +30 -0
- package/dist-lib/integrations/supabase/types.d.ts +16383 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/types.js +78 -0
- package/dist-lib/lib/pickApi.d.ts +89 -0
- package/dist-lib/lib/pickApi.d.ts.map +1 -0
- package/dist-lib/lib/pickApi.js +204 -0
- package/dist-lib/lib/pickTypes.d.ts +165 -0
- package/dist-lib/lib/pickTypes.d.ts.map +1 -0
- package/dist-lib/lib/pickTypes.js +24 -0
- package/dist-lib/lib/utils.d.ts +3 -0
- package/dist-lib/lib/utils.d.ts.map +1 -0
- package/dist-lib/lib/utils.js +5 -0
- package/dist-lib/lib/validationSchemas.d.ts +15 -0
- package/dist-lib/lib/validationSchemas.d.ts.map +1 -0
- package/dist-lib/lib/validationSchemas.js +25 -0
- package/dist-lib/styles.css +1 -0
- package/package.json +107 -0
- package/public/logo.png +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo, useState } from "react";
|
|
3
|
+
import { Badge, Button, Card, CardContent, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, toast, } from "@flowselections/core";
|
|
4
|
+
import { ArrowLeft, Eye, Loader2, Printer, RefreshCw, Search, WifiOff } from "lucide-react";
|
|
5
|
+
import { CountryTiles } from "./CountryTiles";
|
|
6
|
+
import { QueueTable } from "./QueueTable";
|
|
7
|
+
import { getSessionId, pickApi } from "../../lib/pickApi";
|
|
8
|
+
import { defaultFilters, usePickCountryCounts, usePickHeartbeat, usePickQueue, } from "../../hooks/usePickQueue";
|
|
9
|
+
import { usePickCountries, usePickDocumentTypes, usePickPrinters, usePickStatuses, } from "../../hooks/usePickConfig";
|
|
10
|
+
export function PickScherm({ station, screen, onBack, kiosk }) {
|
|
11
|
+
const sessionId = getSessionId();
|
|
12
|
+
const [country, setCountry] = useState(station.require_country_selection ? null : "");
|
|
13
|
+
const [filters, setFilters] = useState(defaultFilters);
|
|
14
|
+
const [busyId, setBusyId] = useState(null);
|
|
15
|
+
const [preview, setPreview] = useState(false);
|
|
16
|
+
const { data: countries } = usePickCountries();
|
|
17
|
+
const { data: statuses } = usePickStatuses();
|
|
18
|
+
const { data: documentTypes } = usePickDocumentTypes();
|
|
19
|
+
const { data: printers } = usePickPrinters();
|
|
20
|
+
const { data: counts } = usePickCountryCounts(screen.id);
|
|
21
|
+
const { online } = usePickHeartbeat(station.id, screen.id, sessionId);
|
|
22
|
+
const effectiveFilters = useMemo(() => ({
|
|
23
|
+
...filters,
|
|
24
|
+
country: country || null,
|
|
25
|
+
sortRules: (screen.sort_rules?.length ? screen.sort_rules : station.sort_rules) ?? [],
|
|
26
|
+
}), [filters, country, screen.sort_rules, station.sort_rules]);
|
|
27
|
+
const { items, total, loading, lockedIds, refresh } = usePickQueue({
|
|
28
|
+
stationId: station.id,
|
|
29
|
+
screenId: screen.id,
|
|
30
|
+
filters: effectiveFilters,
|
|
31
|
+
enabled: country !== null,
|
|
32
|
+
});
|
|
33
|
+
const printerId = screen.printer_id ?? station.default_printer_id ?? null;
|
|
34
|
+
const printer = (Array.isArray(printers) ? printers : []).find((p) => p.id === printerId);
|
|
35
|
+
const runPrint = useCallback(async (item) => {
|
|
36
|
+
if (preview) {
|
|
37
|
+
toast.info(`Voorbeeldmodus: ${item.document_number} zou nu geprint worden.`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (printer && printer.status !== "online" && printer.status !== "unknown") {
|
|
41
|
+
toast.error(`Printer ${printer.name} is niet beschikbaar (${printer.status}).`);
|
|
42
|
+
await pickApi.releaseLock(item.id);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
await pickApi.completePrint(item.id, printerId, sessionId);
|
|
46
|
+
toast.success(`${item.document_number} verstuurd naar ${printer?.name ?? "printer"}.`);
|
|
47
|
+
refresh();
|
|
48
|
+
}, [preview, printer, printerId, sessionId, refresh]);
|
|
49
|
+
const handlePick = useCallback(async (item) => {
|
|
50
|
+
setBusyId(item.id);
|
|
51
|
+
try {
|
|
52
|
+
const claimed = await pickApi.claim({
|
|
53
|
+
itemId: item.id,
|
|
54
|
+
stationId: station.id,
|
|
55
|
+
screenId: screen.id,
|
|
56
|
+
sessionId,
|
|
57
|
+
timeout: station.lock_timeout_seconds,
|
|
58
|
+
});
|
|
59
|
+
await runPrint(claimed ?? item);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
const message = e instanceof Error ? e.message : "Dit document is zojuist verwerkt.";
|
|
63
|
+
toast.error(message);
|
|
64
|
+
// Als claim wel is gelukt maar runPrint faalde, geef de lock vrij zodat
|
|
65
|
+
// het document niet minutenlang geblokkeerd blijft voor andere schermen.
|
|
66
|
+
try {
|
|
67
|
+
await pickApi.releaseLock(item.id);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Lock is mogelijk al opgeruimd of van een andere sessie; negeren.
|
|
71
|
+
}
|
|
72
|
+
refresh();
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
setBusyId(null);
|
|
76
|
+
}
|
|
77
|
+
}, [station.id, station.lock_timeout_seconds, screen.id, sessionId, runPrint, refresh]);
|
|
78
|
+
const handleNext = useCallback(async () => {
|
|
79
|
+
setBusyId("next");
|
|
80
|
+
let claimed = null;
|
|
81
|
+
try {
|
|
82
|
+
claimed = await pickApi.claimNext({
|
|
83
|
+
stationId: station.id,
|
|
84
|
+
screenId: screen.id,
|
|
85
|
+
country: country || null,
|
|
86
|
+
sessionId,
|
|
87
|
+
timeout: station.lock_timeout_seconds,
|
|
88
|
+
});
|
|
89
|
+
await runPrint(claimed);
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
const message = e instanceof Error ? e.message : "Geen document beschikbaar.";
|
|
93
|
+
toast.error(message);
|
|
94
|
+
if (claimed?.id) {
|
|
95
|
+
try {
|
|
96
|
+
await pickApi.releaseLock(claimed.id);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Negeren; lock wordt toch door heartbeat opgeruimd.
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
refresh();
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
setBusyId(null);
|
|
106
|
+
}
|
|
107
|
+
}, [station.id, station.lock_timeout_seconds, screen.id, country, sessionId, runPrint, refresh]);
|
|
108
|
+
// Stap 1 — landselectie
|
|
109
|
+
if (country === null) {
|
|
110
|
+
return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-2xl font-bold text-foreground", children: screen.name }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Kies eerst een land om verder te gaan." })] }), onBack && !kiosk && (_jsxs(Button, { variant: "outline", onClick: onBack, children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Terug"] }))] }), _jsx(CountryTiles, { countries: Array.isArray(countries) ? countries : [], counts: counts ?? {}, onSelect: setCountry })] }));
|
|
111
|
+
}
|
|
112
|
+
const totalPages = Math.max(1, Math.ceil(total / filters.pageSize));
|
|
113
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs(Button, { variant: "outline", size: "lg", onClick: () => setCountry(null), children: [_jsx(ArrowLeft, { className: "mr-2 h-5 w-5" }), " Land wijzigen"] }), _jsxs("div", { children: [_jsxs("h2", { className: "text-xl font-bold text-foreground", children: [screen.name, " \u2014 ", country || "alle landen"] }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [total, " document", total === 1 ? "" : "en", " in wachtrij \u00B7 printer: ", printer?.name ?? "geen", printer && printer.status !== "online" ? ` (${printer.status})` : ""] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [!online && (_jsxs(Badge, { className: "bg-destructive text-destructive-foreground", children: [_jsx(WifiOff, { className: "mr-1 h-3.5 w-3.5" }), " Offline"] })), _jsxs("div", { className: "flex items-center gap-2 rounded-md border px-3 py-2", children: [_jsx(Eye, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { className: "text-sm", children: "Voorbeeld" }), _jsx(Switch, { checked: preview, onCheckedChange: setPreview })] }), _jsx(Button, { variant: "outline", size: "icon", onClick: refresh, "aria-label": "Vernieuwen", children: _jsx(RefreshCw, { className: "h-4 w-4" }) }), _jsxs(Button, { size: "lg", className: "h-14 px-8 text-lg", onClick: handleNext, disabled: busyId !== null, children: [busyId === "next" ? (_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-5 w-5" })), "Volgende uitprinten"] })] })] }), _jsx(Card, { children: _jsxs(CardContent, { className: "flex flex-wrap items-center gap-3 p-4", children: [_jsxs("div", { className: "relative min-w-64 flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "pl-9", placeholder: "Zoek op order, document, klant, referentie of barcode", value: filters.search, onChange: (e) => setFilters((f) => ({ ...f, search: e.target.value, page: 0 })) })] }), _jsxs(Select, { value: filters.documentTypeId ?? "all", onValueChange: (v) => setFilters((f) => ({ ...f, documentTypeId: v === "all" ? null : v, page: 0 })), children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Documenttype" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "Alle documenttypes" }), (Array.isArray(documentTypes) ? documentTypes : []).map((d) => (_jsx(SelectItem, { value: d.id, children: d.name }, d.id)))] })] }), _jsxs("div", { className: "flex items-center gap-2 rounded-md border px-3 py-2", children: [_jsx("span", { className: "text-sm", children: "Alleen spoed" }), _jsx(Switch, { checked: filters.urgentOnly, onCheckedChange: (v) => setFilters((f) => ({ ...f, urgentOnly: v, page: 0 })) })] })] }) }), loading ? (_jsxs("div", { className: "flex items-center justify-center py-16 text-muted-foreground", children: [_jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" }), " Wachtrij laden..."] })) : (_jsx(QueueTable, { items: items, lockedIds: lockedIds, statuses: Array.isArray(statuses) ? statuses : [], documentTypes: Array.isArray(documentTypes) ? documentTypes : [], busyId: busyId, onPick: handlePick })), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-sm text-muted-foreground", children: ["Pagina ", filters.page + 1, " van ", totalPages] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", disabled: filters.page === 0, onClick: () => setFilters((f) => ({ ...f, page: Math.max(0, f.page - 1) })), children: "Vorige" }), _jsx(Button, { variant: "outline", disabled: filters.page + 1 >= totalPages, onClick: () => setFilters((f) => ({ ...f, page: f.page + 1 })), children: "Volgende" })] })] })] }));
|
|
114
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PickDocumentType, PickQueueItem, PickStatus } from "../../lib/pickTypes";
|
|
2
|
+
interface Props {
|
|
3
|
+
items: PickQueueItem[];
|
|
4
|
+
lockedIds: Set<string>;
|
|
5
|
+
statuses: PickStatus[];
|
|
6
|
+
documentTypes: PickDocumentType[];
|
|
7
|
+
busyId: string | null;
|
|
8
|
+
onPick: (item: PickQueueItem) => void;
|
|
9
|
+
readOnly?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, onPick, readOnly, }: Props): import("react").JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=QueueTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueueTable.d.ts","sourceRoot":"","sources":["../../../src/components/pick/QueueTable.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGvF,UAAU,KAAK;IACb,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AASD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,QAAQ,EACR,aAAa,EACb,MAAM,EACN,MAAM,EACN,QAAQ,GACT,EAAE,KAAK,+BAsGP"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Badge, Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@flowselections/core";
|
|
3
|
+
import { AlertTriangle, Lock, Printer } from "lucide-react";
|
|
4
|
+
import { sinceLabel } from "../../lib/pickTypes";
|
|
5
|
+
function priorityTone(priority, urgent) {
|
|
6
|
+
if (urgent)
|
|
7
|
+
return "bg-destructive text-destructive-foreground";
|
|
8
|
+
if (priority <= 10)
|
|
9
|
+
return "bg-primary text-primary-foreground";
|
|
10
|
+
if (priority <= 20)
|
|
11
|
+
return "bg-secondary text-secondary-foreground";
|
|
12
|
+
return "bg-muted text-muted-foreground";
|
|
13
|
+
}
|
|
14
|
+
export function QueueTable({ items, lockedIds, statuses, documentTypes, busyId, onPick, readOnly, }) {
|
|
15
|
+
const safeItems = Array.isArray(items) ? items : [];
|
|
16
|
+
const statusById = new Map((Array.isArray(statuses) ? statuses : []).map((s) => [s.id, s]));
|
|
17
|
+
const docById = new Map((Array.isArray(documentTypes) ? documentTypes : []).map((d) => [d.id, d]));
|
|
18
|
+
return (_jsx("div", { className: "overflow-x-auto rounded-lg border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Document" }), _jsx(TableHead, { children: "Order" }), _jsx(TableHead, { children: "Klant" }), _jsx(TableHead, { className: "hidden lg:table-cell", children: "Afleveradres" }), _jsx(TableHead, { className: "text-right", children: "Regels" }), _jsx(TableHead, { className: "text-right", children: "Karren" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { children: "Prioriteit" }), _jsx(TableHead, { children: "Aangemeld" }), _jsx(TableHead, { children: "Wachttijd" }), _jsx(TableHead, { className: "text-right", children: "Actie" })] }) }), _jsxs(TableBody, { children: [safeItems.map((item) => {
|
|
19
|
+
const locked = lockedIds.has(item.id);
|
|
20
|
+
const status = item.status_id ? statusById.get(item.status_id) : undefined;
|
|
21
|
+
const doc = item.document_type_id ? docById.get(item.document_type_id) : undefined;
|
|
22
|
+
const warnings = Array.isArray(item.warnings) ? item.warnings : [];
|
|
23
|
+
return (_jsxs(TableRow, { className: locked ? "opacity-50" : undefined, children: [_jsxs(TableCell, { className: "font-medium", children: [_jsxs("div", { className: "flex items-center gap-2", children: [item.document_number, warnings.length > 0 && (_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive", "aria-label": "Waarschuwing" }))] }), _jsx("div", { className: "text-xs text-muted-foreground", children: doc?.name ?? "-" })] }), _jsx(TableCell, { children: item.order_number }), _jsx(TableCell, { children: item.customer_name }), _jsx(TableCell, { className: "hidden max-w-56 truncate lg:table-cell", children: item.delivery_address }), _jsx(TableCell, { className: "text-right", children: item.line_count }), _jsx(TableCell, { className: "text-right", children: item.cart_count }), _jsx(TableCell, { children: _jsx(Badge, { style: status?.color ? { backgroundColor: status.color, color: "#fff" } : undefined, children: status?.name ?? "-" }) }), _jsx(TableCell, { children: _jsx("span", { className: "rounded px-2 py-1 text-xs font-semibold " +
|
|
24
|
+
priorityTone(item.priority, item.is_urgent), children: item.is_urgent ? "SPOED" : item.priority }) }), _jsx(TableCell, { className: "whitespace-nowrap text-sm", children: new Date(item.announced_at).toLocaleTimeString("nl-NL", {
|
|
25
|
+
hour: "2-digit",
|
|
26
|
+
minute: "2-digit",
|
|
27
|
+
}) }), _jsx(TableCell, { className: "whitespace-nowrap text-sm", children: sinceLabel(item.announced_at) }), _jsx(TableCell, { className: "text-right", children: locked ? (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(Lock, { className: "h-3.5 w-3.5" }), " In behandeling"] })) : (_jsxs(Button, { size: "sm", variant: "outline", disabled: readOnly || busyId === item.id, onClick: () => onPick(item), children: [_jsx(Printer, { className: "mr-1 h-4 w-4" }), "Printen"] })) })] }, item.id));
|
|
28
|
+
}), safeItems.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 11, className: "py-10 text-center text-muted-foreground", children: "Geen documenten in de wachtrij." }) }))] })] }) }));
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MijnModuleSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/MijnModuleSettingsCard.tsx"],"names":[],"mappings":"AAiCA,wBAAgB,sBAAsB,gCA+CrC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/settings/MijnModuleSettingsCard.tsx — EXAMPLE SETTINGS CARD
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// This is an example of a settings card for your module.
|
|
6
|
+
// It appears on the main settings page when registered in src/index.ts.
|
|
7
|
+
//
|
|
8
|
+
// RULES:
|
|
9
|
+
// - Must return a <Card> as its root element
|
|
10
|
+
// - Handles its own data fetching — no props are passed by the core
|
|
11
|
+
// - Use the same Card primitives from @flowselections/core
|
|
12
|
+
//
|
|
13
|
+
// WHAT TO DO:
|
|
14
|
+
// - Rename this file to match your card's purpose
|
|
15
|
+
// - Add your real settings UI
|
|
16
|
+
// - Register it in src/index.ts under settingsCards
|
|
17
|
+
// - Delete this file entirely if your module has no settings
|
|
18
|
+
// ============================================================================
|
|
19
|
+
import { useState } from "react";
|
|
20
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle, Button, Input, Label, toast, } from "@flowselections/core";
|
|
21
|
+
import { Settings2 } from "lucide-react";
|
|
22
|
+
export function MijnModuleSettingsCard() {
|
|
23
|
+
// Replace with your real settings state
|
|
24
|
+
const [setting, setSetting] = useState("");
|
|
25
|
+
const [saving, setSaving] = useState(false);
|
|
26
|
+
const handleSave = async () => {
|
|
27
|
+
setSaving(true);
|
|
28
|
+
try {
|
|
29
|
+
// Example: save to a table — replace with your real query
|
|
30
|
+
// const { error } = await supabase.from("my_settings").upsert({ ... });
|
|
31
|
+
// if (error) throw error;
|
|
32
|
+
toast.success("Instellingen opgeslagen");
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
toast.error("Fout bij het opslaan");
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
setSaving(false);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Settings2, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { children: "Module Instellingen" }), " "] }), _jsx(CardDescription, { children: "Beheer de instellingen voor deze module " })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "setting", children: "Instelling" }), _jsx(Input, { id: "setting", value: setting, onChange: (e) => setSetting(e.target.value), placeholder: "Waarde..." })] }), _jsx(Button, { onClick: handleSave, disabled: saving, children: saving ? "Opslaan..." : "Opslaan" })] })] }));
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface MijnItem {
|
|
2
|
+
id: string;
|
|
3
|
+
created_at: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
export declare function useMijnModuleData(): {
|
|
7
|
+
items: MijnItem[];
|
|
8
|
+
loading: boolean;
|
|
9
|
+
error: string | null;
|
|
10
|
+
reload: () => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=useMijnModuleData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMijnModuleData.d.ts","sourceRoot":"","sources":["../../src/hooks/useMijnModuleData.ts"],"names":[],"mappings":"AAkBA,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wBAAgB,iBAAiB;;;;;EAkChC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// src/hooks/useMijnModuleData.ts — EXAMPLE DATA HOOK
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Put your data fetching logic in hooks like this, not directly in components.
|
|
5
|
+
// This keeps your pages clean and makes it easy to reuse data across pages.
|
|
6
|
+
//
|
|
7
|
+
// WHAT TO DO:
|
|
8
|
+
// - Rename to match your data (e.g. useProducts, useOrders, useSuppliers)
|
|
9
|
+
// - Replace the example query with your real Supabase query
|
|
10
|
+
// - Replace MijnItem with your actual table's row type
|
|
11
|
+
// - Import and use in your page components
|
|
12
|
+
// - Delete this file if you prefer a different pattern
|
|
13
|
+
// ============================================================================
|
|
14
|
+
import { useState, useEffect, useCallback } from "react";
|
|
15
|
+
import { supabase, toast } from "@flowselections/core";
|
|
16
|
+
export function useMijnModuleData() {
|
|
17
|
+
const [items, setItems] = useState([]);
|
|
18
|
+
const [loading, setLoading] = useState(true);
|
|
19
|
+
const [error, setError] = useState(null);
|
|
20
|
+
const load = useCallback(async () => {
|
|
21
|
+
setLoading(true);
|
|
22
|
+
setError(null);
|
|
23
|
+
try {
|
|
24
|
+
const { data, error } = await supabase
|
|
25
|
+
.from("products") // ← CHANGE THIS to your table
|
|
26
|
+
.select("*")
|
|
27
|
+
.order("created_at", { ascending: false });
|
|
28
|
+
if (error)
|
|
29
|
+
throw error;
|
|
30
|
+
setItems(data ?? []);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
setError("Fout bij het laden van gegevens");
|
|
34
|
+
toast.error("Fout bij het laden van gegevens");
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
setLoading(false);
|
|
38
|
+
}
|
|
39
|
+
}, []);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
load();
|
|
42
|
+
}, [load]);
|
|
43
|
+
return {
|
|
44
|
+
items,
|
|
45
|
+
loading,
|
|
46
|
+
error,
|
|
47
|
+
reload: load,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function usePickCountries(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickCountry[]>, Error>;
|
|
2
|
+
export declare function usePickStatuses(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickStatus[]>, Error>;
|
|
3
|
+
export declare function usePickPrinters(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickPrinter[]>, Error>;
|
|
4
|
+
export declare function usePickDocumentTypes(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickDocumentType[]>, Error>;
|
|
5
|
+
export declare function usePickStationTypes(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickStationType[]>, Error>;
|
|
6
|
+
export declare function usePickTasks(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickTask[]>, Error>;
|
|
7
|
+
export declare function usePickStations(): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickStation[]>, Error>;
|
|
8
|
+
export declare function usePickScreens(stationId?: string): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").PickScreen[]>, Error>;
|
|
9
|
+
//# sourceMappingURL=usePickConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePickConfig.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickConfig.ts"],"names":[],"mappings":"AAGA,wBAAgB,gBAAgB,+FAE/B;AACD,wBAAgB,eAAe,8FAE9B;AACD,wBAAgB,eAAe,+FAE9B;AACD,wBAAgB,oBAAoB,oGAEnC;AACD,wBAAgB,mBAAmB,mGAElC;AACD,wBAAgB,YAAY,4FAE3B;AACD,wBAAgB,eAAe,+FAE9B;AACD,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,6FAKhD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
import { pickApi } from "../lib/pickApi";
|
|
3
|
+
export function usePickCountries() {
|
|
4
|
+
return useQuery({ queryKey: ["pick", "countries"], queryFn: pickApi.countries });
|
|
5
|
+
}
|
|
6
|
+
export function usePickStatuses() {
|
|
7
|
+
return useQuery({ queryKey: ["pick", "statuses"], queryFn: pickApi.statuses });
|
|
8
|
+
}
|
|
9
|
+
export function usePickPrinters() {
|
|
10
|
+
return useQuery({ queryKey: ["pick", "printers"], queryFn: pickApi.printers });
|
|
11
|
+
}
|
|
12
|
+
export function usePickDocumentTypes() {
|
|
13
|
+
return useQuery({ queryKey: ["pick", "documentTypes"], queryFn: pickApi.documentTypes });
|
|
14
|
+
}
|
|
15
|
+
export function usePickStationTypes() {
|
|
16
|
+
return useQuery({ queryKey: ["pick", "stationTypes"], queryFn: pickApi.stationTypes });
|
|
17
|
+
}
|
|
18
|
+
export function usePickTasks() {
|
|
19
|
+
return useQuery({ queryKey: ["pick", "tasks"], queryFn: pickApi.tasks });
|
|
20
|
+
}
|
|
21
|
+
export function usePickStations() {
|
|
22
|
+
return useQuery({ queryKey: ["pick", "stations"], queryFn: pickApi.stations });
|
|
23
|
+
}
|
|
24
|
+
export function usePickScreens(stationId) {
|
|
25
|
+
return useQuery({
|
|
26
|
+
queryKey: ["pick", "screens", stationId ?? "all"],
|
|
27
|
+
queryFn: () => pickApi.screens(stationId),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { PickQueueItem, PickSortRule } from "../lib/pickTypes";
|
|
2
|
+
export interface QueueFilters {
|
|
3
|
+
country: string | null;
|
|
4
|
+
search: string;
|
|
5
|
+
documentTypeId: string | null;
|
|
6
|
+
urgentOnly: boolean;
|
|
7
|
+
page: number;
|
|
8
|
+
pageSize: number;
|
|
9
|
+
sortRules: PickSortRule[];
|
|
10
|
+
}
|
|
11
|
+
export declare const defaultFilters: QueueFilters;
|
|
12
|
+
/**
|
|
13
|
+
* Realtime wachtrij. Elke wijziging in pick_queue of pick_queue_locks laat
|
|
14
|
+
* alle geopende schermen direct opnieuw laden — zonder handmatige refresh.
|
|
15
|
+
*/
|
|
16
|
+
export declare function usePickQueue(args: {
|
|
17
|
+
stationId?: string;
|
|
18
|
+
screenId?: string;
|
|
19
|
+
filters: QueueFilters;
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
}): {
|
|
22
|
+
items: PickQueueItem[];
|
|
23
|
+
total: number;
|
|
24
|
+
loading: boolean;
|
|
25
|
+
error: string | null;
|
|
26
|
+
lockedIds: Set<string>;
|
|
27
|
+
refresh: () => void;
|
|
28
|
+
};
|
|
29
|
+
/** Houdt bij dat dit scherm online is en ruimt verlopen locks op. */
|
|
30
|
+
export declare function usePickHeartbeat(stationId?: string, screenId?: string | null, sessionId?: string): {
|
|
31
|
+
online: boolean;
|
|
32
|
+
};
|
|
33
|
+
export declare function usePickCountryCounts(screenId?: string): import("@tanstack/react-query").UseQueryResult<NoInfer<Record<string, number>>, Error>;
|
|
34
|
+
//# sourceMappingURL=usePickQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePickQueue.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickQueue.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAY,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG9E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,EAAE,YAQ5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;;;;;;;EAkEA;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM;;EAuBhG;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,0FAOrD"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { pickApi, pickDb } from "../lib/pickApi";
|
|
4
|
+
import { safeArray } from "../lib/pickTypes";
|
|
5
|
+
export const defaultFilters = {
|
|
6
|
+
country: null,
|
|
7
|
+
search: "",
|
|
8
|
+
documentTypeId: null,
|
|
9
|
+
urgentOnly: false,
|
|
10
|
+
page: 0,
|
|
11
|
+
pageSize: 25,
|
|
12
|
+
sortRules: [],
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Realtime wachtrij. Elke wijziging in pick_queue of pick_queue_locks laat
|
|
16
|
+
* alle geopende schermen direct opnieuw laden — zonder handmatige refresh.
|
|
17
|
+
*/
|
|
18
|
+
export function usePickQueue(args) {
|
|
19
|
+
const queryClient = useQueryClient();
|
|
20
|
+
const { stationId, screenId, filters } = args;
|
|
21
|
+
const enabled = args.enabled !== false;
|
|
22
|
+
const key = useMemo(() => ["pick", "queue", stationId ?? "-", screenId ?? "-", filters], [stationId, screenId, filters]);
|
|
23
|
+
const queueQuery = useQuery({
|
|
24
|
+
queryKey: key,
|
|
25
|
+
enabled,
|
|
26
|
+
queryFn: () => pickApi.queue({
|
|
27
|
+
stationId,
|
|
28
|
+
screenId,
|
|
29
|
+
country: filters.country,
|
|
30
|
+
search: filters.search.trim() || undefined,
|
|
31
|
+
documentTypeId: filters.documentTypeId,
|
|
32
|
+
urgentOnly: filters.urgentOnly,
|
|
33
|
+
sortRules: filters.sortRules,
|
|
34
|
+
page: filters.page,
|
|
35
|
+
pageSize: filters.pageSize,
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
const locksQuery = useQuery({
|
|
39
|
+
queryKey: ["pick", "locks", stationId ?? "-"],
|
|
40
|
+
enabled,
|
|
41
|
+
queryFn: () => pickApi.locks(stationId),
|
|
42
|
+
refetchInterval: 5000,
|
|
43
|
+
});
|
|
44
|
+
const invalidate = useCallback(() => {
|
|
45
|
+
queryClient.invalidateQueries({ queryKey: ["pick", "queue"] });
|
|
46
|
+
queryClient.invalidateQueries({ queryKey: ["pick", "locks"] });
|
|
47
|
+
queryClient.invalidateQueries({ queryKey: ["pick", "countryCounts"] });
|
|
48
|
+
queryClient.invalidateQueries({ queryKey: ["pick", "dashboard"] });
|
|
49
|
+
}, [queryClient]);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!enabled)
|
|
52
|
+
return;
|
|
53
|
+
const channel = pickDb
|
|
54
|
+
.channel(`pick-queue-${stationId ?? "all"}`)
|
|
55
|
+
.on("postgres_changes", { event: "*", schema: "public", table: "pick_queue" }, invalidate)
|
|
56
|
+
.on("postgres_changes", { event: "*", schema: "public", table: "pick_queue_locks" }, invalidate)
|
|
57
|
+
.subscribe();
|
|
58
|
+
return () => {
|
|
59
|
+
pickDb.removeChannel(channel);
|
|
60
|
+
};
|
|
61
|
+
}, [enabled, stationId, invalidate]);
|
|
62
|
+
const lockedIds = useMemo(() => new Set(safeArray(locksQuery.data).map((l) => l.queue_item_id)), [locksQuery.data]);
|
|
63
|
+
return {
|
|
64
|
+
items: safeArray(queueQuery.data?.items),
|
|
65
|
+
total: queueQuery.data?.total ?? 0,
|
|
66
|
+
loading: queueQuery.isLoading,
|
|
67
|
+
error: queueQuery.error instanceof Error ? queueQuery.error.message : null,
|
|
68
|
+
lockedIds,
|
|
69
|
+
refresh: invalidate,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Houdt bij dat dit scherm online is en ruimt verlopen locks op. */
|
|
73
|
+
export function usePickHeartbeat(stationId, screenId, sessionId) {
|
|
74
|
+
const timer = useRef(null);
|
|
75
|
+
const [online, setOnline] = useState(true);
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (!stationId || !sessionId)
|
|
78
|
+
return;
|
|
79
|
+
const beat = async () => {
|
|
80
|
+
try {
|
|
81
|
+
await pickApi.heartbeat({ stationId, screenId: screenId ?? null, sessionId });
|
|
82
|
+
await pickDb.rpc("pick_release_expired_locks");
|
|
83
|
+
setOnline(true);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
setOnline(false);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
beat();
|
|
90
|
+
timer.current = setInterval(beat, 10000);
|
|
91
|
+
return () => {
|
|
92
|
+
if (timer.current)
|
|
93
|
+
clearInterval(timer.current);
|
|
94
|
+
};
|
|
95
|
+
}, [stationId, screenId, sessionId]);
|
|
96
|
+
return { online };
|
|
97
|
+
}
|
|
98
|
+
export function usePickCountryCounts(screenId) {
|
|
99
|
+
return useQuery({
|
|
100
|
+
queryKey: ["pick", "countryCounts", screenId ?? "-"],
|
|
101
|
+
enabled: !!screenId,
|
|
102
|
+
queryFn: () => pickApi.countryCounts(screenId),
|
|
103
|
+
refetchInterval: 20000,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FlowModule } from "@flowselections/core";
|
|
2
|
+
export * from './_core-safelist';
|
|
3
|
+
export * from './components/TemplatePage';
|
|
4
|
+
export * from './components/TemplateModulePage';
|
|
5
|
+
export { TemplateModuleLogo } from './components/TemplateModuleLogo';
|
|
6
|
+
export * from './lib/pickTypes';
|
|
7
|
+
export * from './lib/pickApi';
|
|
8
|
+
export * from './hooks/usePickConfig';
|
|
9
|
+
export * from './hooks/usePickQueue';
|
|
10
|
+
export { CountryTiles } from './components/pick/CountryTiles';
|
|
11
|
+
export { QueueTable } from './components/pick/QueueTable';
|
|
12
|
+
export { PickScherm } from './components/pick/PickScherm';
|
|
13
|
+
export { ConfigCrud } from './components/pick/ConfigCrud';
|
|
14
|
+
export { PickstationsPage } from './components/PickstationsPage';
|
|
15
|
+
export { PickstationDetailPage } from './components/PickstationDetailPage';
|
|
16
|
+
export { PickDashboardPage } from './components/PickDashboardPage';
|
|
17
|
+
export { PickBeheerPage } from './components/PickBeheerPage';
|
|
18
|
+
export { PickKioskPage } from './components/PickKioskPage';
|
|
19
|
+
export declare const pickSchermenModule: FlowModule;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAErE,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAO3D,eAAO,MAAM,kBAAkB,EAAE,UAiBhC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// src/index.ts — MODULE CONTRACT
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// This is the most important file in your module.
|
|
5
|
+
// The shell repo reads this file to know:
|
|
6
|
+
// - What nav item to show in the sidebar
|
|
7
|
+
// - What settings cards to add to the settings page
|
|
8
|
+
// - Your module's identity (id, name, version)
|
|
9
|
+
//
|
|
10
|
+
// WHAT TO DO:
|
|
11
|
+
// 1. Replace all PLACEHOLDER values below with your module's real values
|
|
12
|
+
// 2. Import your real settings card components (if any)
|
|
13
|
+
// 3. Add your nav item — use `children` if you need a dropdown
|
|
14
|
+
// 4. Done! You don't need to touch any other file for registration.
|
|
15
|
+
// ============================================================================
|
|
16
|
+
import { Boxes, LayoutDashboard, Settings2, Warehouse } from "lucide-react";
|
|
17
|
+
export * from './_core-safelist';
|
|
18
|
+
export * from './components/TemplatePage';
|
|
19
|
+
export * from './components/TemplateModulePage';
|
|
20
|
+
export { TemplateModuleLogo } from './components/TemplateModuleLogo';
|
|
21
|
+
export * from './lib/pickTypes';
|
|
22
|
+
export * from './lib/pickApi';
|
|
23
|
+
export * from './hooks/usePickConfig';
|
|
24
|
+
export * from './hooks/usePickQueue';
|
|
25
|
+
export { CountryTiles } from './components/pick/CountryTiles';
|
|
26
|
+
export { QueueTable } from './components/pick/QueueTable';
|
|
27
|
+
export { PickScherm } from './components/pick/PickScherm';
|
|
28
|
+
export { ConfigCrud } from './components/pick/ConfigCrud';
|
|
29
|
+
export { PickstationsPage } from './components/PickstationsPage';
|
|
30
|
+
export { PickstationDetailPage } from './components/PickstationDetailPage';
|
|
31
|
+
export { PickDashboardPage } from './components/PickDashboardPage';
|
|
32
|
+
export { PickBeheerPage } from './components/PickBeheerPage';
|
|
33
|
+
export { PickKioskPage } from './components/PickKioskPage';
|
|
34
|
+
// Import your settings cards here (delete if you have none)
|
|
35
|
+
// import { MySettingsCard } from "./components/settings/MySettingsCard";
|
|
36
|
+
// ⚠️ HERNOEM naar een unieke naam, bijv. floridayVerkoopModule
|
|
37
|
+
// De naam 'myModule' veroorzaakt een duplicate identifier bij meerdere modules in één shell.
|
|
38
|
+
export const pickSchermenModule = {
|
|
39
|
+
id: "pick-schermen",
|
|
40
|
+
name: "Pickstations",
|
|
41
|
+
version: "1.0.0",
|
|
42
|
+
nav: {
|
|
43
|
+
label: "Pickstations",
|
|
44
|
+
href: "/pickstations",
|
|
45
|
+
icon: Warehouse,
|
|
46
|
+
children: [
|
|
47
|
+
{ label: "Pickstations", href: "/pickstations", icon: Boxes },
|
|
48
|
+
{ label: "Live dashboard", href: "/pickstations/dashboard", icon: LayoutDashboard },
|
|
49
|
+
{ label: "Beheer", href: "/pickstations/beheer", icon: Settings2 },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
settingsCards: [],
|
|
53
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-attacher.d.ts","sourceRoot":"","sources":["../../../src/integrations/supabase/auth-attacher.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,kBAAkB,mHAQ9B,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// This file is automatically generated. Do not edit it directly.
|
|
2
|
+
import { createMiddleware } from '@tanstack/react-start';
|
|
3
|
+
import { supabase } from './client';
|
|
4
|
+
// Must be registered as a global `functionMiddleware` in `src/start.ts`; otherwise
|
|
5
|
+
// the browser never attaches the bearer token to serverFn RPCs.
|
|
6
|
+
export const attachSupabaseAuth = createMiddleware({ type: 'function' }).client(async ({ next }) => {
|
|
7
|
+
const { data } = await supabase.auth.getSession();
|
|
8
|
+
const token = data.session?.access_token;
|
|
9
|
+
return next({
|
|
10
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
|
11
|
+
});
|
|
12
|
+
});
|