@flowselections/logistiek-engine 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/README.md +24 -24
- package/dist-lib/components/AfmetingenBronnenCard.d.ts +2 -0
- package/dist-lib/components/AfmetingenBronnenCard.d.ts.map +1 -0
- package/dist-lib/components/AfmetingenBronnenCard.js +46 -0
- package/dist-lib/components/BufferDebugCard.d.ts.map +1 -1
- package/dist-lib/components/BufferDebugCard.js +6 -1
- package/dist-lib/components/ConsistentieCard.d.ts.map +1 -1
- package/dist-lib/components/ConsistentieCard.js +1 -1
- package/dist-lib/components/KarplanStatusCard.d.ts +2 -0
- package/dist-lib/components/KarplanStatusCard.d.ts.map +1 -0
- package/dist-lib/components/KarplanStatusCard.js +31 -0
- package/dist-lib/components/RegiePage.d.ts.map +1 -1
- package/dist-lib/components/RegiePage.js +3 -1
- package/dist-lib/components/RuleEnginePage.d.ts.map +1 -1
- package/dist-lib/components/RuleEnginePage.js +7 -4
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts +2 -0
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts.map +1 -0
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.js +41 -0
- package/dist-lib/components/rule-engine/RuleFieldInput.d.ts.map +1 -1
- package/dist-lib/components/rule-engine/RuleFieldInput.js +9 -0
- package/dist-lib/hooks/useRecalcJob.d.ts.map +1 -1
- package/dist-lib/hooks/useRecalcJob.js +26 -1
- package/dist-lib/hooks/useScannersPrinters.d.ts +11 -0
- package/dist-lib/hooks/useScannersPrinters.d.ts.map +1 -0
- package/dist-lib/hooks/useScannersPrinters.js +65 -0
- package/dist-lib/index.d.ts +2 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +2 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +2063 -78
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +20293 -0
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/client.js +13 -0
- package/dist-lib/integrations/supabase/client.server.d.ts +2063 -78
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.js +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +2063 -78
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +2097 -68
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/attachAuthToken.d.ts +2 -0
- package/dist-lib/lib/attachAuthToken.d.ts.map +1 -0
- package/dist-lib/lib/attachAuthToken.js +50 -0
- package/dist-lib/lib/bufferMatching.d.ts.map +1 -1
- package/dist-lib/lib/bufferMatching.js +1 -0
- package/dist-lib/lib/cartPlanRequests.server.d.ts +13 -0
- package/dist-lib/lib/cartPlanRequests.server.d.ts.map +1 -0
- package/dist-lib/lib/cartPlanRequests.server.js +168 -0
- package/dist-lib/lib/controlScan.server.d.ts +12 -0
- package/dist-lib/lib/controlScan.server.d.ts.map +1 -0
- package/dist-lib/lib/controlScan.server.js +197 -0
- package/dist-lib/lib/dimensionData.server.d.ts +11 -1
- package/dist-lib/lib/dimensionData.server.d.ts.map +1 -1
- package/dist-lib/lib/dimensionData.server.js +58 -48
- package/dist-lib/lib/dimensionPlanner.d.ts +26 -1
- package/dist-lib/lib/dimensionPlanner.d.ts.map +1 -1
- package/dist-lib/lib/dimensionPlanner.js +37 -6
- package/dist-lib/lib/floridayDocuments.functions.d.ts +6240 -285
- package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.functions.js +4 -3
- package/dist-lib/lib/floridayPush.functions.d.ts +2064 -79
- package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.functions.js +2 -1
- package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
- package/dist-lib/lib/handlers/logistics-tick.server.js +57 -0
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +10302 -377
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.functions.js +6 -5
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts +42 -0
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +563 -31
- package/dist-lib/lib/logisticsPlanner.d.ts.map +1 -1
- package/dist-lib/lib/logisticsPlanner.js +24 -9
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +4163 -193
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.functions.js +3 -2
- package/dist-lib/lib/logisticsRecalcJob.server.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.server.js +1 -0
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts +2064 -79
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalculate.functions.js +3 -1
- package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.js +2560 -1586
- package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/planQueue.server.js +6 -0
- package/dist-lib/lib/readableServerErrors.d.ts +2 -0
- package/dist-lib/lib/readableServerErrors.d.ts.map +1 -0
- package/dist-lib/lib/readableServerErrors.js +36 -0
- package/dist-lib/lib/ruleEngineSchema.d.ts +1 -1
- package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineSchema.js +72 -51
- package/dist-lib/lib/ruleEngineWizard.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineWizard.js +5 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
# logistiek Engine
|
|
2
|
-
|
|
3
|
-
blank project start
|
|
4
|
-
|
|
5
|
-
This project was built with [Lovable](https://lovable.dev).
|
|
6
|
-
|
|
7
|
-
## Build with Lovable
|
|
8
|
-
|
|
9
|
-
Continue developing this project in the [Lovable editor](https://lovable.dev/projects/316ec9c5-0f01-408a-b7ec-3d4dccf9b65d).
|
|
10
|
-
|
|
11
|
-
- **Ship faster**: describe what you want to build and Lovable handles the code.
|
|
12
|
-
- **Stay in sync**: every change made in Lovable is committed straight to this repository.
|
|
13
|
-
- **Full ownership**: this code is yours. Push to `main` on GitHub and your changes sync back into Lovable, ready for your next prompt.
|
|
14
|
-
|
|
15
|
-
## Development
|
|
16
|
-
|
|
17
|
-
Prefer working locally? You need Node.js and npm — [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
|
|
18
|
-
|
|
19
|
-
```sh
|
|
20
|
-
git clone <this-repository-url>
|
|
21
|
-
cd <repository-name>
|
|
22
|
-
npm i
|
|
23
|
-
npm run dev
|
|
24
|
-
```
|
|
1
|
+
# logistiek Engine
|
|
2
|
+
|
|
3
|
+
blank project start
|
|
4
|
+
|
|
5
|
+
This project was built with [Lovable](https://lovable.dev).
|
|
6
|
+
|
|
7
|
+
## Build with Lovable
|
|
8
|
+
|
|
9
|
+
Continue developing this project in the [Lovable editor](https://lovable.dev/projects/316ec9c5-0f01-408a-b7ec-3d4dccf9b65d).
|
|
10
|
+
|
|
11
|
+
- **Ship faster**: describe what you want to build and Lovable handles the code.
|
|
12
|
+
- **Stay in sync**: every change made in Lovable is committed straight to this repository.
|
|
13
|
+
- **Full ownership**: this code is yours. Push to `main` on GitHub and your changes sync back into Lovable, ready for your next prompt.
|
|
14
|
+
|
|
15
|
+
## Development
|
|
16
|
+
|
|
17
|
+
Prefer working locally? You need Node.js and npm — [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
git clone <this-repository-url>
|
|
21
|
+
cd <repository-name>
|
|
22
|
+
npm i
|
|
23
|
+
npm run dev
|
|
24
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AfmetingenBronnenCard.d.ts","sourceRoot":"","sources":["../../src/components/AfmetingenBronnenCard.tsx"],"names":[],"mappings":"AAuDA,wBAAgB,qBAAqB,gCAsHpC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/AfmetingenBronnenCard.tsx — herkomst van de afmetingen
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Toont per product waar het fust en de planthoogte vandaan komen: handmatig
|
|
6
|
+
// ingevuld, uit de Floriday-koppeling, of afgeleid uit de belading. Producten
|
|
7
|
+
// zonder bruikbare afmetingen staan met reden onderaan; die karren krijgen
|
|
8
|
+
// bewust geen laagindeling (fail closed).
|
|
9
|
+
// GEEN <Header /> hier — die levert de shell.
|
|
10
|
+
// ============================================================================
|
|
11
|
+
import { useCallback, useEffect, useState } from "react";
|
|
12
|
+
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, supabase, } from "@flowselections/core";
|
|
13
|
+
import { RefreshCw, Ruler } from "lucide-react";
|
|
14
|
+
const BRON_LABEL = {
|
|
15
|
+
handmatig: "Handmatig ingevuld",
|
|
16
|
+
floriday: "Uit Floriday",
|
|
17
|
+
belading: "Afgeleid uit de belading",
|
|
18
|
+
};
|
|
19
|
+
function bron(waarde) {
|
|
20
|
+
if (!waarde)
|
|
21
|
+
return "—";
|
|
22
|
+
return BRON_LABEL[waarde] ?? waarde;
|
|
23
|
+
}
|
|
24
|
+
export function AfmetingenBronnenCard() {
|
|
25
|
+
const [rijen, setRijen] = useState([]);
|
|
26
|
+
const [loading, setLoading] = useState(true);
|
|
27
|
+
const laden = useCallback(async () => {
|
|
28
|
+
setLoading(true);
|
|
29
|
+
const { data } = await supabase
|
|
30
|
+
.from("logistics_product_dimensions")
|
|
31
|
+
.select("product_id, product_name, fust_name, fust_source, fust_length_mm, fust_width_mm, fust_height_mm, plant_height_cm, height_source, dimension_source, missing_reason")
|
|
32
|
+
.order("product_name", { ascending: true })
|
|
33
|
+
.limit(500);
|
|
34
|
+
setRijen(Array.isArray(data) ? data : []);
|
|
35
|
+
setLoading(false);
|
|
36
|
+
}, []);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
void laden();
|
|
39
|
+
}, [laden]);
|
|
40
|
+
const compleet = rijen.filter((r) => !r.missing_reason);
|
|
41
|
+
const onvolledig = rijen.filter((r) => r.missing_reason);
|
|
42
|
+
const uitFloriday = compleet.filter((r) => r.height_source === "floriday").length;
|
|
43
|
+
const uitBelading = compleet.filter((r) => r.height_source === "belading").length;
|
|
44
|
+
const handmatig = compleet.filter((r) => r.height_source === "handmatig").length;
|
|
45
|
+
return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Ruler, { className: "h-4 w-4" }), "Afmetingen per product"] }), _jsx(CardDescription, { children: "De Engine leidt fust en planthoogte zelf af: eerst handmatig, dan Floriday, dan berekend uit de belading. Ontbreekt alles, dan wordt er bewust geen laagindeling gemaakt." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => void laden(), disabled: loading, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Verversen"] })] }) }), _jsx(CardContent, { className: "space-y-4", children: loading ? (_jsx(Skeleton, { className: "h-24 w-full" })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap gap-2 text-xs", children: [_jsxs(Badge, { variant: "default", children: [compleet.length, " met afmetingen"] }), _jsxs(Badge, { variant: "secondary", children: [handmatig, " handmatig"] }), _jsxs(Badge, { variant: "secondary", children: [uitFloriday, " uit Floriday"] }), _jsxs(Badge, { variant: "secondary", children: [uitBelading, " uit de belading"] }), onvolledig.length > 0 ? (_jsxs(Badge, { variant: "destructive", children: [onvolledig.length, " onvolledig"] })) : null] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Product" }), _jsx(TableHead, { children: "Fust" }), _jsx(TableHead, { children: "Fustmaat (mm)" }), _jsx(TableHead, { children: "Planthoogte" }), _jsx(TableHead, { children: "Herkomst hoogte" })] }) }), _jsxs(TableBody, { children: [compleet.map((r) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: r.product_name ?? "—" }), _jsxs(TableCell, { children: [r.fust_name ?? "—", r.fust_source ? (_jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: bron(r.fust_source) })) : null] }), _jsxs(TableCell, { className: "tabular-nums", children: [r.fust_length_mm, " \u00D7 ", r.fust_width_mm, " \u00D7 ", r.fust_height_mm] }), _jsxs(TableCell, { className: "tabular-nums", children: [r.plant_height_cm, " cm"] }), _jsx(TableCell, { children: bron(r.height_source) })] }, r.product_id))), compleet.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 5, className: "text-sm text-muted-foreground", children: "Nog geen enkel product met volledige afmetingen." }) })) : null] })] }), onvolledig.length > 0 ? (_jsxs("div", { className: "space-y-2 rounded-md border border-destructive/40 bg-destructive/5 p-3", children: [_jsx("p", { className: "text-sm font-medium", children: "Deze producten kunnen niet op afmetingen worden ingedeeld" }), _jsx("ul", { className: "space-y-1 text-sm text-muted-foreground", children: onvolledig.map((r) => (_jsxs("li", { children: [_jsx("span", { className: "font-medium text-foreground", children: r.product_name ?? "Onbekend product" }), " — ", r.missing_reason] }, r.product_id))) })] })) : null] })) })] }));
|
|
46
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BufferDebugCard.d.ts","sourceRoot":"","sources":["../../src/components/BufferDebugCard.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGpF,UAAU,KAAK;IACb,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,CACf,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACtC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,KACvB,OAAO,CAAC;QAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAChG,iBAAiB,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpE,gBAAgB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAClH,WAAW,CAAC,EAAE,CACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAClC,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;CACzC;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,GACZ,EAAE,KAAK,+
|
|
1
|
+
{"version":3,"file":"BufferDebugCard.d.ts","sourceRoot":"","sources":["../../src/components/BufferDebugCard.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGpF,UAAU,KAAK;IACb,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,CACf,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACtC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,KACvB,OAAO,CAAC;QAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAChG,iBAAiB,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpE,gBAAgB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAClH,WAAW,CAAC,EAAE,CACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAClC,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;CACzC;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,GACZ,EAAE,KAAK,+BAmNP"}
|
|
@@ -64,6 +64,11 @@ export function BufferDebugCard({ taken, strategyId, simuleerBuffers, herindelen
|
|
|
64
64
|
? ` · ${indelingTotaal.overgeslagen} vergrendeld overgeslagen`
|
|
65
65
|
: "", indelingTotaal.mislukt > 0 ? ` · ${indelingTotaal.mislukt} mislukt` : ""] }), indelingTotaal.fouten.length > 0 && (_jsx("ul", { className: "text-destructive mt-1 list-disc pl-4 text-xs", children: indelingTotaal.fouten.map((f, i) => (_jsx("li", { children: f }, i))) }))] })), orderResultaat && (_jsxs("p", { className: "text-muted-foreground text-sm", children: ["Laatste herberekening: ", Number(orderResultaat.updated ?? 0), " van", " ", Number(orderResultaat.checked ?? 0), " orders verplaatst in", " ", Number(orderResultaat.durationMs ?? 0), " ms."] })), orders.length === 0 && (_jsx("p", { className: "text-muted-foreground text-sm", children: "Er zijn geen openstaande orders om te simuleren." })), resultaat === null && orders.length > 0 && (_jsxs("p", { className: "text-muted-foreground text-sm", children: ["Klik op \u201CSimuleren\u201D om ", orders.length, " openstaande order(s) door de combineerregels te halen."] })), groepen.length > 0 && (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: "Gevonden buffers" }), _jsx("ul", { className: "space-y-2", children: groepen.map((g) => (_jsxs("li", { className: "rounded-lg border border-border p-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Badge, { variant: Number(g.count) > 1 ? "default" : "outline", children: [Number(g.count), " order", Number(g.count) === 1 ? "" : "s"] }), _jsx("span", { className: "text-sm", children: (Array.isArray(g.orderRefs) ? g.orderRefs : []).join(", ") })] }), _jsx("p", { className: "text-muted-foreground mt-1 font-mono text-xs break-all", children: String(g.bufferKey ?? "") })] }, String(g.bufferRef)))) })] })), regels.length > 0 && (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: "Uitleg per order" }), _jsx("ul", { className: "space-y-2", children: regels.map((r) => {
|
|
66
66
|
const trace = Array.isArray(r.trace) ? r.trace : [];
|
|
67
|
-
return (_jsxs("li", { className: "rounded-lg border border-border p-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium", children: String(r.orderRef) }), _jsx(Badge, { variant: r.buffer ? "secondary" : "outline", children: bufferReasonLabel(r.reason) })
|
|
67
|
+
return (_jsxs("li", { className: "rounded-lg border border-border p-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium", children: String(r.orderRef) }), _jsx(Badge, { variant: r.buffer ? "secondary" : "outline", children: bufferReasonLabel(r.reason) }), r.bufferCloseAt ? (_jsxs("span", { className: "text-muted-foreground text-xs", children: ["sluit", " ", new Date(String(r.bufferCloseAt)).toLocaleString("nl-NL", {
|
|
68
|
+
day: "2-digit",
|
|
69
|
+
month: "2-digit",
|
|
70
|
+
hour: "2-digit",
|
|
71
|
+
minute: "2-digit",
|
|
72
|
+
}), r.closeReference === "pick_start" ? " (vóór start picken)" : " (vóór aanmelden)"] })) : null] }), _jsx("ul", { className: "mt-2 space-y-1", children: trace.map((t, i) => (_jsxs("li", { className: "text-muted-foreground text-xs", children: [_jsx("span", { className: t.result ? "text-foreground" : "text-destructive", children: bufferCriterionLabel(String(t.rule)) }), t.value ? _jsxs("span", { children: [" = ", String(t.value)] }) : null, t.message ? _jsxs("span", { children: [" \u2014 ", String(t.message)] }) : null] }, i))) })] }, String(r.orderRef)));
|
|
68
73
|
}) })] }))] })] }));
|
|
69
74
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConsistentieCard.d.ts","sourceRoot":"","sources":["../../src/components/ConsistentieCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConsistentieCard.d.ts","sourceRoot":"","sources":["../../src/components/ConsistentieCard.tsx"],"names":[],"mappings":"AAuCA,wBAAgB,gBAAgB,gCAuF/B"}
|
|
@@ -34,5 +34,5 @@ export function ConsistentieCard() {
|
|
|
34
34
|
{ label: "Aangemeld in pickwachtrij", waarde: check.announced_carts },
|
|
35
35
|
]
|
|
36
36
|
: [];
|
|
37
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Scale, { className: "h-5 w-5 text-primary" }), "Zelfde cijfers in elke module"] }), _jsx(CardDescription, { children: "Karren van vandaag per venster. Alle vensters horen hetzelfde te tellen; de lever agenda telt alleen wat vandaag geleverd wordt." })] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => void laden(), disabled: loading, children: _jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }) })] }), _jsx(CardContent, { className: "space-y-4", children: loading && !check ? (_jsx(Skeleton, { className: "h-24 w-full" })) : !check ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Geen meting beschikbaar." })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Badge, { variant: check.ok ? "default" : "destructive", children: check.ok ? "Alles gelijk" : "Afwijking gevonden" }), check.orphan_tasks > 0 ? (_jsxs(Badge, { variant: "destructive", children: [check.orphan_tasks, " weestaken"] })) : null, _jsxs("span", { className: "text-muted-foreground text-xs", children: ["Peildag ", check.pick_date] })] }), _jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: vensters.map((v) => (_jsxs("div", { className: "rounded-lg border p-3", children: [_jsx("div", { className: "text-muted-foreground text-xs", children: v.label }), _jsx("div", { className: "text-2xl font-semibold tabular-nums", children: v.waarde })] }, v.label))) }), !check.ok ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "E\u00E9n of meer modules tellen anders. Controleer of die module de laatste koppelprompt heeft toegepast; de Engine corrigeert niets zelf." })) : null] })) })] }));
|
|
37
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Scale, { className: "h-5 w-5 text-primary" }), "Zelfde cijfers in elke module"] }), _jsx(CardDescription, { children: "Karren van vandaag per venster. Alle vensters horen hetzelfde te tellen; de lever agenda telt alleen wat vandaag geleverd wordt." })] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => void laden(), disabled: loading, children: _jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }) })] }), _jsx(CardContent, { className: "space-y-4", children: loading && !check ? (_jsx(Skeleton, { className: "h-24 w-full" })) : !check ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Geen meting beschikbaar." })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Badge, { variant: check.ok ? "default" : "destructive", children: check.ok ? "Alles gelijk" : "Afwijking gevonden" }), check.orphan_tasks > 0 ? (_jsxs(Badge, { variant: "destructive", children: [check.orphan_tasks, " weestaken"] })) : null, (check.duplicate_carts ?? 0) > 0 ? (_jsxs(Badge, { variant: "destructive", children: [check.duplicate_carts, " dubbele karren"] })) : null, (check.orphan_carts ?? 0) > 0 ? (_jsxs(Badge, { variant: "destructive", children: [check.orphan_carts, " karren uit een oude buffer"] })) : null, _jsxs("span", { className: "text-muted-foreground text-xs", children: ["Peildag ", check.pick_date] })] }), _jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: vensters.map((v) => (_jsxs("div", { className: "rounded-lg border p-3", children: [_jsx("div", { className: "text-muted-foreground text-xs", children: v.label }), _jsx("div", { className: "text-2xl font-semibold tabular-nums", children: v.waarde })] }, v.label))) }), !check.ok ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "E\u00E9n of meer modules tellen anders. Controleer of die module de laatste koppelprompt heeft toegepast; de Engine corrigeert niets zelf." })) : null] })) })] }));
|
|
38
38
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KarplanStatusCard.d.ts","sourceRoot":"","sources":["../../src/components/KarplanStatusCard.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,iBAAiB,gCAmFhC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/KarplanStatusCard.tsx — is de karplanning klaar?
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Toont per order van vandaag en de komende dagen of er een sluitend karplan
|
|
6
|
+
// ligt, hoeveel karren dat zijn en of de order al is vrijgegeven voor picken.
|
|
7
|
+
// Alles komt uit public.logistics_cart_plan_overview(); niets wordt hier
|
|
8
|
+
// zelf berekend. GEEN <Header /> hier — die levert de shell.
|
|
9
|
+
// ============================================================================
|
|
10
|
+
import { useCallback, useEffect, useState } from "react";
|
|
11
|
+
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, supabase, } from "@flowselections/core";
|
|
12
|
+
import { ClipboardList, RefreshCw } from "lucide-react";
|
|
13
|
+
export function KarplanStatusCard() {
|
|
14
|
+
const [rijen, setRijen] = useState([]);
|
|
15
|
+
const [loading, setLoading] = useState(true);
|
|
16
|
+
const laden = useCallback(async () => {
|
|
17
|
+
setLoading(true);
|
|
18
|
+
const { data } = await supabase.rpc("logistics_cart_plan_overview", {
|
|
19
|
+
p_days: 3,
|
|
20
|
+
});
|
|
21
|
+
setRijen(Array.isArray(data) ? data : []);
|
|
22
|
+
setLoading(false);
|
|
23
|
+
}, []);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
void laden();
|
|
26
|
+
}, [laden]);
|
|
27
|
+
const zonderPlan = rijen.filter((r) => !r.plan_ready).length;
|
|
28
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(ClipboardList, { className: "h-5 w-5 text-primary" }), "Karplanning per order"] }), _jsx(CardDescription, { children: "Orders van vandaag en de komende dagen. Een order hoort pas op het pickscherm te staan als het karplan klaar is \u00E9n de order is vrijgegeven." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => void laden(), disabled: loading, children: [_jsx(RefreshCw, { className: `mr-2 h-4 w-4 ${loading ? "animate-spin" : ""}` }), "Vernieuwen"] })] }), _jsx(CardContent, { className: "space-y-3", children: loading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : rijen.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen orders met een leverdatum in deze periode." })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "text-sm text-muted-foreground", children: zonderPlan === 0
|
|
29
|
+
? "Alle orders in deze periode hebben een sluitend karplan."
|
|
30
|
+
: `${zonderPlan} order(s) hebben nog geen sluitend karplan.` }), _jsx("div", { className: "divide-y rounded-md border", children: rijen.map((r) => (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium", children: r.order_ref }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Leverdatum ", r.delivery_date ?? "onbekend", r.reason ? ` — ${r.reason}` : ""] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Badge, { variant: r.plan_ready ? "secondary" : "destructive", children: r.plan_ready ? `${r.cart_total ?? 0} karren` : "Geen karplan" }), _jsx(Badge, { variant: r.released ? "default" : "outline", children: r.released ? "Vrijgegeven" : "Nog niet vrij" })] })] }, r.order_ref))) })] })) })] }));
|
|
31
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RegiePage.d.ts","sourceRoot":"","sources":["../../src/components/RegiePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RegiePage.d.ts","sourceRoot":"","sources":["../../src/components/RegiePage.tsx"],"names":[],"mappings":"AA4EA,wBAAgB,SAAS,gCAiYxB"}
|
|
@@ -18,6 +18,8 @@ import { CapaciteitMeldingenCard } from "./CapaciteitMeldingenCard";
|
|
|
18
18
|
import { FloridayPushCard } from "./FloridayPushCard";
|
|
19
19
|
import { PrintjobsCard } from "./PrintjobsCard";
|
|
20
20
|
import { ConsistentieCard } from "./ConsistentieCard";
|
|
21
|
+
import { KarplanStatusCard } from "./KarplanStatusCard";
|
|
22
|
+
import { AfmetingenBronnenCard } from "./AfmetingenBronnenCard";
|
|
21
23
|
import { LOGISTICS_MODULES, TASK_LABEL, TASK_STATUS_LABEL, } from "../lib/logisticsTasks";
|
|
22
24
|
function tijd(value) {
|
|
23
25
|
if (!value)
|
|
@@ -74,7 +76,7 @@ export function RegiePage() {
|
|
|
74
76
|
}
|
|
75
77
|
return counts;
|
|
76
78
|
}, [safeTaken]);
|
|
77
|
-
return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs("h1", { className: "flex items-center gap-2 text-2xl font-semibold tracking-tight", children: [_jsx(Workflow, { className: "h-6 w-6 text-primary" }), "Overzicht & meldingen"] }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Wat er vandaag klaarstaat en waar aandacht voor nodig is." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/logistiek-engine", children: "Terug naar overzicht" }) }), _jsxs(Button, { variant: "outline", onClick: () => void laden(), disabled: loading, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Vernieuwen"] })] })] }), _jsx(ConsistentieCard, {}), _jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: Object.keys(LOGISTICS_MODULES).map((key) => (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsx(CardDescription, { children: LOGISTICS_MODULES[key] }), _jsx(CardTitle, { className: "text-2xl", children: perModule[key] ?? 0 })] }), _jsx(CardContent, { className: "text-muted-foreground text-xs", children: "openstaande en geplande taken" })] }, key))) }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Taken per order" }), _jsx(CardDescription, { children: "Elke order krijgt bij binnenkomst meteen de volledige keten aan taken toegewezen." }), _jsxs("div", { className: "pt-2", children: [_jsx(Label, { htmlFor: "regie-filter", className: "sr-only", children: "Zoeken" }), _jsx(Input, { id: "regie-filter", placeholder: "Zoek op ordernummer, taaktype of module\u2026", value: filter, onChange: (e) => setFilter(e.target.value), className: "max-w-sm" })] })] }), _jsx(CardContent, { className: "space-y-6", children: loading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : perOrder.length === 0 ? (_jsxs("p", { className: "text-muted-foreground py-8 text-center text-sm", children: ["Nog geen taken. Zodra een module een melding wegschrijft in", " ", _jsx("code", { className: "bg-muted rounded px-1", children: "logistics_events" }), " maakt de database de keten meteen aan."] })) : (perOrder.map(([orderRef, orderTaken]) => {
|
|
79
|
+
return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs("h1", { className: "flex items-center gap-2 text-2xl font-semibold tracking-tight", children: [_jsx(Workflow, { className: "h-6 w-6 text-primary" }), "Overzicht & meldingen"] }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Wat er vandaag klaarstaat en waar aandacht voor nodig is." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/logistiek-engine", children: "Terug naar overzicht" }) }), _jsxs(Button, { variant: "outline", onClick: () => void laden(), disabled: loading, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Vernieuwen"] })] })] }), _jsx(ConsistentieCard, {}), _jsx(KarplanStatusCard, {}), _jsx(AfmetingenBronnenCard, {}), _jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: Object.keys(LOGISTICS_MODULES).map((key) => (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsx(CardDescription, { children: LOGISTICS_MODULES[key] }), _jsx(CardTitle, { className: "text-2xl", children: perModule[key] ?? 0 })] }), _jsx(CardContent, { className: "text-muted-foreground text-xs", children: "openstaande en geplande taken" })] }, key))) }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Taken per order" }), _jsx(CardDescription, { children: "Elke order krijgt bij binnenkomst meteen de volledige keten aan taken toegewezen." }), _jsxs("div", { className: "pt-2", children: [_jsx(Label, { htmlFor: "regie-filter", className: "sr-only", children: "Zoeken" }), _jsx(Input, { id: "regie-filter", placeholder: "Zoek op ordernummer, taaktype of module\u2026", value: filter, onChange: (e) => setFilter(e.target.value), className: "max-w-sm" })] })] }), _jsx(CardContent, { className: "space-y-6", children: loading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : perOrder.length === 0 ? (_jsxs("p", { className: "text-muted-foreground py-8 text-center text-sm", children: ["Nog geen taken. Zodra een module een melding wegschrijft in", " ", _jsx("code", { className: "bg-muted rounded px-1", children: "logistics_events" }), " maakt de database de keten meteen aan."] })) : (perOrder.map(([orderRef, orderTaken]) => {
|
|
78
80
|
const spoed = orderTaken.some((t) => (t.priority ?? 0) > 0);
|
|
79
81
|
const actief = orderTaken.some((t) => t.status !== "cancelled" && t.status !== "done" && t.status !== "superseded");
|
|
80
82
|
return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("h2", { className: "flex items-center gap-2 font-medium", children: ["Order ", orderRef, _jsxs("span", { className: "text-muted-foreground text-xs font-normal", children: [orderTaken.length, " taken"] }), spoed && (_jsx(Badge, { variant: "destructive", className: "text-[10px]", children: "spoed" }))] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => void zetPrioriteit(orderRef, spoed ? 0 : 100), children: [_jsx(ArrowUpCircle, { className: "mr-1 h-4 w-4" }), spoed ? "Normaal" : "Spoed"] }), actief && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => void annuleerOrder(orderRef), children: [_jsx(Ban, { className: "mr-1 h-4 w-4" }), "Annuleren"] })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void verwijderOrder(orderRef), children: _jsx(Trash2, { className: "h-4 w-4" }) })] })] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-12", children: "#" }), _jsx(TableHead, { children: "Taak" }), _jsx(TableHead, { children: "Module" }), _jsx(TableHead, { children: "Start" }), _jsx(TableHead, { children: "Gereed" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { className: "text-right", children: "Actie" })] }) }), _jsx(TableBody, { children: orderTaken.map((t) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "text-muted-foreground", children: t.sequence + 1 }), _jsxs(TableCell, { className: "font-medium", children: [TASK_LABEL[t.task_type] ?? t.task_type, t.shadow && (_jsx(Badge, { variant: "outline", className: "ml-2 text-[10px]", children: "schaduw" }))] }), _jsx(TableCell, { className: "text-sm", children: LOGISTICS_MODULES[t.owner_module] ?? t.owner_module }), _jsxs(TableCell, { className: "text-sm", children: [tijd(t.planned_start), t.payload?.["pickWindowShifted"] === true && (_jsx(Badge, { variant: "outline", className: "ml-2 text-[10px]", title: "Het berekende moment lag in het verleden; deze taak is naar nu verschoven.", children: "te laat aangemeld" }))] }), _jsx(TableCell, { className: "text-sm", children: tijd(t.planned_end) }), _jsxs(TableCell, { children: [_jsx(Badge, { variant: statusVariant(t.status), children: TASK_STATUS_LABEL[t.status] ?? t.status }), t.claimed_by && (t.status === "claimed" || t.status === "in_progress") && (_jsxs("span", { className: "text-muted-foreground ml-2 text-xs", children: ["door ", t.claimed_by] })), t.error && _jsx("span", { className: "text-destructive ml-2 text-xs", children: t.error })] }), _jsxs(TableCell, { className: "space-x-1 text-right", children: [t.status === "planned" && (_jsx(Button, { variant: "outline", size: "sm", onClick: () => void claimTaak(t.id), children: "Claimen" })), (t.status === "claimed" || t.status === "in_progress") && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => void rondTaakAf(t.id), children: "Afronden" }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void meldTaakMislukt(t.id, "Handmatig gemeld vanuit regieoverzicht"), children: "Mislukt" })] }))] })] }, t.id))) })] })] }, orderRef));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuleEnginePage.d.ts","sourceRoot":"","sources":["../../src/components/RuleEnginePage.tsx"],"names":[],"mappings":"AAmEA,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAQD,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EAAE,cAAqB,EACjC,YAAY,EAAE,gBAAuB,GACtC,GAAE,mBAAwB,+
|
|
1
|
+
{"version":3,"file":"RuleEnginePage.d.ts","sourceRoot":"","sources":["../../src/components/RuleEnginePage.tsx"],"names":[],"mappings":"AAmEA,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAQD,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EAAE,cAAqB,EACjC,YAAY,EAAE,gBAAuB,GACtC,GAAE,mBAAwB,+BA2b1B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
// ============================================================================
|
|
3
3
|
// src/components/RuleEnginePage.tsx — logistieke werkwijze instellen
|
|
4
4
|
// ============================================================================
|
|
@@ -42,6 +42,7 @@ export function RuleEnginePage({ strategyId: strategyIdProp = null, strategyName
|
|
|
42
42
|
const strategyName = strategyNameProp ?? urlSearch.naam ?? null;
|
|
43
43
|
const { versions, activeConfig, loading, saving, error, createConfig, patchSettings, saveConfig, activateConfig, restoreVersion, deleteConfig, } = useRuleEngine({ strategyId, strategyName });
|
|
44
44
|
const [stepIndex, setStepIndex] = useState(0);
|
|
45
|
+
const [sideOpen, setSideOpen] = useState(false);
|
|
45
46
|
const [createOpen, setCreateOpen] = useState(false);
|
|
46
47
|
const [newName, setNewName] = useState("");
|
|
47
48
|
const [newDescription, setNewDescription] = useState("");
|
|
@@ -98,7 +99,7 @@ export function RuleEnginePage({ strategyId: strategyIdProp = null, strategyName
|
|
|
98
99
|
toast.success("Opgeslagen — de herberekening loopt op de achtergrond");
|
|
99
100
|
}
|
|
100
101
|
catch (e) {
|
|
101
|
-
toast.error("Opnieuw berekenen is niet gelukt. Probeer het nog een keer.");
|
|
102
|
+
toast.error(e?.message ?? "Opnieuw berekenen is niet gelukt. Probeer het nog een keer.");
|
|
102
103
|
}
|
|
103
104
|
finally {
|
|
104
105
|
setRecalculating(false);
|
|
@@ -120,7 +121,9 @@ export function RuleEnginePage({ strategyId: strategyIdProp = null, strategyName
|
|
|
120
121
|
? "Bezig…"
|
|
121
122
|
: "Opslaan & opnieuw berekenen"] })] })] }), error && (_jsx("p", { className: "rounded-md border border-destructive/50 bg-destructive/5 px-3 py-2 text-sm text-destructive", children: "De gegevens konden niet worden geladen. Probeer het opnieuw." })), showJobLine && (_jsxs("div", { className: `rounded-md border px-3 py-2 text-sm ${job?.status === "error" ? "border-destructive/50 bg-destructive/5 text-destructive" : "border-border"}`, children: [_jsx("span", { children: running
|
|
122
123
|
? `${phaseLabel(job?.phase)} — ${job?.processed ?? 0} verwerkt`
|
|
123
|
-
: "De laatste berekening is niet volledig gelukt." }), jobProblems.length > 0 && (_jsx("ul", { className: "mt-1 list-disc pl-5 text-xs", children: jobProblems.map((p, i) => (_jsx("li", { children: p }, i))) }))] })), !loading && activeConfig && !activeConfig.is_active && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-md border border-amber-500/60 bg-amber-500/5 px-3 py-2 text-sm", children: [_jsxs("span", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), "Deze werkwijze staat nog op ", _jsx("strong", { children: "concept" }), " en telt nog niet mee bij het inplannen."] }), _jsxs(Button, { size: "sm", onClick: () => activateConfig(activeConfig.id), children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), "Nu activeren"] })] })), loading || (strategyId && !activeConfig && !error) ? (_jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-64 w-full" })] })) : !activeConfig ? (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Nog geen werkwijze" }), _jsx(CardDescription, { children: "Maak een werkwijze aan om vast te leggen hoe jouw orders verwerkt worden." })] }), _jsx(CardContent, { children: _jsxs(Button, { onClick: () => setCreateOpen(true), children: [_jsx(Plus, { className: "h-4 w-4" }), "Werkwijze aanmaken"] }) })] })) : (_jsxs("div", { className:
|
|
124
|
+
: "De laatste berekening is niet volledig gelukt." }), jobProblems.length > 0 && (_jsx("ul", { className: "mt-1 list-disc pl-5 text-xs", children: jobProblems.map((p, i) => (_jsx("li", { children: p }, i))) }))] })), !loading && activeConfig && !activeConfig.is_active && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-md border border-amber-500/60 bg-amber-500/5 px-3 py-2 text-sm", children: [_jsxs("span", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), "Deze werkwijze staat nog op ", _jsx("strong", { children: "concept" }), " en telt nog niet mee bij het inplannen."] }), _jsxs(Button, { size: "sm", onClick: () => activateConfig(activeConfig.id), children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), "Nu activeren"] })] })), loading || (strategyId && !activeConfig && !error) ? (_jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-64 w-full" })] })) : !activeConfig ? (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Nog geen werkwijze" }), _jsx(CardDescription, { children: "Maak een werkwijze aan om vast te leggen hoe jouw orders verwerkt worden." })] }), _jsx(CardContent, { children: _jsxs(Button, { onClick: () => setCreateOpen(true), children: [_jsx(Plus, { className: "h-4 w-4" }), "Werkwijze aanmaken"] }) })] })) : (_jsxs("div", { className: `grid gap-6 lg:h-[calc(100vh-13rem)] ${sideOpen
|
|
125
|
+
? "lg:grid-cols-[220px_minmax(0,1fr)_320px]"
|
|
126
|
+
: "lg:grid-cols-[220px_minmax(0,1fr)_44px]"}`, children: [_jsx("nav", { className: "space-y-1 lg:overflow-y-auto lg:pr-1", children: WIZARD_STEPS.map((item, index) => (_jsxs("button", { type: "button", onClick: () => setStepIndex(index), className: `flex w-full items-center gap-3 rounded-lg border p-2.5 text-left transition-colors ${index === stepIndex
|
|
124
127
|
? "border-primary bg-primary/5"
|
|
125
128
|
: "border-transparent hover:bg-muted"}`, children: [_jsx("span", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-muted text-xs font-semibold", children: index + 1 }), _jsx("span", { className: "text-sm font-medium", children: item.label })] }, item.id))) }), _jsxs("div", { className: "space-y-4 lg:min-h-0 lg:overflow-y-auto lg:pr-2", children: [_jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: step.label }), _jsx(CardDescription, { children: step.description })] }), _jsx(Badge, { variant: activeConfig.is_active ? "default" : "secondary", children: activeConfig.is_active ? "Actief" : "Concept" })] }) }), _jsx(CardContent, { className: "space-y-3", children: step.groups.map((group, groupIndex) => {
|
|
126
129
|
const visibleFields = group.fields.filter((field) => fieldVisible(field, stepValues, settings));
|
|
@@ -130,5 +133,5 @@ export function RuleEnginePage({ strategyId: strategyIdProp = null, strategyName
|
|
|
130
133
|
const advancedFields = visibleFields.filter((f) => isAdvancedField(f));
|
|
131
134
|
const isLastGroup = groupIndex === step.groups.length - 1;
|
|
132
135
|
return (_jsxs(CollapsibleGroup, { title: group.label, help: group.description, summary: groupSummary(group, stepValues), defaultOpen: groupIndex === 0, children: [basicFields.length > 0 && (_jsx("div", { className: "grid gap-4 md:grid-cols-2", children: basicFields.map((field) => (_jsx("div", { className: fieldClass(field), children: _jsx(RuleFieldInput, { field: field, value: stepValues[field.key], stepValues: stepValues, onChange: (value) => setFieldValue(field.key, value) }) }, field.key))) })), (advancedFields.length > 0 || (step.showConditions && isLastGroup)) && (_jsxs("details", { className: "rounded-lg border border-dashed border-border", children: [_jsx("summary", { className: "cursor-pointer px-3 py-2 text-sm font-medium text-muted-foreground", children: "Geavanceerd" }), _jsxs("div", { className: "space-y-4 border-t border-border px-3 py-4", children: [advancedFields.length > 0 && (_jsx("div", { className: "grid gap-4 md:grid-cols-2", children: advancedFields.map((field) => (_jsx("div", { className: fieldClass(field), children: _jsx(RuleFieldInput, { field: field, value: stepValues[field.key], stepValues: stepValues, onChange: (value) => setFieldValue(field.key, value) }) }, field.key))) })), step.showConditions && isLastGroup && (_jsx(ConditionsEditor, { conditions: stepConditions, onChange: setConditions }))] })] }))] }, group.id));
|
|
133
|
-
}) })] }), _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", onClick: () => setStepIndex((i) => Math.max(0, i - 1)), disabled: stepIndex === 0, children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), "Vorige"] }), _jsxs(Button, { variant: "outline", onClick: () => setStepIndex((i) => Math.min(WIZARD_STEPS.length - 1, i + 1)), disabled: stepIndex === WIZARD_STEPS.length - 1, children: ["Volgende", _jsx(ChevronRight, { className: "h-4 w-4" })] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Button, { variant: "outline", disabled: saving, onClick: () => saveConfig(activeConfig), children: [_jsx(Save, { className: "h-4 w-4" }), "Opslaan"] }), _jsxs(Button, { disabled: saving || activeConfig.is_active, onClick: () => activateConfig(activeConfig.id), children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), activeConfig.is_active ? "Actief" : "Activeren"] }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Meer acties", children: _jsx(MoreVertical, { className: "h-4 w-4" }) }) }), _jsx(DropdownMenuContent, { align: "end", children: _jsxs(DropdownMenuItem, { onClick: () => deleteConfig(activeConfig.id), children: [_jsx(Trash2, { className: "h-4 w-4" }), "Werkwijze verwijderen"] }) })] })] })] })] }), _jsx("div", { className: "lg:min-h-0 lg:overflow-y-auto lg:pr-1", children: _jsxs(Tabs, { defaultValue: "impact", children: [_jsxs(TabsList, { className: "w-full", children: [_jsx(TabsTrigger, { className: "flex-1", value: "impact", children: "Aandachtspunten" }), _jsx(TabsTrigger, { className: "flex-1", value: "versies", children: "Eerdere versies" })] }), _jsx(TabsContent, { value: "impact", className: "mt-3", children: _jsx(ImpactPanel, { settings: settings }) }), _jsx(TabsContent, { value: "versies", className: "mt-3", children: _jsx(VersionsPanel, { versions: versions, currentSettings: settings, onRestore: restoreVersion }) })] }) })] })), _jsx(Dialog, { open: createOpen, onOpenChange: setCreateOpen, children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Nieuwe werkwijze" }), _jsx(DialogDescription, { children: "Elke werkwijze beschrijft hoe orders bij jou verwerkt worden." })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Naam" }), _jsx(Input, { value: newName, onChange: (e) => setNewName(e.target.value), placeholder: "Bijv. Standaard werkwijze" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Omschrijving" }), _jsx(Textarea, { value: newDescription, onChange: (e) => setNewDescription(e.target.value), placeholder: "Waarvoor gebruik je deze werkwijze?" })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => setCreateOpen(false), children: "Annuleren" }), _jsx(Button, { onClick: handleCreate, disabled: !newName.trim(), children: "Aanmaken" })] })] }) })] }));
|
|
136
|
+
}) })] }), _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", onClick: () => setStepIndex((i) => Math.max(0, i - 1)), disabled: stepIndex === 0, children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), "Vorige"] }), _jsxs(Button, { variant: "outline", onClick: () => setStepIndex((i) => Math.min(WIZARD_STEPS.length - 1, i + 1)), disabled: stepIndex === WIZARD_STEPS.length - 1, children: ["Volgende", _jsx(ChevronRight, { className: "h-4 w-4" })] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Button, { variant: "outline", disabled: saving, onClick: () => saveConfig(activeConfig), children: [_jsx(Save, { className: "h-4 w-4" }), "Opslaan"] }), _jsxs(Button, { disabled: saving || activeConfig.is_active, onClick: () => activateConfig(activeConfig.id), children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), activeConfig.is_active ? "Actief" : "Activeren"] }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Meer acties", children: _jsx(MoreVertical, { className: "h-4 w-4" }) }) }), _jsx(DropdownMenuContent, { align: "end", children: _jsxs(DropdownMenuItem, { onClick: () => deleteConfig(activeConfig.id), children: [_jsx(Trash2, { className: "h-4 w-4" }), "Werkwijze verwijderen"] }) })] })] })] })] }), _jsx("div", { className: "lg:min-h-0 lg:overflow-y-auto lg:pr-1", children: sideOpen ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "mb-2 flex justify-end", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Paneel inklappen", onClick: () => setSideOpen(false), children: _jsx(ChevronRight, { className: "h-4 w-4" }) }) }), _jsxs(Tabs, { defaultValue: "impact", children: [_jsxs(TabsList, { className: "w-full", children: [_jsx(TabsTrigger, { className: "flex-1", value: "impact", children: "Aandachtspunten" }), _jsx(TabsTrigger, { className: "flex-1", value: "versies", children: "Eerdere versies" })] }), _jsx(TabsContent, { value: "impact", className: "mt-3", children: _jsx(ImpactPanel, { settings: settings }) }), _jsx(TabsContent, { value: "versies", className: "mt-3", children: _jsx(VersionsPanel, { versions: versions, currentSettings: settings, onRestore: restoreVersion }) })] })] })) : (_jsx(Button, { variant: "outline", size: "icon", "aria-label": "Paneel uitklappen", onClick: () => setSideOpen(true), children: _jsx(ChevronLeft, { className: "h-4 w-4" }) })) })] })), _jsx(Dialog, { open: createOpen, onOpenChange: setCreateOpen, children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Nieuwe werkwijze" }), _jsx(DialogDescription, { children: "Elke werkwijze beschrijft hoe orders bij jou verwerkt worden." })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Naam" }), _jsx(Input, { value: newName, onChange: (e) => setNewName(e.target.value), placeholder: "Bijv. Standaard werkwijze" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Omschrijving" }), _jsx(Textarea, { value: newDescription, onChange: (e) => setNewDescription(e.target.value), placeholder: "Waarvoor gebruik je deze werkwijze?" })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => setCreateOpen(false), children: "Annuleren" }), _jsx(Button, { onClick: handleCreate, disabled: !newName.trim(), children: "Aanmaken" })] })] }) })] }));
|
|
134
137
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloridayConnectionBanner.d.ts","sourceRoot":"","sources":["../../../src/components/rule-engine/FloridayConnectionBanner.tsx"],"names":[],"mappings":"AAYA,wBAAgB,wBAAwB,gCAwDvC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/rule-engine/FloridayConnectionBanner.tsx
|
|
4
|
+
// Toont welke Floriday-koppeling de documenten levert. De gegevens komen
|
|
5
|
+
// volledig uit de authenticatie-module; deze module kiest niets zelf.
|
|
6
|
+
// ============================================================================
|
|
7
|
+
import { useQuery } from "@tanstack/react-query";
|
|
8
|
+
import { Badge, Skeleton } from "@flowselections/core";
|
|
9
|
+
import { AlertTriangle, Link2 } from "lucide-react";
|
|
10
|
+
import { supabase } from "../../integrations/supabase/client";
|
|
11
|
+
import { getFloridayConnection } from "../../lib/floridayDocuments.functions";
|
|
12
|
+
export function FloridayConnectionBanner() {
|
|
13
|
+
const { data, isLoading } = useQuery({
|
|
14
|
+
queryKey: ["floriday-connection"],
|
|
15
|
+
queryFn: async () => {
|
|
16
|
+
try {
|
|
17
|
+
// Zonder sessie geeft de server-function een 401-Response terug; die
|
|
18
|
+
// mag nooit als throw naar de router lekken (blanco scherm).
|
|
19
|
+
const { data: sessionData } = await supabase.auth.getSession();
|
|
20
|
+
if (!sessionData.session) {
|
|
21
|
+
return { ok: false, error: "Geen actieve sessie." };
|
|
22
|
+
}
|
|
23
|
+
return await getFloridayConnection();
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
// Geen sessie of gateway-fout: banner toont de foutstaat, geen crash.
|
|
27
|
+
const message = e instanceof Response ? `HTTP ${e.status}` : String(e?.message ?? e);
|
|
28
|
+
return { ok: false, error: message };
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
retry: false,
|
|
32
|
+
staleTime: 60000,
|
|
33
|
+
});
|
|
34
|
+
if (isLoading)
|
|
35
|
+
return _jsx(Skeleton, { className: "h-14 w-full rounded-lg" });
|
|
36
|
+
if (!data || data.ok !== true) {
|
|
37
|
+
return (_jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-destructive/40 bg-destructive/5 p-3", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 text-destructive" }), _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-medium text-destructive", children: "Geen actieve Floriday-koppeling" }), _jsx("p", { className: "text-muted-foreground", children: "Documenten kunnen niet worden opgehaald zolang de Floriday-authenticatiemodule geen actieve koppeling heeft." })] })] }));
|
|
38
|
+
}
|
|
39
|
+
const c = data.connection;
|
|
40
|
+
return (_jsxs("div", { className: "flex flex-wrap items-center gap-3 rounded-lg border border-border bg-muted/40 p-3", children: [_jsx(Link2, { className: "h-4 w-4 text-muted-foreground" }), _jsxs("div", { className: "text-sm", children: [_jsx("span", { className: "font-medium", children: c?.label ?? c?.organization_name ?? "Floriday" }), c?.gln_code && _jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 GLN ", c.gln_code] })] }), _jsx(Badge, { variant: data.environment === "live" ? "default" : "secondary", children: data.environment === "live" ? "Live" : "Staging" }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Documenten worden opgehaald via de Floriday-authenticatiemodule." })] }));
|
|
41
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuleFieldInput.d.ts","sourceRoot":"","sources":["../../../src/components/rule-engine/RuleFieldInput.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"RuleFieldInput.d.ts","sourceRoot":"","sources":["../../../src/components/rule-engine/RuleFieldInput.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAQ3E,UAAU,KAAK;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,sCA+V3E"}
|
|
@@ -9,9 +9,11 @@ import { Input, Label, Switch, Select, SelectContent, SelectItem, SelectTrigger,
|
|
|
9
9
|
import { fieldHelp } from "../../lib/ruleEngineWizard";
|
|
10
10
|
import { FieldHelp, FieldLabel } from "./FieldHelp";
|
|
11
11
|
import { usePickstations } from "../../hooks/usePickstations";
|
|
12
|
+
import { useScannersPrinters } from "../../hooks/useScannersPrinters";
|
|
12
13
|
import { useDocumentLayouts } from "../../hooks/useDocumentLayouts";
|
|
13
14
|
export function RuleFieldInput({ field, value, onChange, stepValues }) {
|
|
14
15
|
const { stations, types, loading } = usePickstations();
|
|
16
|
+
const { scanners, printers, loading: devicesLoading } = useScannersPrinters();
|
|
15
17
|
const { layouts: matching, allLayouts, autoLayout, loading: layoutsLoading, } = useDocumentLayouts(field.layoutTypes);
|
|
16
18
|
const help = fieldHelp(field);
|
|
17
19
|
if (field.type === "guidance") {
|
|
@@ -35,6 +37,13 @@ export function RuleFieldInput({ field, value, onChange, stepValues }) {
|
|
|
35
37
|
return (_jsxs("div", { className: "space-y-2", children: [_jsx(FieldLabel, { label: field.label, help: help ??
|
|
36
38
|
"Het pickstation waar dit document hoort. De pickschermen koppelen dat station aan een printplek uit de Layout maker; die printplek bepaalt de printer." }), _jsxs(Select, { value: String(value ?? ""), onValueChange: (v) => onChange(v === "__none__" ? "" : v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: loading ? "Laden…" : "Kies een pickstation" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "__none__", children: "Niet instellen" }), options.map((option) => (_jsx(SelectItem, { value: option.id, children: option.name }, option.id)))] })] }), !loading && options.length === 0 && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Er zijn nog geen pickstations ingericht." }))] }));
|
|
37
39
|
}
|
|
40
|
+
if (field.type === "scanner" || field.type === "printer") {
|
|
41
|
+
const isScanner = field.type === "scanner";
|
|
42
|
+
const options = isScanner ? scanners : printers;
|
|
43
|
+
return (_jsxs("div", { className: "space-y-2", children: [_jsx(FieldLabel, { label: field.label, help: help }), _jsxs(Select, { value: String(value ?? ""), onValueChange: (v) => onChange(v === "__none__" ? "" : v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: devicesLoading ? "Laden…" : isScanner ? "Kies een scanner" : "Kies een printer" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "__none__", children: "Niet instellen" }), options.map((option) => (_jsxs(SelectItem, { value: option.id, children: [option.name, option.hint ? ` · ${option.hint}` : ""] }, option.id)))] })] }), !devicesLoading && options.length === 0 && (_jsx("p", { className: "text-xs text-destructive", children: isScanner
|
|
44
|
+
? "Er staan nog geen actieve scanners in het systeem. Zonder scanner kan er niet gecontroleerd worden."
|
|
45
|
+
: "Er staan nog geen actieve printers in het systeem. Zonder printer blijft de afleverbrief wachten." }))] }));
|
|
46
|
+
}
|
|
38
47
|
if (field.type === "days") {
|
|
39
48
|
const selected = Array.isArray(value) ? value : [];
|
|
40
49
|
const days = field.options ?? [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRecalcJob.d.ts","sourceRoot":"","sources":["../../src/hooks/useRecalcJob.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAQD,wBAAgB,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,UAE/C;
|
|
1
|
+
{"version":3,"file":"useRecalcJob.d.ts","sourceRoot":"","sources":["../../src/hooks/useRecalcJob.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAQD,wBAAgB,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,UAE/C;AAwBD,wBAAgB,YAAY;;;qCA6DL,MAAM,GAAG,IAAI;;EAenC"}
|
|
@@ -13,6 +13,27 @@ const PHASE_LABEL = {
|
|
|
13
13
|
export function phaseLabel(phase) {
|
|
14
14
|
return (phase && PHASE_LABEL[phase]) || "Bezig";
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Serverfuncties gooien bij een fout een Response. Die belandt anders als
|
|
18
|
+
* "[object Response]" in de foutafhandeling (leeg scherm). Hier maken we er
|
|
19
|
+
* altijd een leesbare Error van.
|
|
20
|
+
*/
|
|
21
|
+
async function toReadableError(e) {
|
|
22
|
+
if (typeof Response !== "undefined" && e instanceof Response) {
|
|
23
|
+
let body = "";
|
|
24
|
+
try {
|
|
25
|
+
body = (await e.clone().text()).slice(0, 300);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
/* body niet leesbaar */
|
|
29
|
+
}
|
|
30
|
+
if (e.status === 401) {
|
|
31
|
+
return new Error("Je sessie is verlopen. Log opnieuw in en probeer het nog een keer.");
|
|
32
|
+
}
|
|
33
|
+
return new Error(body || `Serverfout (${e.status})`);
|
|
34
|
+
}
|
|
35
|
+
return e instanceof Error ? e : new Error(String(e?.message ?? e));
|
|
36
|
+
}
|
|
16
37
|
export function useRecalcJob() {
|
|
17
38
|
const [job, setJob] = useState(null);
|
|
18
39
|
const [starting, setStarting] = useState(false);
|
|
@@ -56,7 +77,8 @@ export function useRecalcJob() {
|
|
|
56
77
|
break;
|
|
57
78
|
}
|
|
58
79
|
}
|
|
59
|
-
catch {
|
|
80
|
+
catch (e) {
|
|
81
|
+
console.warn("[logistiek-engine] herberekening doorzetten:", (await toReadableError(e)).message);
|
|
60
82
|
/* de cron-taak pakt het verder op */
|
|
61
83
|
}
|
|
62
84
|
finally {
|
|
@@ -75,6 +97,9 @@ export function useRecalcJob() {
|
|
|
75
97
|
await start({ data: { strategyId } });
|
|
76
98
|
await load();
|
|
77
99
|
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
throw await toReadableError(e);
|
|
102
|
+
}
|
|
78
103
|
finally {
|
|
79
104
|
setStarting(false);
|
|
80
105
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface DeviceOption {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
hint?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function useScannersPrinters(): {
|
|
7
|
+
scanners: DeviceOption[];
|
|
8
|
+
printers: DeviceOption[];
|
|
9
|
+
loading: boolean;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=useScannersPrinters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScannersPrinters.d.ts","sourceRoot":"","sources":["../../src/hooks/useScannersPrinters.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAsCD,wBAAgB,mBAAmB;;;;EAuBlC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// src/hooks/useScannersPrinters.ts — scanners en printers uit de database,
|
|
3
|
+
// voor de controle-instellingen in de Rule Engine.
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Alleen actieve records. Geen vaste namen of id's in code: staat er niets in
|
|
6
|
+
// de database, dan blijft de keuzelijst leeg en meldt het scherm dat.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
import { useEffect, useState } from "react";
|
|
9
|
+
import { supabase } from "@flowselections/core";
|
|
10
|
+
const db = () => supabase;
|
|
11
|
+
let cache = null;
|
|
12
|
+
let inflight = null;
|
|
13
|
+
async function load() {
|
|
14
|
+
if (cache)
|
|
15
|
+
return cache;
|
|
16
|
+
if (!inflight) {
|
|
17
|
+
inflight = (async () => {
|
|
18
|
+
const [scanners, printers] = await Promise.all([
|
|
19
|
+
db().from("scan_scanners").select("id, naam, omschrijving, werkplek, actief").order("naam"),
|
|
20
|
+
db().from("printers").select("id, naam, locatie, actief, online").order("naam"),
|
|
21
|
+
]);
|
|
22
|
+
const mapScanner = (rows) => (Array.isArray(rows) ? rows : [])
|
|
23
|
+
.filter((r) => r && r.actief !== false)
|
|
24
|
+
.map((r) => ({
|
|
25
|
+
id: String(r.id),
|
|
26
|
+
name: String(r.naam ?? r.id),
|
|
27
|
+
hint: r.werkplek ? String(r.werkplek) : undefined,
|
|
28
|
+
}));
|
|
29
|
+
const mapPrinter = (rows) => (Array.isArray(rows) ? rows : [])
|
|
30
|
+
.filter((r) => r && r.actief !== false)
|
|
31
|
+
.map((r) => ({
|
|
32
|
+
id: String(r.id),
|
|
33
|
+
name: String(r.naam ?? r.id),
|
|
34
|
+
hint: r.locatie ? String(r.locatie) : undefined,
|
|
35
|
+
}));
|
|
36
|
+
cache = { scanners: mapScanner(scanners?.data), printers: mapPrinter(printers?.data) };
|
|
37
|
+
return cache;
|
|
38
|
+
})();
|
|
39
|
+
}
|
|
40
|
+
return inflight;
|
|
41
|
+
}
|
|
42
|
+
export function useScannersPrinters() {
|
|
43
|
+
const [scanners, setScanners] = useState(cache?.scanners ?? []);
|
|
44
|
+
const [printers, setPrinters] = useState(cache?.printers ?? []);
|
|
45
|
+
const [loading, setLoading] = useState(!cache);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
let active = true;
|
|
48
|
+
load()
|
|
49
|
+
.then((result) => {
|
|
50
|
+
if (!active)
|
|
51
|
+
return;
|
|
52
|
+
setScanners(result.scanners);
|
|
53
|
+
setPrinters(result.printers);
|
|
54
|
+
})
|
|
55
|
+
.catch(() => undefined)
|
|
56
|
+
.finally(() => {
|
|
57
|
+
if (active)
|
|
58
|
+
setLoading(false);
|
|
59
|
+
});
|
|
60
|
+
return () => {
|
|
61
|
+
active = false;
|
|
62
|
+
};
|
|
63
|
+
}, []);
|
|
64
|
+
return { scanners, printers, loading };
|
|
65
|
+
}
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export * from './components/VoorraadMeldingenCard';
|
|
|
10
10
|
export { FloridayPushCard } from './components/FloridayPushCard';
|
|
11
11
|
export { PrintjobsCard } from './components/PrintjobsCard';
|
|
12
12
|
export { ConsistentieCard } from './components/ConsistentieCard';
|
|
13
|
+
export { KarplanStatusCard } from './components/KarplanStatusCard';
|
|
14
|
+
export { AfmetingenBronnenCard } from './components/AfmetingenBronnenCard';
|
|
13
15
|
export * from './hooks/usePrintjobs';
|
|
14
16
|
export * from './components/VertragingMeldingenCard';
|
|
15
17
|
export * from './components/CapaciteitMeldingenCard';
|
package/dist-lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,cAAc,sBAAsB,CAAC;AAErC,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAGrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AAChG,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qCAAqC,CAAC;AAMpD,eAAO,MAAM,qBAAqB,EAAE,UAcnC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,cAAc,sBAAsB,CAAC;AAErC,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAGrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AAChG,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qCAAqC,CAAC;AAMpD,eAAO,MAAM,qBAAqB,EAAE,UAcnC,CAAC"}
|
package/dist-lib/index.js
CHANGED
|
@@ -13,6 +13,8 @@ export * from './components/VoorraadMeldingenCard';
|
|
|
13
13
|
export { FloridayPushCard } from './components/FloridayPushCard';
|
|
14
14
|
export { PrintjobsCard } from './components/PrintjobsCard';
|
|
15
15
|
export { ConsistentieCard } from './components/ConsistentieCard';
|
|
16
|
+
export { KarplanStatusCard } from './components/KarplanStatusCard';
|
|
17
|
+
export { AfmetingenBronnenCard } from './components/AfmetingenBronnenCard';
|
|
16
18
|
export * from './hooks/usePrintjobs';
|
|
17
19
|
export * from './components/VertragingMeldingenCard';
|
|
18
20
|
export * from './components/CapaciteitMeldingenCard';
|