@flowselections/floriday-afhandeling-module 1.0.27 → 1.0.28
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/afhandeling/ControleLijstPrint.js +21 -21
- package/dist-lib/components/pickstation/PakbonTemplate.js +70 -70
- package/dist-lib/index.d.ts +0 -2
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +0 -2
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
- package/dist-lib/lib/carrierSignupMail.server.js +26 -26
- package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartControl.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/package.json +118 -132
- package/dist-lib/components/pickstation/KioskControle.d.ts +0 -2
- package/dist-lib/components/pickstation/KioskControle.d.ts.map +0 -1
- package/dist-lib/components/pickstation/KioskControle.js +0 -7
- package/dist-lib/components/pickstation/LanguagePicker.d.ts +0 -5
- package/dist-lib/components/pickstation/LanguagePicker.d.ts.map +0 -1
- package/dist-lib/components/pickstation/LanguagePicker.js +0 -5
- package/dist-lib/components/pickstation/PickstationPage.d.ts +0 -2
- package/dist-lib/components/pickstation/PickstationPage.d.ts.map +0 -1
- package/dist-lib/components/pickstation/PickstationPage.js +0 -279
package/package.json
CHANGED
|
@@ -1,132 +1,118 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@flowselections/floriday-afhandeling-module",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"private": false,
|
|
5
|
-
"sideEffects": false,
|
|
6
|
-
"type": "module",
|
|
7
|
-
"main": "./dist-lib/index.js",
|
|
8
|
-
"types": "./dist-lib/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"types": "./dist-lib/index.d.ts",
|
|
12
|
-
"default": "./dist-lib/index.js"
|
|
13
|
-
},
|
|
14
|
-
"./server-routes": {
|
|
15
|
-
"types": "./dist-lib/lib/serverRoutes/index.d.ts",
|
|
16
|
-
"default": "./dist-lib/lib/serverRoutes/index.js"
|
|
17
|
-
},
|
|
18
|
-
"./styles": "./dist-lib/styles.css"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"dist-lib"
|
|
22
|
-
],
|
|
23
|
-
"publishConfig": {
|
|
24
|
-
"access": "public"
|
|
25
|
-
},
|
|
26
|
-
"scripts": {
|
|
27
|
-
"dev": "vite dev",
|
|
28
|
-
"build": "vite build",
|
|
29
|
-
"build:lib": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && node -e \"require('fs').writeFileSync('dist-lib/styles.css', '@source \\\"./\\\";\\n')\"",
|
|
30
|
-
"build:lib:watch": "tsc -p tsconfig.build.json --watch",
|
|
31
|
-
"build:dev": "vite build --mode development",
|
|
32
|
-
"preview": "vite preview",
|
|
33
|
-
"lint": "eslint ."
|
|
34
|
-
},
|
|
35
|
-
"peerDependencies": {
|
|
36
|
-
"@flowselections/core": "*",
|
|
37
|
-
"@tanstack/react-query": "^5",
|
|
38
|
-
"react": "^18 || ^19",
|
|
39
|
-
"react-dom": "^18 || ^19"
|
|
40
|
-
},
|
|
41
|
-
"dependencies": {
|
|
42
|
-
"@ai-sdk/openai-compatible": "^3.0.9",
|
|
43
|
-
"@supabase/supabase-js": "^2.110.8",
|
|
44
|
-
"ai": "^7.0.26"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@cloudflare/vite-plugin": "^1.25.5",
|
|
48
|
-
"@eslint/js": "^9.32.0",
|
|
49
|
-
"@flowselections/core": "1.0.16",
|
|
50
|
-
"@lovable.dev/vite-tanstack-config": "2.9.
|
|
51
|
-
"@rsbuild/core": "^1.0.0",
|
|
52
|
-
"@tailwindcss/vite": "^4.2.1",
|
|
53
|
-
"@tanstack/react-query": "^5.83.0",
|
|
54
|
-
"@tanstack/router-plugin": "^1.167.10",
|
|
55
|
-
"@types/node": "^22.16.5",
|
|
56
|
-
"@types/react": "^19.2.0",
|
|
57
|
-
"@types/react-dom": "^19.2.0",
|
|
58
|
-
"@vitejs/plugin-react": "^5.0.4",
|
|
59
|
-
"eslint": "^9.32.0",
|
|
60
|
-
"eslint-plugin-react-hooks": "^5.2.0",
|
|
61
|
-
"eslint-plugin-react-refresh": "^0.4.20",
|
|
62
|
-
"globals": "^15.15.0",
|
|
63
|
-
"react": "^19.2.0",
|
|
64
|
-
"react-dom": "^19.2.0",
|
|
65
|
-
"tailwindcss": "^4.2.1",
|
|
66
|
-
"tw-animate-css": "^1.3.4",
|
|
67
|
-
"typescript": "^5.8.3",
|
|
68
|
-
"tsc-alias": "^1.8.0",
|
|
69
|
-
"typescript-eslint": "^8.56.1",
|
|
70
|
-
"vite": "^7.3.1",
|
|
71
|
-
"vite-tsconfig-paths": "^6.0.2",
|
|
72
|
-
"nitro": "3.0.260603-beta"
|
|
73
|
-
},
|
|
74
|
-
"flowselections": {
|
|
75
|
-
"moduleId": "Afhandeling",
|
|
76
|
-
"pages": [
|
|
77
|
-
{
|
|
78
|
-
"export": "LeveringenPage",
|
|
79
|
-
"route": "afhandeling/leveringen",
|
|
80
|
-
"title": "Planning en Leveringen"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"export": "NieuweLeveringPage",
|
|
84
|
-
"route": "afhandeling/leveringen/nieuw",
|
|
85
|
-
"title": "Levering aanmaken",
|
|
86
|
-
"nav": false
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
"export": "PickingPage",
|
|
90
|
-
"route": "afhandeling/picking",
|
|
91
|
-
"title": "Pick Agenda"
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"export": "ControlePage",
|
|
95
|
-
"route": "afhandeling/controle",
|
|
96
|
-
"title": "Controle Karren"
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
"export": "
|
|
100
|
-
"route": "
|
|
101
|
-
"title": "
|
|
102
|
-
"nav": false
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
"export": "NieuweVervoerderPage",
|
|
120
|
-
"route": "afhandeling/vervoerders/nieuw",
|
|
121
|
-
"title": "Nieuwe vervoerder",
|
|
122
|
-
"nav": false
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
"export": "VervoerderBewerkenPage",
|
|
126
|
-
"route": "afhandeling/vervoerders/$carrierId/bewerken",
|
|
127
|
-
"title": "Vervoerder bewerken",
|
|
128
|
-
"nav": false
|
|
129
|
-
}
|
|
130
|
-
]
|
|
131
|
-
}
|
|
132
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@flowselections/floriday-afhandeling-module",
|
|
3
|
+
"version": "1.0.28",
|
|
4
|
+
"private": false,
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist-lib/index.js",
|
|
8
|
+
"types": "./dist-lib/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist-lib/index.d.ts",
|
|
12
|
+
"default": "./dist-lib/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./server-routes": {
|
|
15
|
+
"types": "./dist-lib/lib/serverRoutes/index.d.ts",
|
|
16
|
+
"default": "./dist-lib/lib/serverRoutes/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./styles": "./dist-lib/styles.css"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist-lib"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"dev": "vite dev",
|
|
28
|
+
"build": "vite build",
|
|
29
|
+
"build:lib": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && node -e \"require('fs').writeFileSync('dist-lib/styles.css', '@source \\\"./\\\";\\n')\"",
|
|
30
|
+
"build:lib:watch": "tsc -p tsconfig.build.json --watch",
|
|
31
|
+
"build:dev": "vite build --mode development",
|
|
32
|
+
"preview": "vite preview",
|
|
33
|
+
"lint": "eslint ."
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@flowselections/core": "*",
|
|
37
|
+
"@tanstack/react-query": "^5",
|
|
38
|
+
"react": "^18 || ^19",
|
|
39
|
+
"react-dom": "^18 || ^19"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@ai-sdk/openai-compatible": "^3.0.9",
|
|
43
|
+
"@supabase/supabase-js": "^2.110.8",
|
|
44
|
+
"ai": "^7.0.26"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@cloudflare/vite-plugin": "^1.25.5",
|
|
48
|
+
"@eslint/js": "^9.32.0",
|
|
49
|
+
"@flowselections/core": "1.0.16",
|
|
50
|
+
"@lovable.dev/vite-tanstack-config": "2.9.1",
|
|
51
|
+
"@rsbuild/core": "^1.0.0",
|
|
52
|
+
"@tailwindcss/vite": "^4.2.1",
|
|
53
|
+
"@tanstack/react-query": "^5.83.0",
|
|
54
|
+
"@tanstack/router-plugin": "^1.167.10",
|
|
55
|
+
"@types/node": "^22.16.5",
|
|
56
|
+
"@types/react": "^19.2.0",
|
|
57
|
+
"@types/react-dom": "^19.2.0",
|
|
58
|
+
"@vitejs/plugin-react": "^5.0.4",
|
|
59
|
+
"eslint": "^9.32.0",
|
|
60
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
61
|
+
"eslint-plugin-react-refresh": "^0.4.20",
|
|
62
|
+
"globals": "^15.15.0",
|
|
63
|
+
"react": "^19.2.0",
|
|
64
|
+
"react-dom": "^19.2.0",
|
|
65
|
+
"tailwindcss": "^4.2.1",
|
|
66
|
+
"tw-animate-css": "^1.3.4",
|
|
67
|
+
"typescript": "^5.8.3",
|
|
68
|
+
"tsc-alias": "^1.8.0",
|
|
69
|
+
"typescript-eslint": "^8.56.1",
|
|
70
|
+
"vite": "^7.3.1",
|
|
71
|
+
"vite-tsconfig-paths": "^6.0.2",
|
|
72
|
+
"nitro": "3.0.260603-beta"
|
|
73
|
+
},
|
|
74
|
+
"flowselections": {
|
|
75
|
+
"moduleId": "Afhandeling",
|
|
76
|
+
"pages": [
|
|
77
|
+
{
|
|
78
|
+
"export": "LeveringenPage",
|
|
79
|
+
"route": "afhandeling/leveringen",
|
|
80
|
+
"title": "Planning en Leveringen"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"export": "NieuweLeveringPage",
|
|
84
|
+
"route": "afhandeling/leveringen/nieuw",
|
|
85
|
+
"title": "Levering aanmaken",
|
|
86
|
+
"nav": false
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"export": "PickingPage",
|
|
90
|
+
"route": "afhandeling/picking",
|
|
91
|
+
"title": "Pick Agenda"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"export": "ControlePage",
|
|
95
|
+
"route": "afhandeling/controle",
|
|
96
|
+
"title": "Controle Karren"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"export": "VervoerdersPage",
|
|
100
|
+
"route": "afhandeling/vervoerders",
|
|
101
|
+
"title": "Vervoerders",
|
|
102
|
+
"nav": false
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"export": "NieuweVervoerderPage",
|
|
106
|
+
"route": "afhandeling/vervoerders/nieuw",
|
|
107
|
+
"title": "Nieuwe vervoerder",
|
|
108
|
+
"nav": false
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"export": "VervoerderBewerkenPage",
|
|
112
|
+
"route": "afhandeling/vervoerders/$carrierId/bewerken",
|
|
113
|
+
"title": "Vervoerder bewerken",
|
|
114
|
+
"nav": false
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"KioskControle.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/KioskControle.tsx"],"names":[],"mappings":"AAGA,wBAAgB,aAAa,gCAoB5B"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useNavigate } from "@tanstack/react-router";
|
|
3
|
-
import { ControlePage } from "../afhandeling/ControlePage";
|
|
4
|
-
export function KioskControle() {
|
|
5
|
-
const navigate = useNavigate();
|
|
6
|
-
return (_jsxs("div", { className: "min-h-screen bg-slate-50 text-slate-900 flex flex-col", children: [_jsx("header", { className: "bg-white border-b sticky top-0 z-20", children: _jsxs("div", { className: "max-w-6xl mx-auto px-4 py-3 flex items-center gap-3", children: [_jsx("button", { onClick: () => navigate({ to: "/pickstation" }), className: "h-12 px-4 rounded-xl bg-white border-2 border-slate-300 hover:bg-slate-100 font-semibold", children: "\u2190 Terug naar Picking" }), _jsx("h1", { className: "text-xl font-semibold", children: "Picking-modus" })] }) }), _jsx("main", { className: "flex-1", children: _jsx(ControlePage, { onExit: () => navigate({ to: "/pickstation" }) }) })] }));
|
|
7
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LanguagePicker.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/LanguagePicker.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAExF,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;CAAE,+BAuBrF"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { PICKSTATION_LANGUAGES } from "../../lib/pickstationI18n";
|
|
3
|
-
export function LanguagePicker({ onPick }) {
|
|
4
|
-
return (_jsx("div", { className: "fixed inset-0 z-50 bg-slate-900 text-white flex items-center justify-center p-6", children: _jsxs("div", { className: "w-full max-w-3xl", children: [_jsx("h1", { className: "text-4xl font-semibold mb-2 text-center", children: "Pickstation" }), _jsx("p", { className: "text-slate-400 text-center mb-10 text-lg", children: "Kies uw taal \u00B7 Wybierz j\u0119zyk \u00B7 Alege\u021Bi limba \u00B7 \u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0435\u0437\u0438\u043A \u00B7 \u041E\u0431\u0435\u0440\u0456\u0442\u044C \u043C\u043E\u0432\u0443 \u00B7 Choose your language" }), _jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: PICKSTATION_LANGUAGES.map((lang) => (_jsxs("button", { onClick: () => onPick(lang.code), className: "bg-white text-slate-900 hover:bg-emerald-500 hover:text-white transition rounded-2xl py-6 px-6 text-left text-2xl font-semibold flex items-center gap-4 shadow-lg", children: [_jsx("span", { className: "text-4xl", children: lang.flag }), _jsx("span", { children: lang.label })] }, lang.code))) })] }) }));
|
|
5
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PickstationPage.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/PickstationPage.tsx"],"names":[],"mappings":"AA2EA,wBAAgB,eAAe,gCA6Z9B"}
|
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
|
-
import { useNavigate } from "@tanstack/react-router";
|
|
4
|
-
import { useQuery } from "@tanstack/react-query";
|
|
5
|
-
import { LanguagePicker } from "./LanguagePicker";
|
|
6
|
-
import { renderPakbonHtml } from "./PakbonTemplate";
|
|
7
|
-
import { printHtml, printPdfBase64 } from "./printDocuments";
|
|
8
|
-
import { ControleLijstPrint } from "../afhandeling/ControleLijstPrint";
|
|
9
|
-
import { countryCode } from "../../lib/countries";
|
|
10
|
-
import { PICKSTATION_DICT, PICKSTATION_LANGUAGES, } from "../../lib/pickstationI18n";
|
|
11
|
-
const LANG_KEY = "pickstation.lang";
|
|
12
|
-
const LAST_GOOD_ORDERS_KEY = "pickstation.lastGoodOrders";
|
|
13
|
-
function statusBadge(status, t, printedCount) {
|
|
14
|
-
switch (status) {
|
|
15
|
-
case "not_printed":
|
|
16
|
-
return { label: t.notPrinted, className: "bg-slate-200 text-slate-700" };
|
|
17
|
-
case "printed":
|
|
18
|
-
return {
|
|
19
|
-
label: `✓ ${t.printed(printedCount || 1)}`,
|
|
20
|
-
className: "bg-emerald-100 text-emerald-800",
|
|
21
|
-
};
|
|
22
|
-
case "checked":
|
|
23
|
-
return { label: `✓ ${t.statusChecked}`, className: "bg-sky-100 text-sky-800" };
|
|
24
|
-
case "ready":
|
|
25
|
-
return { label: t.statusReady, className: "bg-indigo-100 text-indigo-800" };
|
|
26
|
-
case "shipped":
|
|
27
|
-
return { label: t.statusShipped, className: "bg-amber-100 text-amber-900" };
|
|
28
|
-
case "delivered":
|
|
29
|
-
return { label: `✓ ${t.statusDelivered}`, className: "bg-emerald-600 text-white" };
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
const DAY_ABBR_BY_LANG = {
|
|
33
|
-
nl: ["ZO", "MA", "DI", "WO", "DO", "VR", "ZA"],
|
|
34
|
-
en: ["SU", "MO", "TU", "WE", "TH", "FR", "SA"],
|
|
35
|
-
pl: ["ND", "PN", "WT", "ŚR", "CZ", "PT", "SB"],
|
|
36
|
-
ro: ["DU", "LU", "MA", "MI", "JO", "VI", "SÂ"],
|
|
37
|
-
bg: ["НД", "ПН", "ВТ", "СР", "ЧТ", "ПТ", "СБ"],
|
|
38
|
-
uk: ["НД", "ПН", "ВТ", "СР", "ЧТ", "ПТ", "СБ"],
|
|
39
|
-
};
|
|
40
|
-
function computeKlaarzet(o, lang) {
|
|
41
|
-
if (!o.pickupDate || !o.pickupTime) {
|
|
42
|
-
return { label: "—", sortKey: Number.MAX_SAFE_INTEGER };
|
|
43
|
-
}
|
|
44
|
-
const [hh, mm] = o.pickupTime.split(":").map((n) => parseInt(n, 10));
|
|
45
|
-
const d = new Date(o.pickupDate);
|
|
46
|
-
if (Number.isNaN(d.getTime()) || Number.isNaN(hh) || Number.isNaN(mm)) {
|
|
47
|
-
return { label: "—", sortKey: Number.MAX_SAFE_INTEGER };
|
|
48
|
-
}
|
|
49
|
-
d.setHours(hh, mm, 0, 0);
|
|
50
|
-
// Klaarzet = ophaaltijd minus 1 uur.
|
|
51
|
-
d.setHours(d.getHours() - 1);
|
|
52
|
-
const day = (DAY_ABBR_BY_LANG[lang] ?? DAY_ABBR_BY_LANG.nl)[d.getDay()];
|
|
53
|
-
const time = `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
|
|
54
|
-
return { label: `${day} - ${time}`, sortKey: d.getTime() };
|
|
55
|
-
}
|
|
56
|
-
export function PickstationPage() {
|
|
57
|
-
const navigate = useNavigate();
|
|
58
|
-
const [lang, setLang] = useState(null);
|
|
59
|
-
const [printingId, setPrintingId] = useState(null);
|
|
60
|
-
const [pickerOpen, setPickerOpen] = useState(false);
|
|
61
|
-
const [lastGoodOrders, setLastGoodOrders] = useState([]);
|
|
62
|
-
const [pendingConfirm, setPendingConfirm] = useState(null);
|
|
63
|
-
const [confirming, setConfirming] = useState(false);
|
|
64
|
-
const [printWarning, setPrintWarning] = useState(null);
|
|
65
|
-
const [showChecklist, setShowChecklist] = useState(false);
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
const stored = (typeof localStorage !== "undefined"
|
|
68
|
-
? localStorage.getItem(LANG_KEY)
|
|
69
|
-
: null);
|
|
70
|
-
const storedOrders = typeof localStorage !== "undefined"
|
|
71
|
-
? localStorage.getItem(LAST_GOOD_ORDERS_KEY)
|
|
72
|
-
: null;
|
|
73
|
-
if (storedOrders) {
|
|
74
|
-
try {
|
|
75
|
-
const parsed = JSON.parse(storedOrders);
|
|
76
|
-
if (Array.isArray(parsed))
|
|
77
|
-
setLastGoodOrders(parsed);
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
localStorage.removeItem(LAST_GOOD_ORDERS_KEY);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (stored && PICKSTATION_LANGUAGES.some((l) => l.code === stored)) {
|
|
84
|
-
setLang(stored);
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
setPickerOpen(true);
|
|
88
|
-
}
|
|
89
|
-
}, []);
|
|
90
|
-
const pickLang = useCallback((l) => {
|
|
91
|
-
setLang(l);
|
|
92
|
-
setPickerOpen(false);
|
|
93
|
-
try {
|
|
94
|
-
localStorage.setItem(LANG_KEY, l);
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
/* ignore */
|
|
98
|
-
}
|
|
99
|
-
}, []);
|
|
100
|
-
const ordersQuery = useQuery({
|
|
101
|
-
queryKey: ["pickstation", "orders"],
|
|
102
|
-
queryFn: async () => {
|
|
103
|
-
const res = await fetch("/api/public/pickstation/orders", { cache: "no-store" });
|
|
104
|
-
if (!res.ok)
|
|
105
|
-
throw new Error(`HTTP ${res.status}`);
|
|
106
|
-
return res.json();
|
|
107
|
-
},
|
|
108
|
-
refetchInterval: 30000,
|
|
109
|
-
refetchOnWindowFocus: true,
|
|
110
|
-
enabled: lang !== null,
|
|
111
|
-
});
|
|
112
|
-
const t = useMemo(() => PICKSTATION_DICT[lang ?? "nl"], [lang]);
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
if (ordersQuery.data && !ordersQuery.data.error) {
|
|
115
|
-
const next = ordersQuery.data.orders ?? [];
|
|
116
|
-
setLastGoodOrders(next);
|
|
117
|
-
try {
|
|
118
|
-
localStorage.setItem(LAST_GOOD_ORDERS_KEY, JSON.stringify(next));
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
/* ignore */
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}, [ordersQuery.data]);
|
|
125
|
-
const queryError = ordersQuery.data?.error ??
|
|
126
|
-
(ordersQuery.error instanceof Error ? ordersQuery.error.message : undefined);
|
|
127
|
-
const freshOrders = ordersQuery.data?.orders ?? [];
|
|
128
|
-
const unsortedOrders = queryError ? lastGoodOrders : freshOrders;
|
|
129
|
-
const orders = useMemo(() => {
|
|
130
|
-
return unsortedOrders
|
|
131
|
-
.map((o) => ({ o, k: computeKlaarzet(o, lang ?? "nl") }))
|
|
132
|
-
.sort((a, b) => {
|
|
133
|
-
if (a.k.sortKey !== b.k.sortKey)
|
|
134
|
-
return a.k.sortKey - b.k.sortKey;
|
|
135
|
-
const ac = a.o.country ?? "\uFFFF";
|
|
136
|
-
const bc = b.o.country ?? "\uFFFF";
|
|
137
|
-
if (ac !== bc)
|
|
138
|
-
return ac.localeCompare(bc);
|
|
139
|
-
const an = a.o.cartNumber ?? "\uFFFF";
|
|
140
|
-
const bn = b.o.cartNumber ?? "\uFFFF";
|
|
141
|
-
return an.localeCompare(bn);
|
|
142
|
-
})
|
|
143
|
-
.map((x) => x.o);
|
|
144
|
-
}, [unsortedOrders]);
|
|
145
|
-
const printedCount = orders.filter((o) => o.printedCount > 0).length;
|
|
146
|
-
const handlePrint = useCallback(async (order) => {
|
|
147
|
-
if (printingId || pendingConfirm)
|
|
148
|
-
return;
|
|
149
|
-
setPrintingId(order.id);
|
|
150
|
-
setPrintWarning(null);
|
|
151
|
-
try {
|
|
152
|
-
const documents = ["packing-slip", "auction-letter"];
|
|
153
|
-
if (order.deliveryNoteAvailable)
|
|
154
|
-
documents.push("delivery-note");
|
|
155
|
-
let auctionLetter = null;
|
|
156
|
-
let deliveryNote = null;
|
|
157
|
-
try {
|
|
158
|
-
const res = await fetch("/api/public/pickstation/print", {
|
|
159
|
-
method: "POST",
|
|
160
|
-
headers: { "Content-Type": "application/json" },
|
|
161
|
-
body: JSON.stringify({
|
|
162
|
-
orderId: order.id,
|
|
163
|
-
sourceOrderId: order.orderId,
|
|
164
|
-
orderNumber: `${order.orderNumber} (kar ${order.cartIndex}/${order.cartTotal})`,
|
|
165
|
-
customerName: order.customerName,
|
|
166
|
-
documents,
|
|
167
|
-
confirmed: false,
|
|
168
|
-
}),
|
|
169
|
-
});
|
|
170
|
-
if (res.ok) {
|
|
171
|
-
const body = (await res.json());
|
|
172
|
-
auctionLetter = body.auctionLetter ?? null;
|
|
173
|
-
deliveryNote = body.deliveryNote ?? null;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
catch {
|
|
177
|
-
/* network error – continue with pakbon only */
|
|
178
|
-
}
|
|
179
|
-
const html = renderPakbonHtml(order, lang ?? "nl");
|
|
180
|
-
await printHtml(html);
|
|
181
|
-
if (auctionLetter) {
|
|
182
|
-
await printPdfBase64(auctionLetter.base64, auctionLetter.mime);
|
|
183
|
-
}
|
|
184
|
-
if (deliveryNote) {
|
|
185
|
-
await printPdfBase64(deliveryNote.base64, deliveryNote.mime);
|
|
186
|
-
}
|
|
187
|
-
setPendingConfirm(order);
|
|
188
|
-
}
|
|
189
|
-
finally {
|
|
190
|
-
setPrintingId(null);
|
|
191
|
-
}
|
|
192
|
-
}, [printingId, pendingConfirm, lang]);
|
|
193
|
-
const confirmPrinted = useCallback(async (yes) => {
|
|
194
|
-
const order = pendingConfirm;
|
|
195
|
-
if (!order)
|
|
196
|
-
return;
|
|
197
|
-
if (!yes) {
|
|
198
|
-
setPendingConfirm(null);
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
setConfirming(true);
|
|
202
|
-
setPrintWarning(null);
|
|
203
|
-
try {
|
|
204
|
-
const documents = ["packing-slip", "auction-letter"];
|
|
205
|
-
if (order.deliveryNoteAvailable)
|
|
206
|
-
documents.push("delivery-note");
|
|
207
|
-
const res = await fetch("/api/public/pickstation/print", {
|
|
208
|
-
method: "POST",
|
|
209
|
-
headers: { "Content-Type": "application/json" },
|
|
210
|
-
body: JSON.stringify({
|
|
211
|
-
orderId: order.id,
|
|
212
|
-
sourceOrderId: order.orderId,
|
|
213
|
-
orderNumber: `${order.orderNumber} (kar ${order.cartIndex}/${order.cartTotal})`,
|
|
214
|
-
customerName: order.customerName,
|
|
215
|
-
documents,
|
|
216
|
-
confirmed: true,
|
|
217
|
-
}),
|
|
218
|
-
});
|
|
219
|
-
if (res.ok) {
|
|
220
|
-
const body = (await res.json());
|
|
221
|
-
if (body.warning)
|
|
222
|
-
setPrintWarning(body.warning);
|
|
223
|
-
setLang(null);
|
|
224
|
-
setPickerOpen(true);
|
|
225
|
-
try {
|
|
226
|
-
localStorage.removeItem(LANG_KEY);
|
|
227
|
-
}
|
|
228
|
-
catch {
|
|
229
|
-
/* ignore */
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
setPrintWarning(`Bevestigen mislukt (HTTP ${res.status}).`);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
catch (e) {
|
|
237
|
-
setPrintWarning(e instanceof Error ? e.message : "Bevestigen mislukt.");
|
|
238
|
-
}
|
|
239
|
-
finally {
|
|
240
|
-
setConfirming(false);
|
|
241
|
-
setPendingConfirm(null);
|
|
242
|
-
void ordersQuery.refetch();
|
|
243
|
-
}
|
|
244
|
-
}, [pendingConfirm, ordersQuery]);
|
|
245
|
-
const printNext = useCallback(() => {
|
|
246
|
-
const next = orders.find((o) => o.status === "not_printed" && o.printedCount === 0) ??
|
|
247
|
-
orders.find((o) => o.printedCount === 0);
|
|
248
|
-
if (next)
|
|
249
|
-
void handlePrint(next);
|
|
250
|
-
}, [orders, handlePrint]);
|
|
251
|
-
if (!lang || pickerOpen) {
|
|
252
|
-
return _jsx(LanguagePicker, { onPick: pickLang });
|
|
253
|
-
}
|
|
254
|
-
return (_jsxs("div", { className: "min-h-screen bg-slate-50 text-slate-900", children: [_jsx("header", { className: "bg-white border-b sticky top-0 z-10", children: _jsxs("div", { className: "max-w-6xl mx-auto px-4 py-4 flex items-center gap-3 flex-wrap", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h1", { className: "text-2xl font-semibold leading-tight", children: t.title }), _jsxs("p", { className: "text-sm text-slate-500", children: [t.subtitle, " \u00B7 ", t.ofTotal(printedCount, orders.length)] })] }), _jsxs("button", { onClick: () => setPickerOpen(true), className: "h-14 px-5 rounded-xl bg-white border-2 border-slate-300 hover:bg-slate-100 font-semibold text-lg", children: ["\uD83C\uDF10 ", t.changeLang] }), _jsxs("button", { onClick: () => setShowChecklist(true), className: "h-14 px-5 rounded-xl bg-white border-2 border-slate-300 hover:bg-slate-100 font-semibold text-lg", children: ["\uD83D\uDCCB ", t.printChecklist] }), _jsxs("button", { onClick: () => navigate({ to: "/controle" }), className: "h-14 px-5 rounded-xl bg-sky-600 hover:bg-sky-700 text-white font-semibold text-lg shadow", children: ["\u2713 ", t.runControl] }), _jsxs("button", { onClick: printNext, disabled: printingId !== null || orders.length === 0, className: "h-14 px-6 rounded-xl bg-emerald-600 hover:bg-emerald-700 disabled:bg-slate-300 text-white font-bold text-lg shadow", children: ["\uD83D\uDDA8 ", t.printNext] })] }) }), _jsxs("main", { className: "max-w-6xl mx-auto px-4 py-6", children: [ordersQuery.isLoading && _jsx("p", { className: "text-xl text-center py-12", children: t.loading }), queryError && orders.length > 0 && (_jsxs("div", { className: "bg-amber-50 border-2 border-amber-300 text-amber-900 rounded-xl p-4 mb-4", children: [_jsx("strong", { children: "Let op:" }), " verversen is niet gelukt, daarom blijven de laatst bekende pakbonnen zichtbaar. ", queryError] })), printWarning && (_jsxs("div", { className: "bg-amber-50 border-2 border-amber-300 text-amber-900 rounded-xl p-4 mb-4", children: [_jsx("strong", { children: "Let op:" }), " ", printWarning] })), queryError && orders.length === 0 && (_jsxs("div", { className: "bg-rose-50 border-2 border-rose-300 text-rose-900 rounded-xl p-4 mb-4", children: [_jsx("strong", { children: "Picklijst niet bijgewerkt:" }), " ", queryError, " De orders zijn hierdoor niet verwijderd; controleer de Pickagenda of probeer opnieuw."] })), !ordersQuery.isLoading && orders.length === 0 && !queryError && (_jsx("p", { className: "text-2xl text-center py-16 text-slate-500", children: t.empty })), orders.length > 0 && (_jsx("div", { className: "bg-white rounded-2xl border border-slate-200 overflow-hidden shadow-sm", children: _jsxs("table", { className: "w-full text-lg", children: [_jsx("thead", { className: "bg-slate-100 text-slate-600 text-sm uppercase tracking-wide", children: _jsxs("tr", { children: [_jsx("th", { className: "text-left px-5 py-3", children: "Karnr" }), _jsx("th", { className: "text-left px-5 py-3", children: t.orderNumber }), _jsx("th", { className: "text-right px-5 py-3", children: "Fusten" }), _jsx("th", { className: "text-left px-5 py-3", children: "Land" }), _jsx("th", { className: "text-left px-5 py-3", children: "Klaarzetten" }), _jsx("th", { className: "text-left px-5 py-3", children: t.status })] }) }), _jsx("tbody", { children: orders.map((o) => {
|
|
255
|
-
const isPrinting = printingId === o.id;
|
|
256
|
-
const badge = statusBadge(o.status, t, o.printedCount);
|
|
257
|
-
const klaarzet = computeKlaarzet(o, lang ?? "nl");
|
|
258
|
-
return (_jsxs("tr", { className: `border-t border-slate-100 transition select-none ${isPrinting ? "bg-emerald-50" : "hover:bg-slate-50"}`, style: { minHeight: 64 }, children: [_jsx("td", { className: "px-5 py-4 whitespace-nowrap cursor-pointer", onClick: () => void handlePrint(o), children: _jsx("span", { className: "inline-block px-3 py-1.5 rounded-md bg-black text-white font-black text-xl tracking-widest font-mono whitespace-nowrap", children: o.cartNumber ?? "—" }) }), _jsx("td", { className: "px-5 py-4 font-semibold whitespace-nowrap cursor-pointer", onClick: () => void handlePrint(o), children: _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { children: o.orderNumber ?? "—" }), o.orderSource === "floriday" &&
|
|
259
|
-
(o.deliveryNoteAvailable ? (_jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-emerald-100 text-emerald-800 text-xs font-semibold", title: t.deliveryNoteReady, children: ["\uD83D\uDCC4 ", t.deliveryNoteReady] })) : (_jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-slate-100 text-slate-500 text-xs font-medium", title: t.deliveryNotePending, children: ["\u23F3 ", t.deliveryNotePending] })))] }) }), _jsx("td", { className: "px-5 py-4 text-right font-semibold", children: o.cratesOnCart != null ? o.cratesOnCart : "—" }), _jsx("td", { className: "px-5 py-4 font-semibold whitespace-nowrap", children: countryCode(o.country) ?? o.country ?? "—" }), _jsx("td", { className: "px-5 py-4 font-semibold whitespace-nowrap", children: klaarzet.label }), _jsx("td", { className: "px-5 py-4", children: isPrinting ? (_jsx("span", { className: "inline-flex items-center gap-2 px-3 py-1 rounded-full bg-emerald-600 text-white font-semibold", children: t.printingNow })) : (_jsx("span", { className: `inline-flex items-center gap-2 px-3 py-1 rounded-full font-semibold ${badge.className}`, children: badge.label })) })] }, o.id));
|
|
260
|
-
}) })] }) })), _jsx("p", { className: "text-xs text-slate-400 mt-6 text-center", children: t.printDialogHint })] }), pendingConfirm && (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: _jsxs("div", { className: "bg-white rounded-2xl shadow-2xl max-w-md w-full p-6", children: [_jsx("h2", { className: "text-2xl font-bold mb-2", children: t.confirmPrintedTitle }), _jsx("p", { className: "text-slate-600 mb-2", children: t.confirmPrintedBody }), _jsx("div", { className: "mb-4 inline-block px-4 py-2 rounded-md bg-black text-white font-black text-3xl tracking-widest font-mono", children: pendingConfirm.cartNumber ?? "—" }), _jsxs("p", { className: "text-slate-800 font-semibold mb-6", children: [pendingConfirm.orderNumber, " \u00B7 kar ", pendingConfirm.cartIndex, "/", pendingConfirm.cartTotal] }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("button", { onClick: () => void confirmPrinted(true), disabled: confirming, className: "h-14 rounded-xl bg-emerald-600 hover:bg-emerald-700 disabled:bg-slate-300 text-white font-bold text-lg shadow", children: ["\u2713 ", t.confirmYes] }), _jsxs("button", { onClick: () => void confirmPrinted(false), disabled: confirming, className: "h-14 rounded-xl bg-white border-2 border-slate-300 hover:bg-slate-100 disabled:opacity-60 font-semibold text-lg", children: ["\u2715 ", t.confirmNo] })] })] }) })), showChecklist && (_jsx(ControleLijstPrint, { lang: lang ?? "nl", carts: orders.map((o) => ({
|
|
261
|
-
cartNumberId: null,
|
|
262
|
-
cartNumber: o.cartNumber,
|
|
263
|
-
orderId: o.orderId,
|
|
264
|
-
orderSource: o.orderSource,
|
|
265
|
-
cartIndex: o.cartIndex - 1,
|
|
266
|
-
orderNumber: o.orderNumber,
|
|
267
|
-
orderNumbers: [o.orderNumber].filter(Boolean),
|
|
268
|
-
customerName: o.customerName,
|
|
269
|
-
carrierName: o.carrierName,
|
|
270
|
-
deliveryDate: o.deliveryDate,
|
|
271
|
-
pickupDate: o.pickupDate,
|
|
272
|
-
pickupTime: o.pickupTime,
|
|
273
|
-
country: o.country,
|
|
274
|
-
cratesOnCart: o.cratesOnCart,
|
|
275
|
-
pickDate: o.deliveryDate ?? "",
|
|
276
|
-
printedCount: o.printedCount,
|
|
277
|
-
status: o.status,
|
|
278
|
-
})), onClose: () => setShowChecklist(false) }))] }));
|
|
279
|
-
}
|