@burdenoff/microfe-movethewheels 2026.725.1 → 2026.728.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MoveTheWheelsRoutes.js +7 -3
- package/dist/components/ProofOfDeliveryCard.js +155 -0
- package/dist/components/SignaturePad.js +82 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useEntityDocuments.js +4 -4
- package/dist/hooks/useEpod.js +208 -0
- package/dist/index.js +22 -21
- package/dist/movethewheels/components/ProofOfDeliveryCard.d.ts +5 -0
- package/dist/movethewheels/components/SignaturePad.d.ts +11 -0
- package/dist/movethewheels/hooks/index.d.ts +1 -0
- package/dist/movethewheels/hooks/useEntityDocuments.d.ts +17 -1
- package/dist/movethewheels/hooks/useEpod.d.ts +59 -0
- package/dist/movethewheels/pages/DeliveryCapturePage.d.ts +1 -0
- package/dist/movethewheels/types/index.d.ts +18 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/loader-circle.js +8 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/pen-line.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/type.js +24 -0
- package/dist/pages/DeliveryCapturePage.js +245 -0
- package/dist/pages/OrderDetailsPage.js +14 -12
- package/dist/pages/TrackingPage.js +156 -154
- package/dist/utils/formatters.js +13 -2
- package/package.json +4 -3
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +4 -0
- package/src/movethewheels/components/ProofOfDeliveryCard.tsx +149 -0
- package/src/movethewheels/components/SignaturePad.tsx +157 -0
- package/src/movethewheels/hooks/index.ts +12 -0
- package/src/movethewheels/hooks/useEntityDocuments.ts +30 -12
- package/src/movethewheels/hooks/useEpod.ts +410 -0
- package/src/movethewheels/pages/DeliveryCapturePage.tsx +297 -0
- package/src/movethewheels/pages/OrderDetailsPage.tsx +4 -0
- package/src/movethewheels/pages/TrackingPage.tsx +4 -0
- package/src/movethewheels/types/index.ts +21 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProofOfDeliveryCard — the shipper/customer-facing view of a captured ePOD
|
|
3
|
+
* (BOFF-4399). Read-only: shows recipient name, signature, timestamp,
|
|
4
|
+
* geo-location and any delivery photos, with a download link for the
|
|
5
|
+
* signature image. Renders an honest "not yet delivered" empty state when no
|
|
6
|
+
* capture exists.
|
|
7
|
+
*/
|
|
8
|
+
import { CheckCircle2, Clock, Download, MapPin, User } from 'lucide-react';
|
|
9
|
+
import { Card, CardContent, CardHeader, CardTitle, Badge } from './ui';
|
|
10
|
+
import { useEpod, useEpodPhotoUrl } from '../hooks/useEpod';
|
|
11
|
+
import { formatDateTime } from '../utils/formatters';
|
|
12
|
+
|
|
13
|
+
interface ProofOfDeliveryCardProps {
|
|
14
|
+
deliveryJobId: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function EpodPhotoThumbnail({ fileId }: { fileId: string }) {
|
|
18
|
+
const { url, isLoading } = useEpodPhotoUrl(fileId);
|
|
19
|
+
|
|
20
|
+
if (isLoading) {
|
|
21
|
+
return <div className="h-20 w-20 rounded-lg bg-bg-sunken animate-pulse" />;
|
|
22
|
+
}
|
|
23
|
+
if (!url) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return (
|
|
27
|
+
<a href={url} target="_blank" rel="noopener noreferrer" className="shrink-0">
|
|
28
|
+
<img
|
|
29
|
+
src={url}
|
|
30
|
+
alt="Delivery photo"
|
|
31
|
+
className="h-20 w-20 rounded-lg object-cover border border-border"
|
|
32
|
+
/>
|
|
33
|
+
</a>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function ProofOfDeliveryCard({ deliveryJobId }: ProofOfDeliveryCardProps) {
|
|
38
|
+
const { epod, isLoading, error } = useEpod(deliveryJobId);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Card>
|
|
42
|
+
<CardHeader className="flex flex-row items-center justify-between">
|
|
43
|
+
<CardTitle className="flex items-center gap-2">
|
|
44
|
+
<CheckCircle2 size={18} /> Proof of Delivery
|
|
45
|
+
</CardTitle>
|
|
46
|
+
{epod && <Badge variant="success">Captured</Badge>}
|
|
47
|
+
</CardHeader>
|
|
48
|
+
<CardContent>
|
|
49
|
+
{isLoading ? (
|
|
50
|
+
<p className="text-text-secondary text-center py-4">Loading proof of delivery…</p>
|
|
51
|
+
) : error ? (
|
|
52
|
+
<p className="text-sm text-status-error-text text-center py-4">
|
|
53
|
+
Failed to load proof of delivery.
|
|
54
|
+
</p>
|
|
55
|
+
) : epod ? (
|
|
56
|
+
<div className="space-y-4">
|
|
57
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
58
|
+
<div className="flex items-start gap-2">
|
|
59
|
+
<User size={16} className="mt-0.5 text-text-secondary shrink-0" />
|
|
60
|
+
<div>
|
|
61
|
+
<p className="text-xs text-text-secondary">Received by</p>
|
|
62
|
+
<p className="font-medium">{epod.recipientName}</p>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<div className="flex items-start gap-2">
|
|
66
|
+
<Clock size={16} className="mt-0.5 text-text-secondary shrink-0" />
|
|
67
|
+
<div>
|
|
68
|
+
<p className="text-xs text-text-secondary">Delivered at</p>
|
|
69
|
+
<p className="font-medium">{formatDateTime(epod.deliveredAt)}</p>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
{epod.latitude != null && epod.longitude != null && (
|
|
73
|
+
<div className="flex items-start gap-2 sm:col-span-2">
|
|
74
|
+
<MapPin size={16} className="mt-0.5 text-text-secondary shrink-0" />
|
|
75
|
+
<div>
|
|
76
|
+
<p className="text-xs text-text-secondary">Delivery location</p>
|
|
77
|
+
<p className="font-medium">
|
|
78
|
+
{epod.latitude.toFixed(5)}, {epod.longitude.toFixed(5)}
|
|
79
|
+
{epod.locationAccuracy != null && (
|
|
80
|
+
<span className="text-text-secondary"> (±{Math.round(epod.locationAccuracy)}m)</span>
|
|
81
|
+
)}
|
|
82
|
+
</p>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
{epod.notes && (
|
|
89
|
+
<div>
|
|
90
|
+
<p className="text-xs text-text-secondary mb-1">Notes</p>
|
|
91
|
+
<p className="text-sm">{epod.notes}</p>
|
|
92
|
+
</div>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
<div>
|
|
96
|
+
<p className="text-xs text-text-secondary mb-1">
|
|
97
|
+
Signature {epod.signatureType === 'typed' ? '(typed)' : '(drawn)'}
|
|
98
|
+
</p>
|
|
99
|
+
{epod.signatureType === 'drawn' ? (
|
|
100
|
+
<div className="border rounded-lg p-2 inline-block bg-white">
|
|
101
|
+
<img src={epod.signatureData} alt="Recipient signature" className="h-16" />
|
|
102
|
+
</div>
|
|
103
|
+
) : (
|
|
104
|
+
<p className="text-lg italic font-medium border-b border-border inline-block pb-1">
|
|
105
|
+
{epod.signatureData}
|
|
106
|
+
</p>
|
|
107
|
+
)}
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{epod.photoFileIds.length > 0 && (
|
|
111
|
+
<div>
|
|
112
|
+
<p className="text-xs text-text-secondary mb-2">Delivery photos</p>
|
|
113
|
+
<div className="flex flex-wrap gap-2">
|
|
114
|
+
{epod.photoFileIds.map((fileId) => (
|
|
115
|
+
<EpodPhotoThumbnail key={fileId} fileId={fileId} />
|
|
116
|
+
))}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
)}
|
|
120
|
+
|
|
121
|
+
<a
|
|
122
|
+
href={`data:text/plain;charset=utf-8,${encodeURIComponent(
|
|
123
|
+
`Proof of Delivery\nRecipient: ${epod.recipientName}\nDelivered at: ${formatDateTime(
|
|
124
|
+
epod.deliveredAt
|
|
125
|
+
)}${
|
|
126
|
+
epod.latitude != null && epod.longitude != null
|
|
127
|
+
? `\nLocation: ${epod.latitude}, ${epod.longitude}`
|
|
128
|
+
: ''
|
|
129
|
+
}${epod.notes ? `\nNotes: ${epod.notes}` : ''}`
|
|
130
|
+
)}`}
|
|
131
|
+
download={`pod-${deliveryJobId}.txt`}
|
|
132
|
+
className="inline-flex items-center gap-1 text-sm text-primary hover:underline"
|
|
133
|
+
>
|
|
134
|
+
<Download size={14} /> Download record
|
|
135
|
+
</a>
|
|
136
|
+
</div>
|
|
137
|
+
) : (
|
|
138
|
+
<div className="text-center py-6">
|
|
139
|
+
<CheckCircle2 size={32} className="mx-auto mb-2 text-text-secondary opacity-50" />
|
|
140
|
+
<p className="text-text-secondary">Not yet delivered</p>
|
|
141
|
+
<p className="text-xs text-text-secondary mt-1">
|
|
142
|
+
Proof of delivery will appear here once the driver completes capture.
|
|
143
|
+
</p>
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
</CardContent>
|
|
147
|
+
</Card>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SignaturePad — dependency-free canvas signature capture.
|
|
3
|
+
*
|
|
4
|
+
* Pointer-events drawing on a `<canvas>`, exported as a `data:image/png;base64,...`
|
|
5
|
+
* string via `toDataURL`. No external signature-pad package is pulled in — this
|
|
6
|
+
* keeps the ePOD capture core self-contained and avoids a new dependency for a
|
|
7
|
+
* single bounded widget.
|
|
8
|
+
*/
|
|
9
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
10
|
+
import { Button } from './ui';
|
|
11
|
+
import { cn } from '../utils/cn';
|
|
12
|
+
|
|
13
|
+
export interface SignaturePadHandle {
|
|
14
|
+
clear: () => void;
|
|
15
|
+
isEmpty: () => boolean;
|
|
16
|
+
toDataUrl: () => string | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface SignaturePadProps {
|
|
20
|
+
className?: string;
|
|
21
|
+
onChange?: (hasSignature: boolean) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const SignaturePad = forwardRef<SignaturePadHandle, SignaturePadProps>(
|
|
25
|
+
({ className, onChange }, ref) => {
|
|
26
|
+
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
|
27
|
+
const drawingRef = useRef(false);
|
|
28
|
+
const hasDrawnRef = useRef(false);
|
|
29
|
+
const lastPointRef = useRef<{ x: number; y: number } | null>(null);
|
|
30
|
+
const [hasDrawn, setHasDrawn] = useState(false);
|
|
31
|
+
|
|
32
|
+
const getContext = useCallback((): CanvasRenderingContext2D | null => {
|
|
33
|
+
const canvas = canvasRef.current;
|
|
34
|
+
return canvas ? canvas.getContext('2d') : null;
|
|
35
|
+
}, []);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const canvas = canvasRef.current;
|
|
39
|
+
const ctx = getContext();
|
|
40
|
+
if (!canvas || !ctx) return;
|
|
41
|
+
// Size the backing bitmap to the element's rendered size (device-pixel
|
|
42
|
+
// aware) so lines stay crisp regardless of the CSS layout width.
|
|
43
|
+
const ratio = window.devicePixelRatio || 1;
|
|
44
|
+
const rect = canvas.getBoundingClientRect();
|
|
45
|
+
canvas.width = rect.width * ratio;
|
|
46
|
+
canvas.height = rect.height * ratio;
|
|
47
|
+
ctx.scale(ratio, ratio);
|
|
48
|
+
ctx.lineWidth = 2;
|
|
49
|
+
ctx.lineCap = 'round';
|
|
50
|
+
ctx.lineJoin = 'round';
|
|
51
|
+
// Canvas has no CSS var support for strokeStyle — resolve the semantic
|
|
52
|
+
// `text-text-primary` token (applied via className below) to its
|
|
53
|
+
// computed color at draw-setup time instead of a hard-coded hex.
|
|
54
|
+
// `currentColor` is the CSS-spec fallback so a resolution failure still
|
|
55
|
+
// inherits the token via the element's own `color`, never a raw literal.
|
|
56
|
+
ctx.strokeStyle = getComputedStyle(canvas).color || 'currentColor';
|
|
57
|
+
}, [getContext]);
|
|
58
|
+
|
|
59
|
+
const pointFromEvent = useCallback((event: React.PointerEvent<HTMLCanvasElement>) => {
|
|
60
|
+
const canvas = canvasRef.current;
|
|
61
|
+
if (!canvas) return { x: 0, y: 0 };
|
|
62
|
+
const rect = canvas.getBoundingClientRect();
|
|
63
|
+
return { x: event.clientX - rect.left, y: event.clientY - rect.top };
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
const handlePointerDown = useCallback(
|
|
67
|
+
(event: React.PointerEvent<HTMLCanvasElement>) => {
|
|
68
|
+
const canvas = canvasRef.current;
|
|
69
|
+
const ctx = getContext();
|
|
70
|
+
if (!canvas || !ctx) return;
|
|
71
|
+
canvas.setPointerCapture(event.pointerId);
|
|
72
|
+
drawingRef.current = true;
|
|
73
|
+
lastPointRef.current = pointFromEvent(event);
|
|
74
|
+
},
|
|
75
|
+
[getContext, pointFromEvent]
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const handlePointerMove = useCallback(
|
|
79
|
+
(event: React.PointerEvent<HTMLCanvasElement>) => {
|
|
80
|
+
if (!drawingRef.current) return;
|
|
81
|
+
const ctx = getContext();
|
|
82
|
+
const last = lastPointRef.current;
|
|
83
|
+
if (!ctx || !last) return;
|
|
84
|
+
const point = pointFromEvent(event);
|
|
85
|
+
ctx.beginPath();
|
|
86
|
+
ctx.moveTo(last.x, last.y);
|
|
87
|
+
ctx.lineTo(point.x, point.y);
|
|
88
|
+
ctx.stroke();
|
|
89
|
+
lastPointRef.current = point;
|
|
90
|
+
if (!hasDrawnRef.current) {
|
|
91
|
+
hasDrawnRef.current = true;
|
|
92
|
+
setHasDrawn(true);
|
|
93
|
+
onChange?.(true);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
[getContext, onChange, pointFromEvent]
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const handlePointerUp = useCallback((event: React.PointerEvent<HTMLCanvasElement>) => {
|
|
100
|
+
drawingRef.current = false;
|
|
101
|
+
lastPointRef.current = null;
|
|
102
|
+
const canvas = canvasRef.current;
|
|
103
|
+
if (canvas?.hasPointerCapture(event.pointerId)) {
|
|
104
|
+
canvas.releasePointerCapture(event.pointerId);
|
|
105
|
+
}
|
|
106
|
+
}, []);
|
|
107
|
+
|
|
108
|
+
const clear = useCallback(() => {
|
|
109
|
+
const canvas = canvasRef.current;
|
|
110
|
+
const ctx = getContext();
|
|
111
|
+
if (!canvas || !ctx) return;
|
|
112
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
113
|
+
hasDrawnRef.current = false;
|
|
114
|
+
setHasDrawn(false);
|
|
115
|
+
onChange?.(false);
|
|
116
|
+
}, [getContext, onChange]);
|
|
117
|
+
|
|
118
|
+
const toDataUrl = useCallback((): string | null => {
|
|
119
|
+
if (!hasDrawnRef.current) return null;
|
|
120
|
+
return canvasRef.current?.toDataURL('image/png') ?? null;
|
|
121
|
+
}, []);
|
|
122
|
+
|
|
123
|
+
useImperativeHandle(
|
|
124
|
+
ref,
|
|
125
|
+
(): SignaturePadHandle => ({
|
|
126
|
+
clear,
|
|
127
|
+
isEmpty: () => !hasDrawnRef.current,
|
|
128
|
+
toDataUrl,
|
|
129
|
+
}),
|
|
130
|
+
[clear, toDataUrl]
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div className={cn('space-y-2', className)}>
|
|
135
|
+
<canvas
|
|
136
|
+
ref={canvasRef}
|
|
137
|
+
className="w-full h-40 rounded-lg border-2 border-dashed border-border bg-bg-surface text-text-primary touch-none cursor-crosshair"
|
|
138
|
+
onPointerDown={handlePointerDown}
|
|
139
|
+
onPointerMove={handlePointerMove}
|
|
140
|
+
onPointerUp={handlePointerUp}
|
|
141
|
+
onPointerLeave={handlePointerUp}
|
|
142
|
+
role="img"
|
|
143
|
+
aria-label="Signature capture pad"
|
|
144
|
+
/>
|
|
145
|
+
<div className="flex items-center justify-between">
|
|
146
|
+
<p className="text-xs text-text-secondary">
|
|
147
|
+
{hasDrawn ? 'Signature captured' : 'Sign above with your finger or mouse'}
|
|
148
|
+
</p>
|
|
149
|
+
<Button type="button" variant="ghost" size="sm" onClick={clear} disabled={!hasDrawn}>
|
|
150
|
+
Clear
|
|
151
|
+
</Button>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
SignaturePad.displayName = 'SignaturePad';
|
|
@@ -71,3 +71,15 @@ export {
|
|
|
71
71
|
type EntityDocument,
|
|
72
72
|
type EntityDocumentType,
|
|
73
73
|
} from './useEntityDocuments';
|
|
74
|
+
|
|
75
|
+
// Electronic proof of delivery (ePOD) capture — BOFF-4399
|
|
76
|
+
export {
|
|
77
|
+
useEpod,
|
|
78
|
+
useMyPendingEpodDeliveryJobs,
|
|
79
|
+
useCaptureEpod,
|
|
80
|
+
useEpodPhotoUpload,
|
|
81
|
+
useEpodPhotoUrl,
|
|
82
|
+
type PendingEpodDeliveryJob,
|
|
83
|
+
type CaptureEpodArgs,
|
|
84
|
+
type UploadedEpodPhoto,
|
|
85
|
+
} from './useEpod';
|
|
@@ -5,10 +5,26 @@
|
|
|
5
5
|
* driver or order live in the platform Files module (wspace-files-svc), which
|
|
6
6
|
* federates into the same workspace gateway. We tag each uploaded file with two
|
|
7
7
|
* marqueue entity tags — `mtwEntityType` and `mtwEntityId` — and list them back
|
|
8
|
-
* here through
|
|
8
|
+
* here through `getFiles(filter:{ tags:[...] })`.
|
|
9
9
|
*
|
|
10
10
|
* There is no upload UI here (out of scope): uploading/managing happens in the
|
|
11
11
|
* Files module, deep-linked from DocumentsCard. This hook is read-only.
|
|
12
|
+
*
|
|
13
|
+
* BOFF-3922 fix (2026-07-26): this previously called a non-existent root field
|
|
14
|
+
* `files(...)` — the wspace gateway only exposes `Workspace.files` (nested) and
|
|
15
|
+
* root fields `getFiles`/`searchFiles`/`ownedFiles`/`uploadedFiles`, none named
|
|
16
|
+
* bare `files`. Fixed to `getFiles(...): FileList!` (unwrapping `.files`), the
|
|
17
|
+
* root field whose `folderId` arg is optional so it supports a workspace-wide
|
|
18
|
+
* filter-only lookup. Caught by the new graphql-schema-drift CI guard, which
|
|
19
|
+
* had zero prior coverage on this repo — this bug would otherwise have shipped
|
|
20
|
+
* to prod undetected, same as BOFF-3915/BOFF-4703/BOFF-3529.
|
|
21
|
+
*
|
|
22
|
+
* NOT verified by this fix: whether `TagFilterInput.label` (renamed here from
|
|
23
|
+
* the nonexistent `.value`) actually produces the intended
|
|
24
|
+
* mtwEntityType+mtwEntityId AND-filter semantics against wspace-files-svc's
|
|
25
|
+
* tag-matching resolver — that's a wspace-files-svc/wspace-tags-svc business-
|
|
26
|
+
* logic question outside a schema-shape validator's reach (it operates on
|
|
27
|
+
* runtime variable values, not the query document). Flagged as follow-up.
|
|
12
28
|
*/
|
|
13
29
|
|
|
14
30
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
@@ -46,13 +62,15 @@ interface UseEntityDocumentsResult {
|
|
|
46
62
|
|
|
47
63
|
const LIST_ENTITY_FILES_QUERY = `
|
|
48
64
|
query ListEntityDocuments($filter: FileFilterInput, $pagination: PaginationInput) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
getFiles(filter: $filter, pagination: $pagination) {
|
|
66
|
+
files {
|
|
67
|
+
id
|
|
68
|
+
name
|
|
69
|
+
size
|
|
70
|
+
mimeType
|
|
71
|
+
createdAt
|
|
72
|
+
downloadUrl
|
|
73
|
+
}
|
|
56
74
|
}
|
|
57
75
|
}
|
|
58
76
|
`;
|
|
@@ -98,20 +116,20 @@ export function useEntityDocuments(
|
|
|
98
116
|
setIsLoading(true);
|
|
99
117
|
setError(null);
|
|
100
118
|
try {
|
|
101
|
-
const data = await executeGraphQL<{ files: ApiFile[] }>(
|
|
119
|
+
const data = await executeGraphQL<{ getFiles: { files: ApiFile[] } }>(
|
|
102
120
|
graphQLOptions,
|
|
103
121
|
LIST_ENTITY_FILES_QUERY,
|
|
104
122
|
{
|
|
105
123
|
filter: {
|
|
106
124
|
tags: [
|
|
107
|
-
{ key: 'mtwEntityType',
|
|
108
|
-
{ key: 'mtwEntityId',
|
|
125
|
+
{ key: 'mtwEntityType', label: entityType },
|
|
126
|
+
{ key: 'mtwEntityId', label: entityId },
|
|
109
127
|
],
|
|
110
128
|
},
|
|
111
129
|
pagination: { limit: 50, offset: 0 },
|
|
112
130
|
}
|
|
113
131
|
);
|
|
114
|
-
setDocuments((data.files ?? []).map(mapFile));
|
|
132
|
+
setDocuments((data.getFiles?.files ?? []).map(mapFile));
|
|
115
133
|
} catch (fetchError) {
|
|
116
134
|
setError(fetchError instanceof Error ? fetchError : new Error('Failed to load documents'));
|
|
117
135
|
setDocuments([]);
|