@flowselections/floriday-afhandeling-module 1.0.44 → 1.0.45
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/ControlePage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/ControlePage.js +92 -54
- package/dist-lib/hooks/useCartIndex.d.ts.map +1 -1
- package/dist-lib/hooks/useCartIndex.js +16 -7
- package/dist-lib/hooks/useEngineBufferEvents.d.ts +5 -0
- package/dist-lib/hooks/useEngineBufferEvents.d.ts.map +1 -1
- package/dist-lib/hooks/useEngineBufferEvents.js +18 -13
- package/dist-lib/hooks/useEngineTasks.d.ts.map +1 -1
- package/dist-lib/hooks/useEngineTasks.js +8 -18
- package/dist-lib/hooks/useKnownOrders.d.ts.map +1 -1
- package/dist-lib/hooks/useKnownOrders.js +2 -1
- package/dist-lib/hooks/useOrderPickDates.d.ts +1 -1
- package/dist-lib/hooks/useOrderPickDates.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderPickDates.js +5 -3
- package/dist-lib/hooks/usePickAgenda.d.ts.map +1 -1
- package/dist-lib/hooks/usePickAgenda.js +17 -13
- package/dist-lib/hooks/usePickMode.d.ts +8 -2
- package/dist-lib/hooks/usePickMode.d.ts.map +1 -1
- package/dist-lib/hooks/usePickMode.js +17 -9
- package/dist-lib/index.d.ts +1 -2
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +1 -33
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +3053 -161
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +3053 -161
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +2982 -88
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +3063 -143
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/afhandelingSettings.functions.d.ts +5798 -14
- package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
- package/dist-lib/lib/carriers.functions.d.ts +14510 -40
- package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.d.ts +14495 -35
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartControl.functions.d.ts +31999 -104
- package/dist-lib/lib/cartControl.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartControl.functions.js +389 -259
- package/dist-lib/lib/deliveryNote.functions.d.ts +3053 -161
- package/dist-lib/lib/deliveryNote.functions.d.ts.map +1 -1
- package/dist-lib/lib/engineLayouts.functions.d.ts +3053 -161
- package/dist-lib/lib/engineLayouts.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.d.ts +5798 -14
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/orderFulfilment.functions.d.ts +3053 -161
- package/dist-lib/lib/orderFulfilment.functions.d.ts.map +1 -1
- package/dist-lib/lib/pickDates.functions.d.ts +2985 -88
- package/dist-lib/lib/pickDates.functions.d.ts.map +1 -1
- package/dist-lib/lib/pickDates.functions.js +30 -3
- package/dist-lib/lib/pickMode.d.ts +20 -2
- package/dist-lib/lib/pickMode.d.ts.map +1 -1
- package/dist-lib/lib/pickMode.js +65 -16
- package/dist-lib/lib/realtimeBus.d.ts +20 -0
- package/dist-lib/lib/realtimeBus.d.ts.map +1 -0
- package/dist-lib/lib/realtimeBus.js +56 -0
- package/dist-lib/lib/serverFnError.d.ts +12 -0
- package/dist-lib/lib/serverFnError.d.ts.map +1 -1
- package/dist-lib/lib/serverFnError.js +48 -1
- package/dist-lib/moduleDefinition.d.ts +3 -0
- package/dist-lib/moduleDefinition.d.ts.map +1 -0
- package/dist-lib/moduleDefinition.js +36 -0
- package/package.json +2 -2
|
@@ -23,13 +23,40 @@ function keyOf(value) {
|
|
|
23
23
|
return null;
|
|
24
24
|
return normalizeOrderNumber(trimmed) ?? trimmed.toUpperCase();
|
|
25
25
|
}
|
|
26
|
+
/** Bovengrens per opvraging: liever een nette melding dan een vastlopend scherm. */
|
|
27
|
+
const MAX_ORDERS = 3000;
|
|
28
|
+
const MAX_TASKS = 6000;
|
|
29
|
+
function defaultWindow() {
|
|
30
|
+
const today = new Date();
|
|
31
|
+
const shift = (delta) => {
|
|
32
|
+
const d = new Date(today);
|
|
33
|
+
d.setUTCDate(d.getUTCDate() + delta);
|
|
34
|
+
return d.toISOString().slice(0, 10);
|
|
35
|
+
};
|
|
36
|
+
return { from: shift(-60), to: shift(60) };
|
|
37
|
+
}
|
|
26
38
|
export const listOrderPickDates = createServerFn({ method: "GET" })
|
|
27
39
|
.middleware([requireSupabaseAuth])
|
|
28
|
-
.
|
|
40
|
+
.inputValidator((input) => input ?? {})
|
|
41
|
+
.handler(async ({ context, data }) => {
|
|
29
42
|
const supabase = context.supabase;
|
|
43
|
+
const fallback = defaultWindow();
|
|
44
|
+
const from = data.from ?? fallback.from;
|
|
45
|
+
const to = data.to ?? fallback.to;
|
|
30
46
|
const [ordersRes, tasksRes] = await Promise.all([
|
|
31
|
-
supabase
|
|
32
|
-
|
|
47
|
+
supabase
|
|
48
|
+
.from("orders")
|
|
49
|
+
.select("id, order_number, delivery_date")
|
|
50
|
+
.is("deleted_at", null)
|
|
51
|
+
.gte("delivery_date", from)
|
|
52
|
+
.lte("delivery_date", to)
|
|
53
|
+
.limit(MAX_ORDERS),
|
|
54
|
+
supabase
|
|
55
|
+
.from("logistics_tasks")
|
|
56
|
+
.select("order_ref, planned_start")
|
|
57
|
+
.gte("planned_start", `${from}T00:00:00Z`)
|
|
58
|
+
.lte("planned_start", `${to}T23:59:59Z`)
|
|
59
|
+
.limit(MAX_TASKS),
|
|
33
60
|
]);
|
|
34
61
|
if (ordersRes.error)
|
|
35
62
|
return { items: [], error: ordersRes.error.message };
|
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
export type PickMode = "order" | "cart" | "smallest" | "buffer" | null;
|
|
2
|
+
/**
|
|
3
|
+
* `status` maakt het verschil tussen "de Engine zegt dat er niet per kar wordt
|
|
4
|
+
* gepickt" (ok) en "we konden het niet ophalen" (unknown). Een storing mag
|
|
5
|
+
* karcontrole niet stilzwijgend uitzetten.
|
|
6
|
+
*/
|
|
2
7
|
export interface PickModeInfo {
|
|
3
8
|
pickMode: PickMode;
|
|
4
9
|
showCartControl: boolean;
|
|
10
|
+
status: "unknown" | "ok";
|
|
11
|
+
lastError?: string;
|
|
5
12
|
}
|
|
6
|
-
/** Huidige (gecachete) waarde; standaard
|
|
13
|
+
/** Huidige (gecachete) waarde; standaard onbekend. */
|
|
7
14
|
export declare function getPickMode(): PickModeInfo;
|
|
8
15
|
export declare function subscribePickMode(cb: () => void): () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Haalt de werkwijze op bij de Engine. Gooit de fout door bij een storing; de
|
|
18
|
+
* laatst succesvol opgehaalde werkwijze blijft dan gewoon gelden.
|
|
19
|
+
*/
|
|
9
20
|
export declare function fetchPickMode(): Promise<PickModeInfo>;
|
|
10
21
|
export declare function startPickModeWatch(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Veilige variant voor plekken die niet met een fout om kunnen gaan (zoals de
|
|
24
|
+
* zijbalk): faalt stil en geeft de laatst bekende waarde terug.
|
|
25
|
+
*/
|
|
11
26
|
export declare function ensurePickMode(): Promise<PickModeInfo>;
|
|
12
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Forceert een verse ophaalactie (na het wijzigen van de werkwijze). Gooit de
|
|
29
|
+
* fout door, zodat de aanroeper "storing" kan onderscheiden van "uit".
|
|
30
|
+
*/
|
|
13
31
|
export declare function refreshPickMode(): Promise<PickModeInfo>;
|
|
14
32
|
//# sourceMappingURL=pickMode.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pickMode.d.ts","sourceRoot":"","sources":["../../src/lib/pickMode.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,IAAI,CAAC;AAEvE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"pickMode.d.ts","sourceRoot":"","sources":["../../src/lib/pickMode.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,IAAI,CAAC;AAEvE;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0BD,sDAAsD;AACtD,wBAAgB,WAAW,IAAI,YAAY,CAE1C;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAG5D;AAaD;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,YAAY,CAAC,CA4B3D;AAyBD,wBAAgB,kBAAkB,IAAI,IAAI,CA0BzC;AAMD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC,CAYtD;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAMvD"}
|
package/dist-lib/lib/pickMode.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { supabase } from "../integrations/supabase/moduleClient";
|
|
2
|
-
/**
|
|
3
|
-
const
|
|
4
|
-
|
|
2
|
+
/** Nog nooit met succes opgehaald: werkwijze onbekend. */
|
|
3
|
+
const UNKNOWN = { pickMode: null, showCartControl: false, status: "unknown" };
|
|
4
|
+
const PICK_MODE_TIMEOUT_MS = 8000;
|
|
5
|
+
let cached = UNKNOWN;
|
|
5
6
|
let inflight = null;
|
|
6
7
|
const listeners = new Set();
|
|
7
8
|
function normalize(raw) {
|
|
8
9
|
const row = Array.isArray(raw) ? raw[0] : raw;
|
|
9
10
|
if (!row || typeof row !== "object")
|
|
10
|
-
return
|
|
11
|
+
return { ...UNKNOWN };
|
|
11
12
|
const obj = row;
|
|
12
13
|
const mode = (obj.pickMode ?? obj.pick_mode);
|
|
13
14
|
const show = obj.showCartControl ?? obj.show_cart_control;
|
|
@@ -16,9 +17,10 @@ function normalize(raw) {
|
|
|
16
17
|
pickMode,
|
|
17
18
|
// Karcontrole uitsluitend bij picken per kar.
|
|
18
19
|
showCartControl: show === true && pickMode === "cart",
|
|
20
|
+
status: "ok",
|
|
19
21
|
};
|
|
20
22
|
}
|
|
21
|
-
/** Huidige (gecachete) waarde; standaard
|
|
23
|
+
/** Huidige (gecachete) waarde; standaard onbekend. */
|
|
22
24
|
export function getPickMode() {
|
|
23
25
|
return cached;
|
|
24
26
|
}
|
|
@@ -26,24 +28,58 @@ export function subscribePickMode(cb) {
|
|
|
26
28
|
listeners.add(cb);
|
|
27
29
|
return () => listeners.delete(cb);
|
|
28
30
|
}
|
|
31
|
+
/** Oplopende wachttijd na een mislukte poging, zodat we niet blijven stormen. */
|
|
32
|
+
const RETRY_BACKOFF_MS = [2000, 5000, 15000, 30000];
|
|
33
|
+
let failures = 0;
|
|
34
|
+
let lastFailure = 0;
|
|
35
|
+
function backoffActive() {
|
|
36
|
+
if (!failures)
|
|
37
|
+
return false;
|
|
38
|
+
const wait = RETRY_BACKOFF_MS[Math.min(failures - 1, RETRY_BACKOFF_MS.length - 1)];
|
|
39
|
+
return Date.now() - lastFailure < wait;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Haalt de werkwijze op bij de Engine. Gooit de fout door bij een storing; de
|
|
43
|
+
* laatst succesvol opgehaalde werkwijze blijft dan gewoon gelden.
|
|
44
|
+
*/
|
|
29
45
|
export async function fetchPickMode() {
|
|
30
46
|
const previous = cached;
|
|
31
47
|
try {
|
|
32
|
-
|
|
48
|
+
let timeoutId;
|
|
49
|
+
const timeout = new Promise((_, reject) => {
|
|
50
|
+
timeoutId = setTimeout(() => reject(new Error("De planning antwoordt niet binnen 8 seconden")), PICK_MODE_TIMEOUT_MS);
|
|
51
|
+
});
|
|
52
|
+
const request = supabase.rpc("logistics_pick_mode");
|
|
53
|
+
const { data, error } = await Promise.race([request, timeout]);
|
|
54
|
+
if (timeoutId)
|
|
55
|
+
clearTimeout(timeoutId);
|
|
33
56
|
if (error)
|
|
34
57
|
throw new Error(error.message);
|
|
35
58
|
cached = normalize(data);
|
|
59
|
+
failures = 0;
|
|
60
|
+
lastFetch = Date.now();
|
|
36
61
|
}
|
|
37
|
-
catch {
|
|
38
|
-
|
|
62
|
+
catch (err) {
|
|
63
|
+
failures += 1;
|
|
64
|
+
lastFailure = Date.now();
|
|
65
|
+
const message = err instanceof Error ? err.message : "onbekende fout";
|
|
66
|
+
// Laatst bekende werkwijze behouden; alleen de foutmelding aanvullen.
|
|
67
|
+
cached = { ...previous, lastError: message };
|
|
68
|
+
notifyListeners(previous);
|
|
69
|
+
throw err instanceof Error ? err : new Error(message);
|
|
39
70
|
}
|
|
40
|
-
|
|
41
|
-
if (previous.pickMode !== cached.pickMode || previous.showCartControl !== cached.showCartControl) {
|
|
42
|
-
notifyChanged();
|
|
43
|
-
}
|
|
44
|
-
listeners.forEach((cb) => cb());
|
|
71
|
+
notifyListeners(previous);
|
|
45
72
|
return cached;
|
|
46
73
|
}
|
|
74
|
+
function notifyListeners(previous) {
|
|
75
|
+
const changed = previous.pickMode !== cached.pickMode ||
|
|
76
|
+
previous.showCartControl !== cached.showCartControl ||
|
|
77
|
+
previous.status !== cached.status;
|
|
78
|
+
if (!changed)
|
|
79
|
+
return;
|
|
80
|
+
notifyChanged();
|
|
81
|
+
listeners.forEach((cb) => cb());
|
|
82
|
+
}
|
|
47
83
|
function notifyChanged() {
|
|
48
84
|
if (typeof window !== "undefined") {
|
|
49
85
|
// Zodat de zijbalk van de shell direct meeloopt met de nieuwe werkwijze.
|
|
@@ -84,20 +120,33 @@ export function startPickModeWatch() {
|
|
|
84
120
|
/** Haalt één keer op en hergebruikt de lopende aanvraag. */
|
|
85
121
|
let lastFetch = 0;
|
|
86
122
|
const TTL_MS = 10000;
|
|
123
|
+
/**
|
|
124
|
+
* Veilige variant voor plekken die niet met een fout om kunnen gaan (zoals de
|
|
125
|
+
* zijbalk): faalt stil en geeft de laatst bekende waarde terug.
|
|
126
|
+
*/
|
|
87
127
|
export function ensurePickMode() {
|
|
88
128
|
startPickModeWatch();
|
|
89
129
|
if (!inflight && lastFetch > 0 && Date.now() - lastFetch < TTL_MS)
|
|
90
130
|
return Promise.resolve(cached);
|
|
131
|
+
if (!inflight && backoffActive())
|
|
132
|
+
return Promise.resolve(cached);
|
|
91
133
|
if (!inflight) {
|
|
92
|
-
inflight = fetchPickMode()
|
|
134
|
+
inflight = fetchPickMode()
|
|
135
|
+
.catch(() => cached)
|
|
136
|
+
.finally(() => {
|
|
93
137
|
inflight = null;
|
|
94
138
|
});
|
|
95
139
|
}
|
|
96
140
|
return inflight;
|
|
97
141
|
}
|
|
98
|
-
/**
|
|
142
|
+
/**
|
|
143
|
+
* Forceert een verse ophaalactie (na het wijzigen van de werkwijze). Gooit de
|
|
144
|
+
* fout door, zodat de aanroeper "storing" kan onderscheiden van "uit".
|
|
145
|
+
*/
|
|
99
146
|
export function refreshPickMode() {
|
|
100
147
|
lastFetch = 0;
|
|
148
|
+
failures = 0;
|
|
101
149
|
inflight = null;
|
|
102
|
-
|
|
150
|
+
startPickModeWatch();
|
|
151
|
+
return fetchPickMode();
|
|
103
152
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eén gedeelde realtime-verbinding per tabel, met samenvoegen van seintjes.
|
|
3
|
+
*
|
|
4
|
+
* Zonder dit maakte elk scherm-onderdeel een eigen kanaal met een willekeurige
|
|
5
|
+
* naam, en leidde elke wijziging van de Engine direct tot opnieuw ophalen. Bij
|
|
6
|
+
* een reeks wijzigingen (de Engine schrijft tientallen taken achter elkaar)
|
|
7
|
+
* stapelden die opvragingen op en blokkeerde het scherm.
|
|
8
|
+
*/
|
|
9
|
+
type Listener = (row: Record<string, unknown>) => void;
|
|
10
|
+
/** Abonneer op wijzigingen van één tabel. Geeft een opzegfunctie terug. */
|
|
11
|
+
export declare function subscribeTable(table: string, listener: Listener): () => void;
|
|
12
|
+
/**
|
|
13
|
+
* Voegt snel opeenvolgende aanroepen samen tot één aanroep. Zonder dit leidt
|
|
14
|
+
* elke afzonderlijke wijziging van de Engine tot een eigen opvraging.
|
|
15
|
+
*/
|
|
16
|
+
export declare function debounce(fn: () => void, waitMs?: number): (() => void) & {
|
|
17
|
+
cancel: () => void;
|
|
18
|
+
};
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=realtimeBus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtimeBus.d.ts","sourceRoot":"","sources":["../../src/lib/realtimeBus.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,KAAK,QAAQ,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAiCvD,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAO5E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,MAAM,SAAM,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,IAAI,CAAA;CAAE,CAc5F"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { supabase } from "../integrations/supabase/moduleClient";
|
|
2
|
+
const entries = new Map();
|
|
3
|
+
function ensureEntry(table) {
|
|
4
|
+
const existing = entries.get(table);
|
|
5
|
+
if (existing)
|
|
6
|
+
return existing;
|
|
7
|
+
const listeners = new Set();
|
|
8
|
+
const channel = supabase
|
|
9
|
+
.channel(`shared-${table}`)
|
|
10
|
+
.on("postgres_changes", { event: "*", schema: "public", table }, (payload) => {
|
|
11
|
+
const row = (payload.new ?? payload.old ?? {});
|
|
12
|
+
for (const listener of listeners)
|
|
13
|
+
listener(row);
|
|
14
|
+
})
|
|
15
|
+
.subscribe();
|
|
16
|
+
const entry = {
|
|
17
|
+
listeners,
|
|
18
|
+
unsubscribe: () => {
|
|
19
|
+
supabase.removeChannel(channel);
|
|
20
|
+
entries.delete(table);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
entries.set(table, entry);
|
|
24
|
+
return entry;
|
|
25
|
+
}
|
|
26
|
+
/** Abonneer op wijzigingen van één tabel. Geeft een opzegfunctie terug. */
|
|
27
|
+
export function subscribeTable(table, listener) {
|
|
28
|
+
const entry = ensureEntry(table);
|
|
29
|
+
entry.listeners.add(listener);
|
|
30
|
+
return () => {
|
|
31
|
+
entry.listeners.delete(listener);
|
|
32
|
+
if (entry.listeners.size === 0)
|
|
33
|
+
entry.unsubscribe();
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Voegt snel opeenvolgende aanroepen samen tot één aanroep. Zonder dit leidt
|
|
38
|
+
* elke afzonderlijke wijziging van de Engine tot een eigen opvraging.
|
|
39
|
+
*/
|
|
40
|
+
export function debounce(fn, waitMs = 750) {
|
|
41
|
+
let timer = null;
|
|
42
|
+
const run = () => {
|
|
43
|
+
if (timer)
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
timer = setTimeout(() => {
|
|
46
|
+
timer = null;
|
|
47
|
+
fn();
|
|
48
|
+
}, waitMs);
|
|
49
|
+
};
|
|
50
|
+
run.cancel = () => {
|
|
51
|
+
if (timer)
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
timer = null;
|
|
54
|
+
};
|
|
55
|
+
return run;
|
|
56
|
+
}
|
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
* een leeg scherm op. Deze helpers zetten hem altijd om naar een echte Error.
|
|
6
6
|
*/
|
|
7
7
|
export declare function toServerFnError(e: unknown): Promise<Error>;
|
|
8
|
+
/** Tijdslimiet per aanroep: zonder limiet blijft het scherm eindeloos laden. */
|
|
9
|
+
export declare const SERVER_CALL_TIMEOUT_MS = 15000;
|
|
10
|
+
export interface ServerFnCallOptions {
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
maxAttempts?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Roept een server function aan met tijdslimiet en beperkte herpoging, en
|
|
16
|
+
* logt de duur. Een hangende aanroep gaf eerder een scherm dat eeuwig
|
|
17
|
+
* "Laden..." bleef tonen.
|
|
18
|
+
*/
|
|
19
|
+
export declare function callServerFn<T>(call: () => Promise<T>, context?: string, options?: ServerFnCallOptions): Promise<T>;
|
|
8
20
|
/** Roept een server function aan en geeft bij elke fout de fallback terug. */
|
|
9
21
|
export declare function safeServerCall<T>(call: () => Promise<T>, fallback: T, context?: string): Promise<T>;
|
|
10
22
|
//# sourceMappingURL=serverFnError.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serverFnError.d.ts","sourceRoot":"","sources":["../../src/lib/serverFnError.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAUhE;AAED,8EAA8E;AAC9E,wBAAsB,cAAc,CAAC,CAAC,EACpC,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACtB,QAAQ,EAAE,CAAC,EACX,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,CAAC,CAQZ"}
|
|
1
|
+
{"version":3,"file":"serverFnError.d.ts","sourceRoot":"","sources":["../../src/lib/serverFnError.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAUhE;AAED,gFAAgF;AAChF,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAK7C,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAUD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACtB,OAAO,SAAa,EACpB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,CAAC,CAAC,CA+BZ;AAED,8EAA8E;AAC9E,wBAAsB,cAAc,CAAC,CAAC,EACpC,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACtB,QAAQ,EAAE,CAAC,EACX,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,CAAC,CAQZ"}
|
|
@@ -16,10 +16,57 @@ export async function toServerFnError(e) {
|
|
|
16
16
|
return e;
|
|
17
17
|
return new Error(String(e));
|
|
18
18
|
}
|
|
19
|
+
/** Tijdslimiet per aanroep: zonder limiet blijft het scherm eindeloos laden. */
|
|
20
|
+
export const SERVER_CALL_TIMEOUT_MS = 15000;
|
|
21
|
+
/** Aantal herpogingen bij tijdelijke fouten (niet bij 401/403). */
|
|
22
|
+
const MAX_ATTEMPTS = 3;
|
|
23
|
+
function isAuthFailure(err) {
|
|
24
|
+
return /^(401|403)\b/.test(err.message) || /Unauthorized|Forbidden/i.test(err.message);
|
|
25
|
+
}
|
|
26
|
+
function sleep(ms) {
|
|
27
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Roept een server function aan met tijdslimiet en beperkte herpoging, en
|
|
31
|
+
* logt de duur. Een hangende aanroep gaf eerder een scherm dat eeuwig
|
|
32
|
+
* "Laden..." bleef tonen.
|
|
33
|
+
*/
|
|
34
|
+
export async function callServerFn(call, context = "onbekend", options = {}) {
|
|
35
|
+
let lastError = new Error("Aanroep mislukt");
|
|
36
|
+
const timeoutMs = options.timeoutMs ?? SERVER_CALL_TIMEOUT_MS;
|
|
37
|
+
const maxAttempts = options.maxAttempts ?? MAX_ATTEMPTS;
|
|
38
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
39
|
+
const startedAt = Date.now();
|
|
40
|
+
let timeoutId;
|
|
41
|
+
try {
|
|
42
|
+
const timeout = new Promise((_, reject) => { timeoutId = setTimeout(() => reject(new Error(`Time-out na ${timeoutMs / 1000} seconden`)), timeoutMs); });
|
|
43
|
+
const result = await Promise.race([call(), timeout]);
|
|
44
|
+
if (timeoutId)
|
|
45
|
+
clearTimeout(timeoutId);
|
|
46
|
+
console.info("[serverFn] call done", { context, attempt, durationMs: Date.now() - startedAt });
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
if (timeoutId)
|
|
51
|
+
clearTimeout(timeoutId);
|
|
52
|
+
lastError = await toServerFnError(e);
|
|
53
|
+
console.warn("[serverFn] call attempt failed", {
|
|
54
|
+
context,
|
|
55
|
+
attempt,
|
|
56
|
+
durationMs: Date.now() - startedAt,
|
|
57
|
+
message: lastError.message,
|
|
58
|
+
});
|
|
59
|
+
if (isAuthFailure(lastError) || attempt === maxAttempts)
|
|
60
|
+
break;
|
|
61
|
+
await sleep(attempt * 500);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw lastError;
|
|
65
|
+
}
|
|
19
66
|
/** Roept een server function aan en geeft bij elke fout de fallback terug. */
|
|
20
67
|
export async function safeServerCall(call, fallback, context) {
|
|
21
68
|
try {
|
|
22
|
-
return await call
|
|
69
|
+
return await callServerFn(call, context ?? "onbekend");
|
|
23
70
|
}
|
|
24
71
|
catch (e) {
|
|
25
72
|
const err = await toServerFnError(e);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moduleDefinition.d.ts","sourceRoot":"","sources":["../src/moduleDefinition.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAgBvD,eAAO,MAAM,yBAAyB,EAAE,UAqBvC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { CalendarCheck, CalendarRange, ClipboardCheck, PackageCheck } from "lucide-react";
|
|
2
|
+
import { AfhandelingSettingsCard } from "./components/settings/AfhandelingSettingsCard";
|
|
3
|
+
import { VervoerdersSettingsCard } from "./components/settings/VervoerdersSettingsCard";
|
|
4
|
+
import { getPickMode } from "./lib/pickMode";
|
|
5
|
+
const baseChildren = [
|
|
6
|
+
{ label: "Pick Agenda", href: "/afhandeling/picking", icon: CalendarCheck },
|
|
7
|
+
{ label: "Planning en leveringen", href: "/afhandeling/leveringen", icon: CalendarRange },
|
|
8
|
+
];
|
|
9
|
+
const cartControlChild = {
|
|
10
|
+
label: "Controle karren",
|
|
11
|
+
href: "/afhandeling/controle",
|
|
12
|
+
icon: ClipboardCheck,
|
|
13
|
+
};
|
|
14
|
+
export const floridayAfhandelingModule = {
|
|
15
|
+
id: "afhandeling",
|
|
16
|
+
name: "Afhandeling",
|
|
17
|
+
version: "1.4.0",
|
|
18
|
+
nav: {
|
|
19
|
+
label: "Afhandeling",
|
|
20
|
+
href: "/afhandeling/picking",
|
|
21
|
+
icon: PackageCheck,
|
|
22
|
+
get children() {
|
|
23
|
+
const info = getPickMode();
|
|
24
|
+
if (info.showCartControl)
|
|
25
|
+
return [...baseChildren, cartControlChild];
|
|
26
|
+
if (info.status !== "ok") {
|
|
27
|
+
return [...baseChildren, { ...cartControlChild, label: "Controle karren (onbekend)" }];
|
|
28
|
+
}
|
|
29
|
+
return baseChildren;
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
settingsCards: [
|
|
33
|
+
{ component: VervoerdersSettingsCard, order: 80 },
|
|
34
|
+
{ component: AfhandelingSettingsCard, order: 100 },
|
|
35
|
+
],
|
|
36
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowselections/floriday-afhandeling-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.45",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@cloudflare/vite-plugin": "^1.25.5",
|
|
50
50
|
"@eslint/js": "^9.32.0",
|
|
51
|
-
"@flowselections/core": "1.0.
|
|
51
|
+
"@flowselections/core": "1.0.21",
|
|
52
52
|
"@lovable.dev/vite-tanstack-config": "2.13.1",
|
|
53
53
|
"@rsbuild/core": "^1.0.0",
|
|
54
54
|
"@tailwindcss/vite": "^4.2.1",
|