@flowselections/pick-schermen-kwekers 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/PickPublicPage.d.ts +7 -0
- package/dist-lib/components/PickPublicPage.d.ts.map +1 -0
- package/dist-lib/components/PickPublicPage.js +19 -0
- package/dist-lib/components/PickstationsPage.d.ts.map +1 -1
- package/dist-lib/components/PickstationsPage.js +57 -14
- package/dist-lib/components/pick/LanguageTiles.d.ts +8 -0
- package/dist-lib/components/pick/LanguageTiles.d.ts.map +1 -0
- package/dist-lib/components/pick/LanguageTiles.js +11 -0
- package/dist-lib/components/pick/PickScherm.d.ts +6 -4
- package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
- package/dist-lib/components/pick/PickScherm.js +145 -61
- package/dist-lib/components/pick/PublicPickRoute.d.ts +6 -0
- package/dist-lib/components/pick/PublicPickRoute.d.ts.map +1 -0
- package/dist-lib/components/pick/PublicPickRoute.js +11 -0
- package/dist-lib/components/pick/QueueTable.d.ts +4 -1
- package/dist-lib/components/pick/QueueTable.d.ts.map +1 -1
- package/dist-lib/components/pick/QueueTable.js +11 -10
- package/dist-lib/hooks/usePickQueue.d.ts +7 -1
- package/dist-lib/hooks/usePickQueue.d.ts.map +1 -1
- package/dist-lib/hooks/usePickQueue.js +43 -6
- package/dist-lib/index.d.ts +6 -6
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +7 -12
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +9221 -5284
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +9221 -5284
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +9221 -5284
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +9394 -5387
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/layoutApi.d.ts +23 -0
- package/dist-lib/lib/layoutApi.d.ts.map +1 -0
- package/dist-lib/lib/layoutApi.js +94 -0
- package/dist-lib/lib/layoutMaker/documentProfiles.d.ts +50 -0
- package/dist-lib/lib/layoutMaker/documentProfiles.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/documentProfiles.js +458 -0
- package/dist-lib/lib/layoutMaker/documentTypes.d.ts +123 -0
- package/dist-lib/lib/layoutMaker/documentTypes.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/documentTypes.js +74 -0
- package/dist-lib/lib/layoutMaker/logoLibrary.d.ts +13 -0
- package/dist-lib/lib/layoutMaker/logoLibrary.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/logoLibrary.js +54 -0
- package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts +196 -0
- package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/pakbonBuilder.js +813 -0
- package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts +48 -0
- package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/pakbonHtml.js +703 -0
- package/dist-lib/lib/layoutRenderer.d.ts +7 -0
- package/dist-lib/lib/layoutRenderer.d.ts.map +1 -0
- package/dist-lib/lib/layoutRenderer.js +233 -0
- package/dist-lib/lib/layoutTypes.d.ts +84 -0
- package/dist-lib/lib/layoutTypes.d.ts.map +1 -0
- package/dist-lib/lib/layoutTypes.js +25 -0
- package/dist-lib/lib/logisticsApi.d.ts +54 -0
- package/dist-lib/lib/logisticsApi.d.ts.map +1 -0
- package/dist-lib/lib/logisticsApi.js +72 -0
- package/dist-lib/lib/logisticsTypes.d.ts +34 -0
- package/dist-lib/lib/logisticsTypes.d.ts.map +1 -0
- package/dist-lib/lib/logisticsTypes.js +36 -0
- package/dist-lib/lib/orderContext.d.ts +50 -0
- package/dist-lib/lib/orderContext.d.ts.map +1 -0
- package/dist-lib/lib/orderContext.js +162 -0
- package/dist-lib/lib/pakbonOrderInput.d.ts +8 -0
- package/dist-lib/lib/pakbonOrderInput.d.ts.map +1 -0
- package/dist-lib/lib/pakbonOrderInput.js +150 -0
- package/dist-lib/lib/pickApi.d.ts +24 -1
- package/dist-lib/lib/pickApi.d.ts.map +1 -1
- package/dist-lib/lib/pickApi.js +46 -5
- package/dist-lib/lib/pickI18n.d.ts +14 -0
- package/dist-lib/lib/pickI18n.d.ts.map +1 -0
- package/dist-lib/lib/pickI18n.js +500 -0
- package/dist-lib/lib/pickPrint.d.ts +18 -0
- package/dist-lib/lib/pickPrint.d.ts.map +1 -0
- package/dist-lib/lib/pickPrint.js +184 -0
- package/dist-lib/lib/pickTypes.d.ts +1 -0
- package/dist-lib/lib/pickTypes.d.ts.map +1 -1
- package/package.json +7 -20
- package/dist-lib/components/PickBeheerPage.d.ts +0 -2
- package/dist-lib/components/PickBeheerPage.d.ts.map +0 -1
- package/dist-lib/components/PickBeheerPage.js +0 -84
- package/dist-lib/components/PickDashboardPage.d.ts +0 -2
- package/dist-lib/components/PickDashboardPage.d.ts.map +0 -1
- package/dist-lib/components/PickDashboardPage.js +0 -54
- package/dist-lib/components/PickKioskPage.d.ts +0 -7
- package/dist-lib/components/PickKioskPage.d.ts.map +0 -1
- package/dist-lib/components/PickKioskPage.js +0 -18
- package/dist-lib/components/PickstationDetailPage.d.ts +0 -6
- package/dist-lib/components/PickstationDetailPage.d.ts.map +0 -1
- package/dist-lib/components/PickstationDetailPage.js +0 -25
- package/dist-lib/components/pick/ConfigCrud.d.ts +0 -27
- package/dist-lib/components/pick/ConfigCrud.d.ts.map +0 -1
- package/dist-lib/components/pick/ConfigCrud.js +0 -64
- package/dist-lib/components/pick/CountryTiles.d.ts +0 -9
- package/dist-lib/components/pick/CountryTiles.d.ts.map +0 -1
- package/dist-lib/components/pick/CountryTiles.js +0 -13
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Printen gebeurt uitsluitend met de layout uit de Layout maker. Deze module
|
|
2
|
+
// bevat geen enkel eigen documentsjabloon, ook niet als terugval.
|
|
3
|
+
import { logosMetViewUrl, resolveLayout } from "./layoutApi";
|
|
4
|
+
import { renderLayoutHtml } from "./layoutRenderer";
|
|
5
|
+
import { EmptyLayoutError, layoutSecties, MissingLayoutError } from "./layoutTypes";
|
|
6
|
+
import { fetchPakbonData } from "./orderContext";
|
|
7
|
+
import { maakPakbonOrder, printPakbon } from "./layoutMaker/pakbonHtml";
|
|
8
|
+
import { pakbonOrderInput } from "./pakbonOrderInput";
|
|
9
|
+
import { pickDb } from "./pickApi";
|
|
10
|
+
export { EmptyLayoutError, MissingLayoutError };
|
|
11
|
+
function obj(raw) {
|
|
12
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
13
|
+
}
|
|
14
|
+
function payloadOf(item) {
|
|
15
|
+
return obj(item.payload);
|
|
16
|
+
}
|
|
17
|
+
/** Alle plekken waar de Engine layoutgegevens kan meesturen, in volgorde van voorkeur. */
|
|
18
|
+
function layoutSources(item) {
|
|
19
|
+
const p = payloadOf(item);
|
|
20
|
+
return [p, obj(p["layout"]), obj(p["data"]), obj(obj(p["data"])["layout"]), obj(p["document"])];
|
|
21
|
+
}
|
|
22
|
+
function pickField(item, keys) {
|
|
23
|
+
for (const src of layoutSources(item)) {
|
|
24
|
+
for (const key of keys) {
|
|
25
|
+
const v = src[key];
|
|
26
|
+
if (v !== undefined && v !== null && v !== "")
|
|
27
|
+
return v;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
export function documentTypeOf(item) {
|
|
33
|
+
return String(pickField(item, ["documentType", "document_type", "documentsoort"]) ?? "pakbon");
|
|
34
|
+
}
|
|
35
|
+
/** Layoutreferentie zoals de Logistiek Engine die heeft meegegeven. */
|
|
36
|
+
function engineLayoutRef(item) {
|
|
37
|
+
const id = pickField(item, ["layoutId", "layout_id"]);
|
|
38
|
+
const name = pickField(item, ["layoutName", "layout_name"]);
|
|
39
|
+
const version = pickField(item, ["layoutVersion", "layout_version"]);
|
|
40
|
+
return {
|
|
41
|
+
layoutId: id ? String(id) : null,
|
|
42
|
+
layoutName: name ? String(name) : null,
|
|
43
|
+
layoutVersion: Number.isFinite(Number(version)) ? Number(version) : null,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Vraagt de taak bij de Engine op wanneer de wachtrijregel zelf geen layout
|
|
48
|
+
* meestuurt. Zo blijft de Engine altijd bepalend voor de opmaak.
|
|
49
|
+
*/
|
|
50
|
+
async function taskLayoutId(item) {
|
|
51
|
+
const taskId = pickField(item, ["taskId", "task_id"]);
|
|
52
|
+
if (!taskId)
|
|
53
|
+
return null;
|
|
54
|
+
const res = await pickDb.from("logistics_tasks").select("payload").eq("id", String(taskId)).limit(1);
|
|
55
|
+
if (res.error)
|
|
56
|
+
return null;
|
|
57
|
+
const rows = Array.isArray(res.data) ? res.data : [];
|
|
58
|
+
const payload = obj(rows[0]?.payload);
|
|
59
|
+
const nested = { ...payload, ...obj(payload["layout"]), ...obj(payload["data"]) };
|
|
60
|
+
const id = nested["layoutId"] ?? nested["layout_id"];
|
|
61
|
+
return id ? String(id) : null;
|
|
62
|
+
}
|
|
63
|
+
/** Datacontext voor de layout: wat de Engine meestuurt, aangevuld met de wachtrijregel. */
|
|
64
|
+
function buildData(item) {
|
|
65
|
+
const p = payloadOf(item);
|
|
66
|
+
const engineData = p["data"] && typeof p["data"] === "object" && !Array.isArray(p["data"])
|
|
67
|
+
? p["data"]
|
|
68
|
+
: {};
|
|
69
|
+
return {
|
|
70
|
+
...p,
|
|
71
|
+
...engineData,
|
|
72
|
+
document: { ...item, ...engineData["document"] },
|
|
73
|
+
...item,
|
|
74
|
+
printedAt: new Date().toISOString(),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Rendert het document met de layout uit de Layout maker en opent de
|
|
79
|
+
* printdialoog. Gooit MissingLayoutError als er geen actieve layout is.
|
|
80
|
+
*/
|
|
81
|
+
export async function printQueueItem(item, locale = "nl-NL") {
|
|
82
|
+
const documentType = documentTypeOf(item);
|
|
83
|
+
const engine = engineLayoutRef(item);
|
|
84
|
+
const layoutId = engine.layoutId ?? (await taskLayoutId(item));
|
|
85
|
+
const resolved = await resolveLayout({ documentType, layoutId });
|
|
86
|
+
const secties = layoutSecties(resolved.layout);
|
|
87
|
+
if (secties.length) {
|
|
88
|
+
const orderId = pickField(item, ["orderId", "order_id"]);
|
|
89
|
+
const data = await fetchPakbonData({
|
|
90
|
+
orderId: orderId ? String(orderId) : null,
|
|
91
|
+
orderNumber: item.order_number ?? null,
|
|
92
|
+
});
|
|
93
|
+
if (!data)
|
|
94
|
+
throw new Error("Ordergegevens niet gevonden voor dit document");
|
|
95
|
+
const layout = resolved.layout;
|
|
96
|
+
const landscape = String(layout.orientatie ?? "").toLowerCase() === "landscape";
|
|
97
|
+
const breedte = layout.breedte_mm ?? 210;
|
|
98
|
+
const hoogte = layout.hoogte_mm ?? 297;
|
|
99
|
+
const order = maakPakbonOrder(pakbonOrderInput(data));
|
|
100
|
+
printPakbon(layout.config, order, {
|
|
101
|
+
breedteMm: landscape ? hoogte : breedte,
|
|
102
|
+
hoogteMm: landscape ? breedte : hoogte,
|
|
103
|
+
margeMm: layout.marge_boven ?? undefined,
|
|
104
|
+
titel: `Pakbon ${item.order_number ?? ""}`.trim(),
|
|
105
|
+
logos: await logosMetViewUrl(resolved.logos),
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
layoutId: layout.id,
|
|
109
|
+
layoutName: layout.naam,
|
|
110
|
+
layoutVersion: layout.huidige_versie ?? null,
|
|
111
|
+
documentType,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (!resolved.elements.length)
|
|
115
|
+
throw new EmptyLayoutError(resolved.layout.naam);
|
|
116
|
+
const html = renderLayoutHtml(resolved, buildData(item), locale);
|
|
117
|
+
await openPrintDialog(html);
|
|
118
|
+
return {
|
|
119
|
+
layoutId: resolved.layout.id,
|
|
120
|
+
layoutName: resolved.layout.naam,
|
|
121
|
+
layoutVersion: resolved.layout.huidige_versie ?? null,
|
|
122
|
+
documentType,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** Meldt de taak af bij de Engine met de gebruikte layout in het resultaat. */
|
|
126
|
+
export async function completeLogisticsTaskForItem(item, print) {
|
|
127
|
+
const p = payloadOf(item);
|
|
128
|
+
const taskId = (p["taskId"] ?? p["task_id"] ?? null);
|
|
129
|
+
if (!taskId)
|
|
130
|
+
return;
|
|
131
|
+
await pickDb.rpc("logistics_complete_task", {
|
|
132
|
+
p_task_id: taskId,
|
|
133
|
+
p_result: {
|
|
134
|
+
printed: true,
|
|
135
|
+
queueItemId: item.id,
|
|
136
|
+
documentType: print.documentType,
|
|
137
|
+
layoutId: print.layoutId,
|
|
138
|
+
layoutName: print.layoutName,
|
|
139
|
+
layoutVersion: print.layoutVersion,
|
|
140
|
+
printedAt: new Date().toISOString(),
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function openPrintDialog(html) {
|
|
145
|
+
if (typeof window === "undefined" || typeof document === "undefined")
|
|
146
|
+
return Promise.resolve();
|
|
147
|
+
return new Promise((resolve) => {
|
|
148
|
+
const iframe = document.createElement("iframe");
|
|
149
|
+
iframe.setAttribute("aria-hidden", "true");
|
|
150
|
+
iframe.style.position = "fixed";
|
|
151
|
+
iframe.style.right = "0";
|
|
152
|
+
iframe.style.bottom = "0";
|
|
153
|
+
iframe.style.width = "0";
|
|
154
|
+
iframe.style.height = "0";
|
|
155
|
+
iframe.style.border = "0";
|
|
156
|
+
document.body.appendChild(iframe);
|
|
157
|
+
const cleanup = () => {
|
|
158
|
+
window.setTimeout(() => {
|
|
159
|
+
if (iframe.parentNode)
|
|
160
|
+
iframe.parentNode.removeChild(iframe);
|
|
161
|
+
}, 1000);
|
|
162
|
+
resolve();
|
|
163
|
+
};
|
|
164
|
+
iframe.onload = () => {
|
|
165
|
+
try {
|
|
166
|
+
const win = iframe.contentWindow;
|
|
167
|
+
if (!win)
|
|
168
|
+
return cleanup();
|
|
169
|
+
win.focus();
|
|
170
|
+
win.print();
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// printen geblokkeerd of niet beschikbaar
|
|
174
|
+
}
|
|
175
|
+
cleanup();
|
|
176
|
+
};
|
|
177
|
+
const doc = iframe.contentDocument;
|
|
178
|
+
if (!doc)
|
|
179
|
+
return cleanup();
|
|
180
|
+
doc.open();
|
|
181
|
+
doc.write(html);
|
|
182
|
+
doc.close();
|
|
183
|
+
});
|
|
184
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pickTypes.d.ts","sourceRoot":"","sources":["../../src/lib/pickTypes.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pickTypes.d.ts","sourceRoot":"","sources":["../../src/lib/pickTypes.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowselections/pick-schermen-kwekers",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"flowselections": {
|
|
5
5
|
"moduleId": "pick-schermen",
|
|
6
6
|
"pages": [
|
|
@@ -10,24 +10,11 @@
|
|
|
10
10
|
"title": "Pickstations"
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
|
-
"export": "
|
|
14
|
-
"route": "
|
|
15
|
-
"title": "
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"export": "PickDashboardPage",
|
|
19
|
-
"route": "pickstations/dashboard",
|
|
20
|
-
"title": "Live dashboard"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"export": "PickBeheerPage",
|
|
24
|
-
"route": "pickstations/beheer",
|
|
25
|
-
"title": "Beheer"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"export": "PickKioskPage",
|
|
29
|
-
"route": "kiosk/$stationId/$screenId",
|
|
30
|
-
"title": "Kiosk"
|
|
13
|
+
"export": "PublicPickRoute",
|
|
14
|
+
"route": "pickstation/$slug",
|
|
15
|
+
"title": "PublicPickRoute",
|
|
16
|
+
"nav": false,
|
|
17
|
+
"public": true
|
|
31
18
|
}
|
|
32
19
|
]
|
|
33
20
|
},
|
|
@@ -76,7 +63,7 @@
|
|
|
76
63
|
"@cloudflare/vite-plugin": "^1.25.5",
|
|
77
64
|
"@eslint/js": "^9.32.0",
|
|
78
65
|
"@flowselections/core": "1.0.16",
|
|
79
|
-
"@lovable.dev/vite-tanstack-config": "2.
|
|
66
|
+
"@lovable.dev/vite-tanstack-config": "2.9.0",
|
|
80
67
|
"@rsbuild/core": "^1.0.0",
|
|
81
68
|
"@tailwindcss/vite": "^4.2.1",
|
|
82
69
|
"@tanstack/react-query": "^5.83.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PickBeheerPage.d.ts","sourceRoot":"","sources":["../../src/components/PickBeheerPage.tsx"],"names":[],"mappings":"AAwBA,wBAAgB,cAAc,gCAsN7B"}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { useQuery } from "@tanstack/react-query";
|
|
4
|
-
import { Card, CardContent, CardHeader, CardTitle, Tabs, TabsContent, TabsList, TabsTrigger } from "@flowselections/core";
|
|
5
|
-
import { ConfigCrud } from "./pick/ConfigCrud";
|
|
6
|
-
import { pickApi } from "../lib/pickApi";
|
|
7
|
-
import { safeArray, SORT_FIELDS } from "../lib/pickTypes";
|
|
8
|
-
import { usePickDocumentTypes, usePickPrinters, usePickStationTypes, usePickStations, usePickTasks, } from "../hooks/usePickConfig";
|
|
9
|
-
const baseFields = (extra = []) => [
|
|
10
|
-
{ key: "name", label: "Naam", type: "text", required: true },
|
|
11
|
-
{ key: "description", label: "Omschrijving", type: "textarea", inTable: false },
|
|
12
|
-
...extra,
|
|
13
|
-
{ key: "color", label: "Kleur", type: "color", defaultValue: "#3b82f6" },
|
|
14
|
-
{ key: "icon", label: "Icoon (lucide naam)", type: "text", inTable: false, defaultValue: "package" },
|
|
15
|
-
{ key: "sort_order", label: "Volgorde", type: "number", defaultValue: 100 },
|
|
16
|
-
{ key: "active", label: "Actief", type: "boolean", defaultValue: true },
|
|
17
|
-
];
|
|
18
|
-
export function PickBeheerPage() {
|
|
19
|
-
const { data: stations } = usePickStations();
|
|
20
|
-
const { data: printers } = usePickPrinters();
|
|
21
|
-
const { data: types } = usePickStationTypes();
|
|
22
|
-
const { data: tasks } = usePickTasks();
|
|
23
|
-
const { data: docTypes } = usePickDocumentTypes();
|
|
24
|
-
const [screenStation, setScreenStation] = useState(undefined);
|
|
25
|
-
const logs = useQuery({ queryKey: ["pick", "logs"], queryFn: () => pickApi.logs(50) });
|
|
26
|
-
const opts = (rows) => safeArray(rows).map((r) => ({ value: r.id, label: r.name }));
|
|
27
|
-
const stationOptions = opts(stations);
|
|
28
|
-
const firstStation = screenStation ?? stationOptions[0]?.value;
|
|
29
|
-
return (_jsxs("main", { className: "space-y-6 p-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-foreground", children: "Beheer pickstations" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Alles is databasegestuurd: stations, schermen, taken, documenttypes, statussen, landen en printers." })] }), _jsxs(Tabs, { defaultValue: "stations", children: [_jsxs(TabsList, { className: "flex flex-wrap", children: [_jsx(TabsTrigger, { value: "stations", children: "Pickstations" }), _jsx(TabsTrigger, { value: "screens", children: "Pickschermen" }), _jsx(TabsTrigger, { value: "types", children: "Types" }), _jsx(TabsTrigger, { value: "tasks", children: "Taken" }), _jsx(TabsTrigger, { value: "documents", children: "Documenttypes" }), _jsx(TabsTrigger, { value: "statuses", children: "Statussen" }), _jsx(TabsTrigger, { value: "countries", children: "Landen" }), _jsx(TabsTrigger, { value: "printers", children: "Printers" }), _jsx(TabsTrigger, { value: "permissions", children: "Rechten" }), _jsx(TabsTrigger, { value: "logs", children: "Logboek" })] }), _jsx(TabsContent, { value: "stations", className: "mt-4", children: _jsx(ConfigCrud, { table: "pick_stations", title: "Pickstations", description: "Onbeperkt aantal stations, elk met een eigen taak en standaardprinter.", fields: baseFields([
|
|
30
|
-
{ key: "station_type_id", label: "Type", type: "select", options: opts(types) },
|
|
31
|
-
{ key: "task_id", label: "Taak", type: "select", options: opts(tasks) },
|
|
32
|
-
{ key: "default_printer_id", label: "Standaardprinter", type: "select", options: opts(printers), inTable: false },
|
|
33
|
-
{ key: "location", label: "Locatie", type: "text", inTable: false },
|
|
34
|
-
{ key: "department", label: "Afdeling", type: "text", inTable: false },
|
|
35
|
-
{ key: "allow_multi_screen", label: "Meerdere schermen toegestaan", type: "boolean", defaultValue: true, inTable: false },
|
|
36
|
-
{ key: "lock_timeout_seconds", label: "Lock timeout (sec)", type: "number", defaultValue: 120, inTable: false },
|
|
37
|
-
]) }) }), _jsxs(TabsContent, { value: "screens", className: "mt-4 space-y-4", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: "Kies een pickstation" }) }), _jsx(CardContent, { className: "flex flex-wrap gap-2", children: stationOptions.map((s) => (_jsx("button", { onClick: () => setScreenStation(s.value), className: `rounded-md border px-4 py-2 text-sm ${firstStation === s.value ? "border-primary bg-primary/10 font-medium" : "hover:bg-muted"}`, children: s.label }, s.value))) })] }), firstStation && (_jsx(ConfigCrud, { table: "pick_station_screens", title: "Pickschermen", description: "Een station kan meerdere schermen bevatten, elk met eigen documenttype en sorteerregels.", filter: { column: "station_id", value: firstStation }, fields: baseFields([
|
|
38
|
-
{ key: "document_type_id", label: "Documenttype", type: "select", options: opts(docTypes) },
|
|
39
|
-
{ key: "printer_id", label: "Printer", type: "select", options: opts(printers), inTable: false },
|
|
40
|
-
{ key: "kiosk_enabled", label: "Kioskmodus", type: "boolean", defaultValue: true, inTable: false },
|
|
41
|
-
{ key: "primary_sort_field", label: "Sorteren op", type: "select", options: SORT_FIELDS, inTable: false, defaultValue: "announced_at" },
|
|
42
|
-
]) }, firstStation))] }), _jsx(TabsContent, { value: "types", className: "mt-4", children: _jsx(ConfigCrud, { table: "pick_station_types", title: "Types pickstation", fields: baseFields() }) }), _jsx(TabsContent, { value: "tasks", className: "mt-4", children: _jsx(ConfigCrud, { table: "pick_station_tasks", title: "Taken", description: "Order picking, productie picking, retour picking \u2014 vrij uitbreidbaar.", fields: baseFields([{ key: "workflow", label: "Workflow", type: "text", inTable: false }]) }) }), _jsx(TabsContent, { value: "documents", className: "mt-4", children: _jsx(ConfigCrud, { table: "pick_document_types", title: "Documenttypes", fields: baseFields([
|
|
43
|
-
{ key: "report_key", label: "Rapportkoppeling", type: "text", inTable: false },
|
|
44
|
-
{ key: "print_template", label: "Printtemplate", type: "text", inTable: false },
|
|
45
|
-
{ key: "default_printer_id", label: "Printer", type: "select", options: opts(printers), inTable: false },
|
|
46
|
-
{ key: "priority", label: "Prioriteit", type: "number", defaultValue: 5 },
|
|
47
|
-
{ key: "workflow", label: "Workflow", type: "text", inTable: false },
|
|
48
|
-
]) }) }), _jsx(TabsContent, { value: "statuses", className: "mt-4", children: _jsx(ConfigCrud, { table: "pick_document_statuses", title: "Statussen", fields: [
|
|
49
|
-
{ key: "code", label: "Code", type: "text" },
|
|
50
|
-
...baseFields([{ key: "is_final", label: "Eindstatus", type: "boolean", defaultValue: false, inTable: false }]),
|
|
51
|
-
] }) }), _jsx(TabsContent, { value: "countries", className: "mt-4", children: _jsx(ConfigCrud, { table: "pick_countries", title: "Landen", fields: [
|
|
52
|
-
{ key: "code", label: "Landcode", type: "text" },
|
|
53
|
-
{ key: "name", label: "Naam", type: "text" },
|
|
54
|
-
{ key: "flag_emoji", label: "Vlag", type: "text" },
|
|
55
|
-
{ key: "sort_order", label: "Volgorde", type: "number", defaultValue: 100 },
|
|
56
|
-
{ key: "active", label: "Actief", type: "boolean", defaultValue: true },
|
|
57
|
-
] }) }), _jsx(TabsContent, { value: "printers", className: "mt-4", children: _jsx(ConfigCrud, { table: "pick_station_printers", title: "Printers", orderBy: "name", fields: [
|
|
58
|
-
{ key: "name", label: "Naam", type: "text" },
|
|
59
|
-
{ key: "location", label: "Locatie", type: "text" },
|
|
60
|
-
{ key: "connection", label: "Verbinding", type: "text", inTable: false },
|
|
61
|
-
{
|
|
62
|
-
key: "status",
|
|
63
|
-
label: "Status",
|
|
64
|
-
type: "select",
|
|
65
|
-
defaultValue: "online",
|
|
66
|
-
options: [
|
|
67
|
-
{ value: "online", label: "Online" },
|
|
68
|
-
{ value: "offline", label: "Offline" },
|
|
69
|
-
{ value: "no_paper", label: "Geen papier" },
|
|
70
|
-
{ value: "error", label: "Storing" },
|
|
71
|
-
{ value: "unknown", label: "Onbekend" },
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
{ key: "active", label: "Actief", type: "boolean", defaultValue: true },
|
|
75
|
-
] }) }), _jsx(TabsContent, { value: "permissions", className: "mt-4", children: _jsx(ConfigCrud, { table: "pick_station_permissions", title: "Rechten per gebruiker", orderBy: "created_at", description: "Beperk gebruikers tot een station, land of spoedwerk en bepaal wie mag herprinten of locks verbreken.", fields: [
|
|
76
|
-
{ key: "user_id", label: "Gebruiker ID", type: "text" },
|
|
77
|
-
{ key: "station_id", label: "Pickstation", type: "select", options: stationOptions },
|
|
78
|
-
{ key: "country_code", label: "Land (leeg = alle)", type: "text" },
|
|
79
|
-
{ key: "urgent_only", label: "Alleen spoed", type: "boolean", defaultValue: false, inTable: false },
|
|
80
|
-
{ key: "can_reprint", label: "Mag herprinten", type: "boolean", defaultValue: false },
|
|
81
|
-
{ key: "can_break_lock", label: "Mag lock verbreken", type: "boolean", defaultValue: false },
|
|
82
|
-
{ key: "can_cancel", label: "Mag annuleren", type: "boolean", defaultValue: false },
|
|
83
|
-
] }) }), _jsx(TabsContent, { value: "logs", className: "mt-4", children: _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: "Laatste 50 acties" }) }), _jsxs(CardContent, { className: "space-y-1 text-sm", children: [safeArray(logs.data).map((l) => (_jsxs("div", { className: "flex justify-between border-b py-1 last:border-0", children: [_jsx("span", { className: "font-medium", children: l.action }), _jsx("span", { className: "text-muted-foreground", children: new Date(l.created_at).toLocaleString("nl-NL") })] }, l.id))), safeArray(logs.data).length === 0 && (_jsx("p", { className: "text-muted-foreground", children: "Nog geen acties gelogd." }))] })] }) })] })] }));
|
|
84
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PickDashboardPage.d.ts","sourceRoot":"","sources":["../../src/components/PickDashboardPage.tsx"],"names":[],"mappings":"AASA,wBAAgB,iBAAiB,gCA8IhC"}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
|
-
import { Badge, Card, CardContent, CardHeader, CardTitle } from "@flowselections/core";
|
|
5
|
-
import { Activity, Clock, Loader2, Printer, Users } from "lucide-react";
|
|
6
|
-
import { pickApi, pickDb } from "../lib/pickApi";
|
|
7
|
-
import { safeArray } from "../lib/pickTypes";
|
|
8
|
-
import { usePickPrinters, usePickStations } from "../hooks/usePickConfig";
|
|
9
|
-
export function PickDashboardPage() {
|
|
10
|
-
const queryClient = useQueryClient();
|
|
11
|
-
const { data: stations } = usePickStations();
|
|
12
|
-
const { data: printers } = usePickPrinters();
|
|
13
|
-
const dashboard = useQuery({
|
|
14
|
-
queryKey: ["pick", "dashboard"],
|
|
15
|
-
queryFn: pickApi.dashboard,
|
|
16
|
-
refetchInterval: 10000,
|
|
17
|
-
});
|
|
18
|
-
const heartbeats = useQuery({
|
|
19
|
-
queryKey: ["pick", "heartbeats"],
|
|
20
|
-
queryFn: pickApi.heartbeats,
|
|
21
|
-
refetchInterval: 10000,
|
|
22
|
-
});
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
const channel = pickDb
|
|
25
|
-
.channel("pick-dashboard")
|
|
26
|
-
.on("postgres_changes", { event: "*", schema: "public", table: "pick_queue" }, () => {
|
|
27
|
-
queryClient.invalidateQueries({ queryKey: ["pick", "dashboard"] });
|
|
28
|
-
})
|
|
29
|
-
.on("postgres_changes", { event: "*", schema: "public", table: "pick_queue_locks" }, () => {
|
|
30
|
-
queryClient.invalidateQueries({ queryKey: ["pick", "dashboard"] });
|
|
31
|
-
})
|
|
32
|
-
.subscribe();
|
|
33
|
-
return () => {
|
|
34
|
-
pickDb.removeChannel(channel);
|
|
35
|
-
};
|
|
36
|
-
}, [queryClient]);
|
|
37
|
-
const rows = safeArray(dashboard.data);
|
|
38
|
-
const beats = safeArray(heartbeats.data);
|
|
39
|
-
const safeStations = safeArray(stations);
|
|
40
|
-
const safePrinters = safeArray(printers);
|
|
41
|
-
return (_jsxs("main", { className: "space-y-6 p-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-foreground", children: "Live dashboard" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Realtime status van alle pickstations, schermen en printers." })] }), dashboard.isLoading ? (_jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Laden..."] })) : (_jsxs("div", { className: "grid gap-4 md:grid-cols-2 xl:grid-cols-3", children: [rows.map((row) => {
|
|
42
|
-
const station = safeStations.find((s) => s.id === row.station_id);
|
|
43
|
-
const online = beats.filter((b) => b.station_id === row.station_id &&
|
|
44
|
-
Date.now() - new Date(b.last_seen_at).getTime() < 60000).length;
|
|
45
|
-
const printer = safePrinters.find((p) => p.id === station?.default_printer_id);
|
|
46
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsx(CardTitle, { children: row.station_name }), _jsx(Badge, { className: online > 0
|
|
47
|
-
? "bg-emerald-600 text-white"
|
|
48
|
-
: "bg-muted text-muted-foreground", children: online > 0 ? `${online} online` : "offline" })] }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "grid grid-cols-3 gap-2 text-center", children: [_jsxs("div", { className: "rounded-lg bg-muted p-3", children: [_jsx("div", { className: "text-2xl font-bold", children: row.waiting }), _jsx("div", { className: "text-xs text-muted-foreground", children: "wachtend" })] }), _jsxs("div", { className: "rounded-lg bg-muted p-3", children: [_jsx("div", { className: "text-2xl font-bold", children: row.active }), _jsx("div", { className: "text-xs text-muted-foreground", children: "actief" })] }), _jsxs("div", { className: "rounded-lg bg-muted p-3", children: [_jsx("div", { className: "text-2xl font-bold", children: row.done_today }), _jsx("div", { className: "text-xs text-muted-foreground", children: "vandaag" })] })] }), _jsxs("div", { className: "space-y-1 text-sm text-muted-foreground", children: [_jsxs("p", { className: "flex items-center gap-2", children: [_jsx(Clock, { className: "h-4 w-4" }), "Gemiddelde wachttijd: ", Math.round(Number(row.avg_wait_seconds) / 60), " min"] }), _jsxs("p", { className: "flex items-center gap-2", children: [_jsx(Users, { className: "h-4 w-4" }), " Actieve sessies: ", row.active_sessions] }), _jsxs("p", { className: "flex items-center gap-2", children: [_jsx(Printer, { className: "h-4 w-4" }), " Printer: ", printer?.name ?? "geen", printer ? ` (${printer.status})` : ""] })] })] })] }, row.station_id));
|
|
49
|
-
}), rows.length === 0 && (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen actieve pickstations." }))] })), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Activity, { className: "h-5 w-5" }), " Printerstatus"] }) }), _jsx(CardContent, { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: safePrinters.map((p) => (_jsxs("div", { className: "flex items-center justify-between rounded-lg border p-3", children: [_jsxs("div", { children: [_jsx("div", { className: "font-medium", children: p.name }), _jsx("div", { className: "text-xs text-muted-foreground", children: p.location ?? "-" })] }), _jsx(Badge, { className: p.status === "online"
|
|
50
|
-
? "bg-emerald-600 text-white"
|
|
51
|
-
: p.status === "unknown"
|
|
52
|
-
? "bg-muted text-muted-foreground"
|
|
53
|
-
: "bg-destructive text-destructive-foreground", children: p.status })] }, p.id))) })] })] }));
|
|
54
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PickKioskPage.d.ts","sourceRoot":"","sources":["../../src/components/PickKioskPage.tsx"],"names":[],"mappings":"AAMA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,KAAK,+BA4B3D"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Loader2 } from "lucide-react";
|
|
3
|
-
import { usePickScreens, usePickStations } from "../hooks/usePickConfig";
|
|
4
|
-
import { safeArray } from "../lib/pickTypes";
|
|
5
|
-
import { PickScherm } from "./pick/PickScherm";
|
|
6
|
-
export function PickKioskPage({ stationId, screenId }) {
|
|
7
|
-
const { data: stations, isLoading: l1 } = usePickStations();
|
|
8
|
-
const { data: screens, isLoading: l2 } = usePickScreens(stationId);
|
|
9
|
-
const station = safeArray(stations).find((s) => s.id === stationId);
|
|
10
|
-
const screen = safeArray(screens).find((s) => s.id === screenId);
|
|
11
|
-
if (l1 || l2) {
|
|
12
|
-
return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-background", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin text-primary" }) }));
|
|
13
|
-
}
|
|
14
|
-
if (!station || !screen) {
|
|
15
|
-
return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-background", children: _jsx("p", { className: "text-muted-foreground", children: "Pickscherm niet gevonden." }) }));
|
|
16
|
-
}
|
|
17
|
-
return (_jsx("div", { className: "min-h-screen bg-background", children: _jsx(PickScherm, { station: station, screen: screen, kiosk: true }) }));
|
|
18
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PickstationDetailPage.d.ts","sourceRoot":"","sources":["../../src/components/PickstationDetailPage.tsx"],"names":[],"mappings":"AAOA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,+BA2FzD"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
3
|
-
import { Link } from "@tanstack/react-router";
|
|
4
|
-
import { Badge, Button, Card, CardContent } from "@flowselections/core";
|
|
5
|
-
import { ArrowLeft, Loader2, Maximize2, MonitorPlay } from "lucide-react";
|
|
6
|
-
import { PickScherm } from "./pick/PickScherm";
|
|
7
|
-
import { usePickScreens, usePickStations } from "../hooks/usePickConfig";
|
|
8
|
-
export function PickstationDetailPage({ stationId }) {
|
|
9
|
-
const { data: stations, isLoading } = usePickStations();
|
|
10
|
-
const { data: screens, isLoading: screensLoading } = usePickScreens(stationId);
|
|
11
|
-
const [screenId, setScreenId] = useState(null);
|
|
12
|
-
const station = useMemo(() => (Array.isArray(stations) ? stations : []).find((s) => s.id === stationId), [stations, stationId]);
|
|
13
|
-
const safeScreens = (Array.isArray(screens) ? screens : []).filter((s) => s.active);
|
|
14
|
-
const screen = safeScreens.find((s) => s.id === screenId);
|
|
15
|
-
if (isLoading || screensLoading) {
|
|
16
|
-
return (_jsxs("main", { className: "flex items-center gap-2 p-6 text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Laden..."] }));
|
|
17
|
-
}
|
|
18
|
-
if (!station) {
|
|
19
|
-
return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsx("p", { className: "text-muted-foreground", children: "Pickstation niet gevonden." }), _jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/pickstations", children: "Terug naar overzicht" }) })] }));
|
|
20
|
-
}
|
|
21
|
-
if (screen) {
|
|
22
|
-
return (_jsx("main", { className: "p-6", children: _jsx(PickScherm, { station: station, screen: screen, onBack: () => setScreenId(null) }) }));
|
|
23
|
-
}
|
|
24
|
-
return (_jsxs("main", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-foreground", children: station.name }), _jsx("p", { className: "text-sm text-muted-foreground", children: station.description })] }), _jsx(Button, { variant: "outline", asChild: true, children: _jsxs(Link, { to: "/pickstations", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Alle pickstations"] }) })] }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3", children: [safeScreens.map((s) => (_jsx(Card, { className: "border-2 transition-all hover:border-primary", children: _jsxs(CardContent, { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx(MonitorPlay, { className: "mt-1 h-6 w-6 text-primary" }), _jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: s.name }), _jsx("p", { className: "text-sm text-muted-foreground", children: s.description })] })] }), _jsx(Badge, { variant: "outline", children: s.screen_type }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { className: "h-12 flex-1 text-base", onClick: () => setScreenId(s.id), children: "Openen" }), _jsx(Button, { variant: "outline", size: "icon", className: "h-12 w-12", asChild: true, children: _jsx(Link, { to: "/kiosk/$stationId/$screenId", params: { stationId: station.id, screenId: s.id }, target: "_blank", "aria-label": "Openen in kioskmodus", children: _jsx(Maximize2, { className: "h-5 w-5" }) }) })] })] }) }, s.id))), safeScreens.length === 0 && (_jsx("p", { className: "text-sm text-muted-foreground", children: "Dit pickstation heeft nog geen pickschermen. Voeg ze toe via Beheer." }))] })] }));
|
|
25
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export type FieldType = "text" | "textarea" | "number" | "boolean" | "color" | "select";
|
|
2
|
-
export interface CrudField {
|
|
3
|
-
key: string;
|
|
4
|
-
label: string;
|
|
5
|
-
type: FieldType;
|
|
6
|
-
options?: {
|
|
7
|
-
value: string;
|
|
8
|
-
label: string;
|
|
9
|
-
}[];
|
|
10
|
-
defaultValue?: unknown;
|
|
11
|
-
inTable?: boolean;
|
|
12
|
-
required?: boolean;
|
|
13
|
-
}
|
|
14
|
-
interface Props {
|
|
15
|
-
table: string;
|
|
16
|
-
title: string;
|
|
17
|
-
description?: string;
|
|
18
|
-
fields: CrudField[];
|
|
19
|
-
orderBy?: string;
|
|
20
|
-
filter?: {
|
|
21
|
-
column: string;
|
|
22
|
-
value: string;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export declare function ConfigCrud({ table, title, description, fields, orderBy, filter }: Props): import("react").JSX.Element;
|
|
26
|
-
export {};
|
|
27
|
-
//# sourceMappingURL=ConfigCrud.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigCrud.d.ts","sourceRoot":"","sources":["../../../src/components/pick/ConfigCrud.tsx"],"names":[],"mappings":"AAgCA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAExF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAID,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAsB,EAAE,MAAM,EAAE,EAAE,KAAK,+BA0MtG"}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
3
|
-
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
|
-
import { Button, Card, CardContent, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Textarea, toast, } from "@flowselections/core";
|
|
5
|
-
import { Loader2, Pencil, Plus, Trash2 } from "lucide-react";
|
|
6
|
-
import { pickApi, pickDb } from "../../lib/pickApi";
|
|
7
|
-
import { safeArray } from "../../lib/pickTypes";
|
|
8
|
-
export function ConfigCrud({ table, title, description, fields, orderBy = "sort_order", filter }) {
|
|
9
|
-
const queryClient = useQueryClient();
|
|
10
|
-
const [open, setOpen] = useState(false);
|
|
11
|
-
const [draft, setDraft] = useState({});
|
|
12
|
-
const queryKey = ["pick", "crud", table, filter?.value ?? "-"];
|
|
13
|
-
const { data, isLoading } = useQuery({
|
|
14
|
-
queryKey,
|
|
15
|
-
queryFn: async () => {
|
|
16
|
-
let q = pickDb.from(table).select("*").order(orderBy, { ascending: true });
|
|
17
|
-
if (filter)
|
|
18
|
-
q = q.eq(filter.column, filter.value);
|
|
19
|
-
const res = await q;
|
|
20
|
-
if (res.error)
|
|
21
|
-
throw new Error(res.error.message);
|
|
22
|
-
return safeArray(res.data);
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
const rows = safeArray(data);
|
|
26
|
-
const tableFields = useMemo(() => fields.filter((f) => f.inTable !== false), [fields]);
|
|
27
|
-
const save = useMutation({
|
|
28
|
-
mutationFn: async (row) => {
|
|
29
|
-
const payload = { ...row };
|
|
30
|
-
if (filter)
|
|
31
|
-
payload[filter.column] = filter.value;
|
|
32
|
-
return pickApi.upsert(table, payload);
|
|
33
|
-
},
|
|
34
|
-
onSuccess: () => {
|
|
35
|
-
toast.success("Opgeslagen");
|
|
36
|
-
setOpen(false);
|
|
37
|
-
queryClient.invalidateQueries({ queryKey });
|
|
38
|
-
queryClient.invalidateQueries({ queryKey: ["pick"] });
|
|
39
|
-
},
|
|
40
|
-
onError: (e) => toast.error(e instanceof Error ? e.message : "Opslaan mislukt (alleen beheerders)."),
|
|
41
|
-
});
|
|
42
|
-
const remove = useMutation({
|
|
43
|
-
mutationFn: (id) => pickApi.remove(table, id),
|
|
44
|
-
onSuccess: () => {
|
|
45
|
-
toast.success("Verwijderd");
|
|
46
|
-
queryClient.invalidateQueries({ queryKey });
|
|
47
|
-
queryClient.invalidateQueries({ queryKey: ["pick"] });
|
|
48
|
-
},
|
|
49
|
-
onError: (e) => toast.error(e instanceof Error ? e.message : "Verwijderen mislukt (alleen beheerders)."),
|
|
50
|
-
});
|
|
51
|
-
const openNew = () => {
|
|
52
|
-
const base = {};
|
|
53
|
-
for (const f of fields)
|
|
54
|
-
base[f.key] = f.defaultValue ?? (f.type === "boolean" ? true : "");
|
|
55
|
-
setDraft(base);
|
|
56
|
-
setOpen(true);
|
|
57
|
-
};
|
|
58
|
-
const openEdit = (row) => {
|
|
59
|
-
setDraft({ ...row });
|
|
60
|
-
setOpen(true);
|
|
61
|
-
};
|
|
62
|
-
const setField = (key, value) => setDraft((d) => ({ ...d, [key]: value }));
|
|
63
|
-
return (_jsxs(Card, { children: [_jsxs(CardContent, { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold text-foreground", children: title }), description && _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs(Button, { onClick: openNew, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Nieuw"] })] }), isLoading ? (_jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Laden..."] })) : (_jsx("div", { className: "overflow-x-auto rounded-lg border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [tableFields.map((f) => (_jsx(TableHead, { children: f.label }, f.key))), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsxs(TableBody, { children: [rows.map((row) => (_jsxs(TableRow, { children: [tableFields.map((f) => (_jsx(TableCell, { children: f.type === "boolean" ? (row[f.key] ? "Ja" : "Nee") : f.type === "color" ? (_jsx("span", { className: "inline-block h-5 w-10 rounded", style: { backgroundColor: String(row[f.key] ?? "#ccc") } })) : f.type === "select" ? (f.options?.find((o) => o.value === row[f.key])?.label ?? "-") : (String(row[f.key] ?? "-")) }, f.key))), _jsxs(TableCell, { className: "space-x-2 text-right", children: [_jsx(Button, { size: "icon", variant: "ghost", onClick: () => openEdit(row), "aria-label": "Bewerken", children: _jsx(Pencil, { className: "h-4 w-4" }) }), _jsx(Button, { size: "icon", variant: "ghost", onClick: () => remove.mutate(String(row.id)), "aria-label": "Verwijderen", children: _jsx(Trash2, { className: "h-4 w-4 text-destructive" }) })] })] }, row.id))), rows.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: tableFields.length + 1, className: "py-8 text-center text-muted-foreground", children: "Nog geen gegevens." }) }))] })] }) }))] }), _jsx(Dialog, { open: open, onOpenChange: setOpen, children: _jsxs(DialogContent, { className: "max-h-[85vh] overflow-y-auto", children: [_jsx(DialogHeader, { children: _jsxs(DialogTitle, { children: [draft.id ? "Bewerken" : "Nieuw", " \u2014 ", title] }) }), _jsx("div", { className: "space-y-4", children: fields.map((f) => (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: `fld-${f.key}`, children: f.label }), f.type === "textarea" ? (_jsx(Textarea, { id: `fld-${f.key}`, value: String(draft[f.key] ?? ""), onChange: (e) => setField(f.key, e.target.value) })) : f.type === "boolean" ? (_jsx("div", { children: _jsx(Switch, { checked: Boolean(draft[f.key]), onCheckedChange: (v) => setField(f.key, v) }) })) : f.type === "select" ? (_jsxs(Select, { value: draft[f.key] ? String(draft[f.key]) : "none", onValueChange: (v) => setField(f.key, v === "none" ? null : v), children: [_jsx(SelectTrigger, { id: `fld-${f.key}`, children: _jsx(SelectValue, { placeholder: "Kies..." }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "none", children: "Geen" }), (f.options ?? []).map((o) => (_jsx(SelectItem, { value: o.value, children: o.label }, o.value)))] })] })) : (_jsx(Input, { id: `fld-${f.key}`, type: f.type === "number" ? "number" : f.type === "color" ? "color" : "text", value: String(draft[f.key] ?? ""), onChange: (e) => setField(f.key, f.type === "number" ? Number(e.target.value) : e.target.value) }))] }, f.key))) }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => setOpen(false), children: "Annuleren" }), _jsxs(Button, { onClick: () => save.mutate(draft), disabled: save.isPending, children: [save.isPending && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Opslaan"] })] })] }) })] }));
|
|
64
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { PickCountry } from "../../lib/pickTypes";
|
|
2
|
-
interface Props {
|
|
3
|
-
countries: PickCountry[];
|
|
4
|
-
counts: Record<string, number>;
|
|
5
|
-
onSelect: (code: string) => void;
|
|
6
|
-
}
|
|
7
|
-
export declare function CountryTiles({ countries, counts, onSelect }: Props): import("react").JSX.Element;
|
|
8
|
-
export {};
|
|
9
|
-
//# sourceMappingURL=CountryTiles.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CountryTiles.d.ts","sourceRoot":"","sources":["../../../src/components/pick/CountryTiles.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,UAAU,KAAK;IACb,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,KAAK,+BAmClE"}
|