@burdenoff/microfe-assethandler 2026.826.6 → 2026.826.7
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/assethandler/AssetHandlerRoot.d.ts.map +1 -1
- package/dist/assethandler/AssetHandlerRoot.js +53 -46
- package/dist/assethandler/AssetHandlerRoot.js.map +1 -1
- package/dist/assethandler/AssetHandlerRoutes.d.ts.map +1 -1
- package/dist/assethandler/AssetHandlerRoutes.js +43 -39
- package/dist/assethandler/AssetHandlerRoutes.js.map +1 -1
- package/dist/assethandler/pages/PhysicalAuditsPage.d.ts +2 -0
- package/dist/assethandler/pages/PhysicalAuditsPage.d.ts.map +1 -0
- package/dist/assethandler/pages/PhysicalAuditsPage.js +465 -0
- package/dist/assethandler/pages/PhysicalAuditsPage.js.map +1 -0
- package/dist/generated/wspace-types.d.ts +101 -0
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import { notify as e } from "../utils/toast.js";
|
|
2
|
+
import { StatTile as t } from "../components/StatTile.js";
|
|
3
|
+
import { SectionHeader as n } from "../components/SectionHeader.js";
|
|
4
|
+
import "../components/index.js";
|
|
5
|
+
import { downloadCsv as r } from "../utils/csv.js";
|
|
6
|
+
import { useMemo as ee, useState as i } from "react";
|
|
7
|
+
import { CheckCircle2 as a, Download as o, MapPin as s, ScanLine as c, Trash2 as l } from "lucide-react";
|
|
8
|
+
import { gql as u } from "@apollo/client";
|
|
9
|
+
import { useMutation as d, useQuery as f } from "@apollo/client/react";
|
|
10
|
+
import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
11
|
+
import { Button as g, GlassCard as _, Input as v, Label as y, PagePurpose as b, Textarea as x } from "@burdenoff/fe-libs/ui";
|
|
12
|
+
//#region src/assethandler/pages/PhysicalAuditsPage.tsx
|
|
13
|
+
var S = u`
|
|
14
|
+
fragment AssetHandlerPhysicalAuditFields on PhysicalAudit {
|
|
15
|
+
id
|
|
16
|
+
name
|
|
17
|
+
expectedLocation
|
|
18
|
+
status
|
|
19
|
+
notes
|
|
20
|
+
startedAt
|
|
21
|
+
completedAt
|
|
22
|
+
expectedCount
|
|
23
|
+
scannedCount
|
|
24
|
+
presentCount
|
|
25
|
+
missingCount
|
|
26
|
+
movedCount
|
|
27
|
+
unexpectedCount
|
|
28
|
+
unresolvedCount
|
|
29
|
+
items {
|
|
30
|
+
id
|
|
31
|
+
assetId
|
|
32
|
+
scannedTagId
|
|
33
|
+
assetNumber
|
|
34
|
+
assetName
|
|
35
|
+
expectedLocation
|
|
36
|
+
observedLocation
|
|
37
|
+
outcome
|
|
38
|
+
scannedAt
|
|
39
|
+
resolutionNotes
|
|
40
|
+
resolvedAt
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`, C = u`
|
|
44
|
+
query AssetHandlerPhysicalAudits {
|
|
45
|
+
physicalAudits {
|
|
46
|
+
...AssetHandlerPhysicalAuditFields
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
${S}
|
|
50
|
+
`, w = u`
|
|
51
|
+
mutation AssetHandlerCreatePhysicalAudit($input: CreatePhysicalAuditInput!) {
|
|
52
|
+
createPhysicalAudit(input: $input) {
|
|
53
|
+
...AssetHandlerPhysicalAuditFields
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
${S}
|
|
57
|
+
`, T = u`
|
|
58
|
+
mutation AssetHandlerScanPhysicalAuditTag($input: ScanPhysicalAuditTagInput!) {
|
|
59
|
+
scanPhysicalAuditTag(input: $input) {
|
|
60
|
+
id
|
|
61
|
+
outcome
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
`, E = u`
|
|
65
|
+
mutation AssetHandlerCompletePhysicalAudit($id: ID!) {
|
|
66
|
+
completePhysicalAudit(id: $id) {
|
|
67
|
+
...AssetHandlerPhysicalAuditFields
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
${S}
|
|
71
|
+
`, D = u`
|
|
72
|
+
mutation AssetHandlerResolvePhysicalAuditItem($input: ResolvePhysicalAuditItemInput!) {
|
|
73
|
+
resolvePhysicalAuditItem(input: $input) {
|
|
74
|
+
id
|
|
75
|
+
resolutionNotes
|
|
76
|
+
resolvedAt
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`, te = u`
|
|
80
|
+
mutation AssetHandlerDeletePhysicalAudit($id: ID!) {
|
|
81
|
+
deletePhysicalAudit(id: $id)
|
|
82
|
+
}
|
|
83
|
+
`, O = {
|
|
84
|
+
PENDING: "bg-bg-sunken text-text-secondary",
|
|
85
|
+
PRESENT: "bg-status-success-subtle text-status-success-text",
|
|
86
|
+
MISSING: "bg-status-error-subtle text-status-error-text",
|
|
87
|
+
MOVED: "bg-status-warning-subtle text-status-warning-text",
|
|
88
|
+
UNEXPECTED: "bg-status-info-bg-subtle text-status-info-text"
|
|
89
|
+
};
|
|
90
|
+
function ne(e) {
|
|
91
|
+
return e.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
92
|
+
}
|
|
93
|
+
function k(e) {
|
|
94
|
+
return e ? new Date(e).toLocaleString() : "—";
|
|
95
|
+
}
|
|
96
|
+
function A() {
|
|
97
|
+
let { data: u, loading: S, error: A, refetch: j } = f(C), [M, N] = i(null), [P, F] = i(""), [I, L] = i(""), [R, z] = i(""), [B, V] = i(""), [H, U] = i(""), [W, G] = i(""), K = u?.physicalAudits ?? [], q = ee(() => K.find((e) => e.id === M) ?? K[0] ?? null, [K, M]), [J, Y] = d(w), [X, Z] = d(T), [re, ie] = d(E), [ae, oe] = d(D), [se, Q] = d(te), $ = async () => {
|
|
98
|
+
await j();
|
|
99
|
+
}, ce = async (t) => {
|
|
100
|
+
t.preventDefault();
|
|
101
|
+
let n = (await J({ variables: { input: {
|
|
102
|
+
name: P.trim(),
|
|
103
|
+
...I.trim() ? { expectedLocation: I.trim() } : {},
|
|
104
|
+
...R.trim() ? { notes: R.trim() } : {}
|
|
105
|
+
} } })).data?.createPhysicalAudit;
|
|
106
|
+
n && (N(n.id), F(""), z(""), U(n.expectedLocation ?? ""), await $(), e.success("Physical audit started", `${n.expectedCount} expected assets snapshotted.`));
|
|
107
|
+
}, le = async (t) => {
|
|
108
|
+
t.preventDefault(), q && (await X({ variables: { input: {
|
|
109
|
+
auditId: q.id,
|
|
110
|
+
tagId: B.trim(),
|
|
111
|
+
observedLocation: H.trim()
|
|
112
|
+
} } }), V(""), await $(), e.success("Tag reconciled", "The audit result was persisted against the expected inventory."));
|
|
113
|
+
}, ue = async () => {
|
|
114
|
+
q && (await re({ variables: { id: q.id } }), await $(), e.success("Audit completed", "Unscanned expected assets are now marked missing."));
|
|
115
|
+
}, de = async (t, n) => {
|
|
116
|
+
await ae({ variables: { input: {
|
|
117
|
+
itemId: t.id,
|
|
118
|
+
resolutionNotes: W.trim(),
|
|
119
|
+
updateRegistryLocation: n
|
|
120
|
+
} } }), await $(), e.success("Exception reconciled", n ? "The asset registry location was corrected." : "Review evidence saved.");
|
|
121
|
+
}, fe = async () => {
|
|
122
|
+
!q || !window.confirm(`Delete physical audit "${q.name}"?`) || (await se({ variables: { id: q.id } }), N(null), await $(), e.success("Audit deleted", "The audit and its scan evidence were removed."));
|
|
123
|
+
}, pe = () => {
|
|
124
|
+
q && r(`physical-audit-${ne(q.name) || q.id}.csv`, [
|
|
125
|
+
"Audit ID",
|
|
126
|
+
"Audit name",
|
|
127
|
+
"Status",
|
|
128
|
+
"Tag ID",
|
|
129
|
+
"Asset number",
|
|
130
|
+
"Asset name",
|
|
131
|
+
"Expected location",
|
|
132
|
+
"Observed location",
|
|
133
|
+
"Outcome",
|
|
134
|
+
"Scanned at",
|
|
135
|
+
"Resolved at",
|
|
136
|
+
"Resolution notes"
|
|
137
|
+
], q.items.map((e) => [
|
|
138
|
+
q.id,
|
|
139
|
+
q.name,
|
|
140
|
+
q.status,
|
|
141
|
+
e.scannedTagId,
|
|
142
|
+
e.assetNumber,
|
|
143
|
+
e.assetName,
|
|
144
|
+
e.expectedLocation,
|
|
145
|
+
e.observedLocation,
|
|
146
|
+
e.outcome,
|
|
147
|
+
e.scannedAt,
|
|
148
|
+
e.resolvedAt,
|
|
149
|
+
e.resolutionNotes
|
|
150
|
+
]));
|
|
151
|
+
};
|
|
152
|
+
if (A) throw A;
|
|
153
|
+
return /* @__PURE__ */ h("div", {
|
|
154
|
+
className: "space-y-6 p-6",
|
|
155
|
+
children: [
|
|
156
|
+
/* @__PURE__ */ m(n, {
|
|
157
|
+
hero: !0,
|
|
158
|
+
icon: c,
|
|
159
|
+
title: "Physical audits",
|
|
160
|
+
description: "Run a reproducible on-site stocktake."
|
|
161
|
+
}),
|
|
162
|
+
/* @__PURE__ */ m(b, { children: "Snapshot expected inventory, scan tags on site, reconcile present, missing, moved and unexpected items, then retain and export the evidence." }),
|
|
163
|
+
/* @__PURE__ */ h(_, {
|
|
164
|
+
className: "p-5",
|
|
165
|
+
children: [/* @__PURE__ */ m(n, {
|
|
166
|
+
title: "Start a stocktake",
|
|
167
|
+
description: "Expected inventory is frozen when the audit starts."
|
|
168
|
+
}), /* @__PURE__ */ h("form", {
|
|
169
|
+
className: "mt-4 grid gap-4 md:grid-cols-3",
|
|
170
|
+
onSubmit: (e) => void ce(e),
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ h("div", {
|
|
173
|
+
className: "space-y-2",
|
|
174
|
+
children: [/* @__PURE__ */ m(y, {
|
|
175
|
+
htmlFor: "audit-name",
|
|
176
|
+
children: "Audit name"
|
|
177
|
+
}), /* @__PURE__ */ m(v, {
|
|
178
|
+
id: "audit-name",
|
|
179
|
+
value: P,
|
|
180
|
+
onChange: (e) => F(e.target.value),
|
|
181
|
+
required: !0
|
|
182
|
+
})]
|
|
183
|
+
}),
|
|
184
|
+
/* @__PURE__ */ h("div", {
|
|
185
|
+
className: "space-y-2",
|
|
186
|
+
children: [/* @__PURE__ */ m(y, {
|
|
187
|
+
htmlFor: "expected-location",
|
|
188
|
+
children: "Expected location"
|
|
189
|
+
}), /* @__PURE__ */ m(v, {
|
|
190
|
+
id: "expected-location",
|
|
191
|
+
value: I,
|
|
192
|
+
onChange: (e) => L(e.target.value),
|
|
193
|
+
placeholder: "Leave blank for all active assets"
|
|
194
|
+
})]
|
|
195
|
+
}),
|
|
196
|
+
/* @__PURE__ */ h("div", {
|
|
197
|
+
className: "space-y-2",
|
|
198
|
+
children: [/* @__PURE__ */ m(y, {
|
|
199
|
+
htmlFor: "audit-notes",
|
|
200
|
+
children: "Audit notes"
|
|
201
|
+
}), /* @__PURE__ */ m(v, {
|
|
202
|
+
id: "audit-notes",
|
|
203
|
+
value: R,
|
|
204
|
+
onChange: (e) => z(e.target.value)
|
|
205
|
+
})]
|
|
206
|
+
}),
|
|
207
|
+
/* @__PURE__ */ h(g, {
|
|
208
|
+
type: "submit",
|
|
209
|
+
disabled: !P.trim() || Y.loading,
|
|
210
|
+
children: [/* @__PURE__ */ m(c, { className: "mr-2 h-4 w-4" }), " Start physical audit"]
|
|
211
|
+
})
|
|
212
|
+
]
|
|
213
|
+
})]
|
|
214
|
+
}),
|
|
215
|
+
/* @__PURE__ */ h(_, {
|
|
216
|
+
className: "p-5",
|
|
217
|
+
children: [/* @__PURE__ */ m(n, {
|
|
218
|
+
title: "Audit sessions",
|
|
219
|
+
description: S ? "Loading…" : `${K.length} retained`
|
|
220
|
+
}), /* @__PURE__ */ h("div", {
|
|
221
|
+
className: "mt-4 flex flex-wrap gap-2",
|
|
222
|
+
children: [K.map((e) => /* @__PURE__ */ h(g, {
|
|
223
|
+
variant: q?.id === e.id ? "default" : "outline",
|
|
224
|
+
onClick: () => {
|
|
225
|
+
N(e.id), U(e.expectedLocation ?? "");
|
|
226
|
+
},
|
|
227
|
+
children: [
|
|
228
|
+
e.name,
|
|
229
|
+
" · ",
|
|
230
|
+
e.status.replace("_", " ")
|
|
231
|
+
]
|
|
232
|
+
}, e.id)), !S && K.length === 0 && /* @__PURE__ */ m("p", {
|
|
233
|
+
className: "text-sm text-text-secondary",
|
|
234
|
+
children: "No audits yet."
|
|
235
|
+
})]
|
|
236
|
+
})]
|
|
237
|
+
}),
|
|
238
|
+
q && /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ h("div", {
|
|
239
|
+
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-7",
|
|
240
|
+
children: [
|
|
241
|
+
/* @__PURE__ */ m(t, {
|
|
242
|
+
label: "Expected",
|
|
243
|
+
value: q.expectedCount,
|
|
244
|
+
icon: s
|
|
245
|
+
}),
|
|
246
|
+
/* @__PURE__ */ m(t, {
|
|
247
|
+
label: "Scanned",
|
|
248
|
+
value: q.scannedCount,
|
|
249
|
+
icon: c
|
|
250
|
+
}),
|
|
251
|
+
/* @__PURE__ */ m(t, {
|
|
252
|
+
label: "Present",
|
|
253
|
+
value: q.presentCount,
|
|
254
|
+
icon: a
|
|
255
|
+
}),
|
|
256
|
+
/* @__PURE__ */ m(t, {
|
|
257
|
+
label: "Missing",
|
|
258
|
+
value: q.missingCount,
|
|
259
|
+
icon: c
|
|
260
|
+
}),
|
|
261
|
+
/* @__PURE__ */ m(t, {
|
|
262
|
+
label: "Moved",
|
|
263
|
+
value: q.movedCount,
|
|
264
|
+
icon: s
|
|
265
|
+
}),
|
|
266
|
+
/* @__PURE__ */ m(t, {
|
|
267
|
+
label: "Unexpected",
|
|
268
|
+
value: q.unexpectedCount,
|
|
269
|
+
icon: c
|
|
270
|
+
}),
|
|
271
|
+
/* @__PURE__ */ m(t, {
|
|
272
|
+
label: "Unresolved",
|
|
273
|
+
value: q.unresolvedCount,
|
|
274
|
+
icon: c
|
|
275
|
+
})
|
|
276
|
+
]
|
|
277
|
+
}), /* @__PURE__ */ h(_, {
|
|
278
|
+
className: "p-5",
|
|
279
|
+
children: [
|
|
280
|
+
/* @__PURE__ */ h("div", {
|
|
281
|
+
className: "flex flex-wrap items-start justify-between gap-3",
|
|
282
|
+
children: [/* @__PURE__ */ h("div", { children: [
|
|
283
|
+
/* @__PURE__ */ m("h2", {
|
|
284
|
+
className: "text-lg font-semibold text-text-primary",
|
|
285
|
+
children: q.name
|
|
286
|
+
}),
|
|
287
|
+
/* @__PURE__ */ h("p", {
|
|
288
|
+
className: "text-sm text-text-secondary",
|
|
289
|
+
children: [
|
|
290
|
+
"ID ",
|
|
291
|
+
q.id,
|
|
292
|
+
" · expected ",
|
|
293
|
+
q.expectedLocation ?? "all active locations",
|
|
294
|
+
" ",
|
|
295
|
+
"· started ",
|
|
296
|
+
k(q.startedAt)
|
|
297
|
+
]
|
|
298
|
+
}),
|
|
299
|
+
q.completedAt && /* @__PURE__ */ h("p", {
|
|
300
|
+
className: "text-sm text-text-secondary",
|
|
301
|
+
children: ["Completed ", k(q.completedAt)]
|
|
302
|
+
})
|
|
303
|
+
] }), /* @__PURE__ */ h("div", {
|
|
304
|
+
className: "flex gap-2",
|
|
305
|
+
children: [/* @__PURE__ */ h(g, {
|
|
306
|
+
variant: "outline",
|
|
307
|
+
onClick: pe,
|
|
308
|
+
children: [/* @__PURE__ */ m(o, { className: "mr-2 h-4 w-4" }), " Export CSV"]
|
|
309
|
+
}), /* @__PURE__ */ h(g, {
|
|
310
|
+
variant: "outline",
|
|
311
|
+
onClick: () => void fe(),
|
|
312
|
+
disabled: Q.loading,
|
|
313
|
+
children: [/* @__PURE__ */ m(l, { className: "mr-2 h-4 w-4" }), " Delete audit"]
|
|
314
|
+
})]
|
|
315
|
+
})]
|
|
316
|
+
}),
|
|
317
|
+
q.status === "IN_PROGRESS" && /* @__PURE__ */ h("form", {
|
|
318
|
+
className: "mt-5 grid gap-4 md:grid-cols-[1fr_1fr_auto]",
|
|
319
|
+
onSubmit: (e) => void le(e),
|
|
320
|
+
children: [
|
|
321
|
+
/* @__PURE__ */ h("div", {
|
|
322
|
+
className: "space-y-2",
|
|
323
|
+
children: [/* @__PURE__ */ m(y, {
|
|
324
|
+
htmlFor: "audit-tag",
|
|
325
|
+
children: "Scan or enter tag ID"
|
|
326
|
+
}), /* @__PURE__ */ m(v, {
|
|
327
|
+
id: "audit-tag",
|
|
328
|
+
value: B,
|
|
329
|
+
onChange: (e) => V(e.target.value),
|
|
330
|
+
required: !0
|
|
331
|
+
})]
|
|
332
|
+
}),
|
|
333
|
+
/* @__PURE__ */ h("div", {
|
|
334
|
+
className: "space-y-2",
|
|
335
|
+
children: [/* @__PURE__ */ m(y, {
|
|
336
|
+
htmlFor: "observed-location",
|
|
337
|
+
children: "Observed location"
|
|
338
|
+
}), /* @__PURE__ */ m(v, {
|
|
339
|
+
id: "observed-location",
|
|
340
|
+
value: H,
|
|
341
|
+
onChange: (e) => U(e.target.value),
|
|
342
|
+
required: !0
|
|
343
|
+
})]
|
|
344
|
+
}),
|
|
345
|
+
/* @__PURE__ */ m(g, {
|
|
346
|
+
className: "self-end",
|
|
347
|
+
type: "submit",
|
|
348
|
+
disabled: Z.loading || !B.trim() || !H.trim(),
|
|
349
|
+
children: "Reconcile scan"
|
|
350
|
+
})
|
|
351
|
+
]
|
|
352
|
+
}),
|
|
353
|
+
/* @__PURE__ */ m("div", {
|
|
354
|
+
className: "mt-5 overflow-x-auto",
|
|
355
|
+
children: /* @__PURE__ */ h("table", {
|
|
356
|
+
className: "w-full min-w-[980px] text-left text-sm",
|
|
357
|
+
children: [/* @__PURE__ */ m("thead", {
|
|
358
|
+
className: "border-b border-border text-text-secondary",
|
|
359
|
+
children: /* @__PURE__ */ h("tr", { children: [
|
|
360
|
+
/* @__PURE__ */ m("th", {
|
|
361
|
+
className: "px-3 py-2",
|
|
362
|
+
children: "Tag"
|
|
363
|
+
}),
|
|
364
|
+
/* @__PURE__ */ m("th", {
|
|
365
|
+
className: "px-3 py-2",
|
|
366
|
+
children: "Asset"
|
|
367
|
+
}),
|
|
368
|
+
/* @__PURE__ */ m("th", {
|
|
369
|
+
className: "px-3 py-2",
|
|
370
|
+
children: "Expected"
|
|
371
|
+
}),
|
|
372
|
+
/* @__PURE__ */ m("th", {
|
|
373
|
+
className: "px-3 py-2",
|
|
374
|
+
children: "Observed"
|
|
375
|
+
}),
|
|
376
|
+
/* @__PURE__ */ m("th", {
|
|
377
|
+
className: "px-3 py-2",
|
|
378
|
+
children: "Outcome"
|
|
379
|
+
}),
|
|
380
|
+
/* @__PURE__ */ m("th", {
|
|
381
|
+
className: "px-3 py-2",
|
|
382
|
+
children: "Resolution"
|
|
383
|
+
})
|
|
384
|
+
] })
|
|
385
|
+
}), /* @__PURE__ */ m("tbody", { children: q.items.map((e) => /* @__PURE__ */ h("tr", {
|
|
386
|
+
className: "border-b border-border/60",
|
|
387
|
+
children: [
|
|
388
|
+
/* @__PURE__ */ m("td", {
|
|
389
|
+
className: "px-3 py-3 font-mono text-xs",
|
|
390
|
+
children: e.scannedTagId
|
|
391
|
+
}),
|
|
392
|
+
/* @__PURE__ */ m("td", {
|
|
393
|
+
className: "px-3 py-3",
|
|
394
|
+
children: e.assetName ?? e.assetNumber ?? "Unregistered tag"
|
|
395
|
+
}),
|
|
396
|
+
/* @__PURE__ */ m("td", {
|
|
397
|
+
className: "px-3 py-3",
|
|
398
|
+
children: e.expectedLocation ?? "—"
|
|
399
|
+
}),
|
|
400
|
+
/* @__PURE__ */ m("td", {
|
|
401
|
+
className: "px-3 py-3",
|
|
402
|
+
children: e.observedLocation ?? "—"
|
|
403
|
+
}),
|
|
404
|
+
/* @__PURE__ */ m("td", {
|
|
405
|
+
className: "px-3 py-3",
|
|
406
|
+
children: /* @__PURE__ */ m("span", {
|
|
407
|
+
className: `rounded-full px-2 py-1 text-xs font-medium ${O[e.outcome]}`,
|
|
408
|
+
children: e.outcome
|
|
409
|
+
})
|
|
410
|
+
}),
|
|
411
|
+
/* @__PURE__ */ m("td", {
|
|
412
|
+
className: "px-3 py-3",
|
|
413
|
+
children: e.resolutionNotes ?? "—"
|
|
414
|
+
})
|
|
415
|
+
]
|
|
416
|
+
}, e.id)) })]
|
|
417
|
+
})
|
|
418
|
+
}),
|
|
419
|
+
q.status === "IN_PROGRESS" && /* @__PURE__ */ m(g, {
|
|
420
|
+
className: "mt-5",
|
|
421
|
+
onClick: () => void ue(),
|
|
422
|
+
disabled: ie.loading,
|
|
423
|
+
children: "Complete audit and mark unscanned items missing"
|
|
424
|
+
}),
|
|
425
|
+
q.status === "COMPLETED" && q.unresolvedCount > 0 && /* @__PURE__ */ h("div", {
|
|
426
|
+
className: "mt-5 space-y-3 rounded-lg border border-border p-4",
|
|
427
|
+
children: [
|
|
428
|
+
/* @__PURE__ */ m(y, {
|
|
429
|
+
htmlFor: "resolution-notes",
|
|
430
|
+
children: "Exception resolution evidence"
|
|
431
|
+
}),
|
|
432
|
+
/* @__PURE__ */ m(x, {
|
|
433
|
+
id: "resolution-notes",
|
|
434
|
+
value: W,
|
|
435
|
+
onChange: (e) => G(e.target.value),
|
|
436
|
+
placeholder: "Record who verified the discrepancy and what changed."
|
|
437
|
+
}),
|
|
438
|
+
/* @__PURE__ */ m("div", {
|
|
439
|
+
className: "flex flex-wrap gap-2",
|
|
440
|
+
children: q.items.filter((e) => [
|
|
441
|
+
"MISSING",
|
|
442
|
+
"MOVED",
|
|
443
|
+
"UNEXPECTED"
|
|
444
|
+
].includes(e.outcome) && !e.resolvedAt).map((e) => /* @__PURE__ */ h(g, {
|
|
445
|
+
variant: "outline",
|
|
446
|
+
disabled: !W.trim() || oe.loading,
|
|
447
|
+
onClick: () => void de(e, e.outcome === "MOVED"),
|
|
448
|
+
children: [
|
|
449
|
+
"Resolve ",
|
|
450
|
+
e.scannedTagId,
|
|
451
|
+
e.outcome === "MOVED" ? " and update location" : ""
|
|
452
|
+
]
|
|
453
|
+
}, e.id))
|
|
454
|
+
})
|
|
455
|
+
]
|
|
456
|
+
})
|
|
457
|
+
]
|
|
458
|
+
})] })
|
|
459
|
+
]
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
//#endregion
|
|
463
|
+
export { A as PhysicalAuditsPage };
|
|
464
|
+
|
|
465
|
+
//# sourceMappingURL=PhysicalAuditsPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicalAuditsPage.js","names":[],"sources":["../../../src/assethandler/pages/PhysicalAuditsPage.tsx"],"sourcesContent":["import { useMemo, useState, type FormEvent } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Button, GlassCard, Input, Label, PagePurpose, Textarea } from '@burdenoff/fe-libs/ui';\nimport { CheckCircle2, Download, MapPin, ScanLine, Trash2 } from 'lucide-react';\n\nimport { SectionHeader, StatTile } from '../components';\nimport { downloadCsv } from '../utils/csv';\nimport { notify } from '../utils/toast';\n\ntype AuditStatus = 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED';\ntype AuditOutcome = 'PENDING' | 'PRESENT' | 'MISSING' | 'MOVED' | 'UNEXPECTED';\n\ninterface PhysicalAuditItem {\n id: string;\n assetId: string | null;\n scannedTagId: string;\n assetNumber: string | null;\n assetName: string | null;\n expectedLocation: string | null;\n observedLocation: string | null;\n outcome: AuditOutcome;\n scannedAt: string | null;\n resolutionNotes: string | null;\n resolvedAt: string | null;\n}\n\ninterface PhysicalAudit {\n id: string;\n name: string;\n expectedLocation: string | null;\n status: AuditStatus;\n notes: string | null;\n startedAt: string;\n completedAt: string | null;\n expectedCount: number;\n scannedCount: number;\n presentCount: number;\n missingCount: number;\n movedCount: number;\n unexpectedCount: number;\n unresolvedCount: number;\n items: PhysicalAuditItem[];\n}\n\nconst AUDIT_FIELDS = gql`\n fragment AssetHandlerPhysicalAuditFields on PhysicalAudit {\n id\n name\n expectedLocation\n status\n notes\n startedAt\n completedAt\n expectedCount\n scannedCount\n presentCount\n missingCount\n movedCount\n unexpectedCount\n unresolvedCount\n items {\n id\n assetId\n scannedTagId\n assetNumber\n assetName\n expectedLocation\n observedLocation\n outcome\n scannedAt\n resolutionNotes\n resolvedAt\n }\n }\n`;\n\nconst AUDITS_QUERY = gql`\n query AssetHandlerPhysicalAudits {\n physicalAudits {\n ...AssetHandlerPhysicalAuditFields\n }\n }\n ${AUDIT_FIELDS}\n`;\n\nconst CREATE_AUDIT = gql`\n mutation AssetHandlerCreatePhysicalAudit($input: CreatePhysicalAuditInput!) {\n createPhysicalAudit(input: $input) {\n ...AssetHandlerPhysicalAuditFields\n }\n }\n ${AUDIT_FIELDS}\n`;\n\nconst SCAN_AUDIT_TAG = gql`\n mutation AssetHandlerScanPhysicalAuditTag($input: ScanPhysicalAuditTagInput!) {\n scanPhysicalAuditTag(input: $input) {\n id\n outcome\n }\n }\n`;\n\nconst COMPLETE_AUDIT = gql`\n mutation AssetHandlerCompletePhysicalAudit($id: ID!) {\n completePhysicalAudit(id: $id) {\n ...AssetHandlerPhysicalAuditFields\n }\n }\n ${AUDIT_FIELDS}\n`;\n\nconst RESOLVE_AUDIT_ITEM = gql`\n mutation AssetHandlerResolvePhysicalAuditItem($input: ResolvePhysicalAuditItemInput!) {\n resolvePhysicalAuditItem(input: $input) {\n id\n resolutionNotes\n resolvedAt\n }\n }\n`;\n\nconst DELETE_AUDIT = gql`\n mutation AssetHandlerDeletePhysicalAudit($id: ID!) {\n deletePhysicalAudit(id: $id)\n }\n`;\n\nconst OUTCOME_TONE: Record<AuditOutcome, string> = {\n PENDING: 'bg-bg-sunken text-text-secondary',\n PRESENT: 'bg-status-success-subtle text-status-success-text',\n MISSING: 'bg-status-error-subtle text-status-error-text',\n MOVED: 'bg-status-warning-subtle text-status-warning-text',\n UNEXPECTED: 'bg-status-info-bg-subtle text-status-info-text',\n};\n\nfunction safeFilename(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nfunction formatDate(value: string | null): string {\n return value ? new Date(value).toLocaleString() : '—';\n}\n\nexport function PhysicalAuditsPage() {\n const { data, loading, error, refetch } = useQuery<{ physicalAudits: PhysicalAudit[] }>(\n AUDITS_QUERY\n );\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [name, setName] = useState('');\n const [expectedLocation, setExpectedLocation] = useState('');\n const [notes, setNotes] = useState('');\n const [tagId, setTagId] = useState('');\n const [observedLocation, setObservedLocation] = useState('');\n const [resolutionNotes, setResolutionNotes] = useState('');\n\n const audits = data?.physicalAudits ?? [];\n const selected = useMemo(\n () => audits.find((audit) => audit.id === selectedId) ?? audits[0] ?? null,\n [audits, selectedId]\n );\n\n const [createAudit, createState] = useMutation<\n { createPhysicalAudit: PhysicalAudit },\n { input: { name: string; expectedLocation?: string; notes?: string } }\n >(CREATE_AUDIT);\n const [scanAuditTag, scanState] = useMutation(SCAN_AUDIT_TAG);\n const [completeAudit, completeState] = useMutation(COMPLETE_AUDIT);\n const [resolveItem, resolveState] = useMutation(RESOLVE_AUDIT_ITEM);\n const [deleteAudit, deleteState] = useMutation(DELETE_AUDIT);\n\n const refresh = async (): Promise<void> => {\n await refetch();\n };\n\n const submitCreate = async (event: FormEvent): Promise<void> => {\n event.preventDefault();\n const result = await createAudit({\n variables: {\n input: {\n name: name.trim(),\n ...(expectedLocation.trim() ? { expectedLocation: expectedLocation.trim() } : {}),\n ...(notes.trim() ? { notes: notes.trim() } : {}),\n },\n },\n });\n const created = result.data?.createPhysicalAudit;\n if (!created) return;\n setSelectedId(created.id);\n setName('');\n setNotes('');\n setObservedLocation(created.expectedLocation ?? '');\n await refresh();\n notify.success(\n 'Physical audit started',\n `${created.expectedCount} expected assets snapshotted.`\n );\n };\n\n const submitScan = async (event: FormEvent): Promise<void> => {\n event.preventDefault();\n if (!selected) return;\n await scanAuditTag({\n variables: {\n input: {\n auditId: selected.id,\n tagId: tagId.trim(),\n observedLocation: observedLocation.trim(),\n },\n },\n });\n setTagId('');\n await refresh();\n notify.success(\n 'Tag reconciled',\n 'The audit result was persisted against the expected inventory.'\n );\n };\n\n const finishAudit = async (): Promise<void> => {\n if (!selected) return;\n await completeAudit({ variables: { id: selected.id } });\n await refresh();\n notify.success('Audit completed', 'Unscanned expected assets are now marked missing.');\n };\n\n const resolveException = async (\n item: PhysicalAuditItem,\n updateRegistryLocation: boolean\n ): Promise<void> => {\n await resolveItem({\n variables: {\n input: {\n itemId: item.id,\n resolutionNotes: resolutionNotes.trim(),\n updateRegistryLocation,\n },\n },\n });\n await refresh();\n notify.success(\n 'Exception reconciled',\n updateRegistryLocation\n ? 'The asset registry location was corrected.'\n : 'Review evidence saved.'\n );\n };\n\n const removeAudit = async (): Promise<void> => {\n if (!selected || !window.confirm(`Delete physical audit \"${selected.name}\"?`)) return;\n await deleteAudit({ variables: { id: selected.id } });\n setSelectedId(null);\n await refresh();\n notify.success('Audit deleted', 'The audit and its scan evidence were removed.');\n };\n\n const exportAudit = (): void => {\n if (!selected) return;\n downloadCsv(\n `physical-audit-${safeFilename(selected.name) || selected.id}.csv`,\n [\n 'Audit ID',\n 'Audit name',\n 'Status',\n 'Tag ID',\n 'Asset number',\n 'Asset name',\n 'Expected location',\n 'Observed location',\n 'Outcome',\n 'Scanned at',\n 'Resolved at',\n 'Resolution notes',\n ],\n selected.items.map((item) => [\n selected.id,\n selected.name,\n selected.status,\n item.scannedTagId,\n item.assetNumber,\n item.assetName,\n item.expectedLocation,\n item.observedLocation,\n item.outcome,\n item.scannedAt,\n item.resolvedAt,\n item.resolutionNotes,\n ])\n );\n };\n\n if (error) throw error;\n\n return (\n <div className=\"space-y-6 p-6\">\n <SectionHeader\n hero\n icon={ScanLine}\n title=\"Physical audits\"\n description=\"Run a reproducible on-site stocktake.\"\n />\n <PagePurpose>\n Snapshot expected inventory, scan tags on site, reconcile present, missing, moved and\n unexpected items, then retain and export the evidence.\n </PagePurpose>\n\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Start a stocktake\"\n description=\"Expected inventory is frozen when the audit starts.\"\n />\n <form\n className=\"mt-4 grid gap-4 md:grid-cols-3\"\n onSubmit={(event) => void submitCreate(event)}\n >\n <div className=\"space-y-2\">\n <Label htmlFor=\"audit-name\">Audit name</Label>\n <Input\n id=\"audit-name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n required\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"expected-location\">Expected location</Label>\n <Input\n id=\"expected-location\"\n value={expectedLocation}\n onChange={(event) => setExpectedLocation(event.target.value)}\n placeholder=\"Leave blank for all active assets\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"audit-notes\">Audit notes</Label>\n <Input\n id=\"audit-notes\"\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n />\n </div>\n <Button type=\"submit\" disabled={!name.trim() || createState.loading}>\n <ScanLine className=\"mr-2 h-4 w-4\" /> Start physical audit\n </Button>\n </form>\n </GlassCard>\n\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Audit sessions\"\n description={loading ? 'Loading…' : `${audits.length} retained`}\n />\n <div className=\"mt-4 flex flex-wrap gap-2\">\n {audits.map((audit) => (\n <Button\n key={audit.id}\n variant={selected?.id === audit.id ? 'default' : 'outline'}\n onClick={() => {\n setSelectedId(audit.id);\n setObservedLocation(audit.expectedLocation ?? '');\n }}\n >\n {audit.name} · {audit.status.replace('_', ' ')}\n </Button>\n ))}\n {!loading && audits.length === 0 && (\n <p className=\"text-sm text-text-secondary\">No audits yet.</p>\n )}\n </div>\n </GlassCard>\n\n {selected && (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-7\">\n <StatTile label=\"Expected\" value={selected.expectedCount} icon={MapPin} />\n <StatTile label=\"Scanned\" value={selected.scannedCount} icon={ScanLine} />\n <StatTile label=\"Present\" value={selected.presentCount} icon={CheckCircle2} />\n <StatTile label=\"Missing\" value={selected.missingCount} icon={ScanLine} />\n <StatTile label=\"Moved\" value={selected.movedCount} icon={MapPin} />\n <StatTile label=\"Unexpected\" value={selected.unexpectedCount} icon={ScanLine} />\n <StatTile label=\"Unresolved\" value={selected.unresolvedCount} icon={ScanLine} />\n </div>\n\n <GlassCard className=\"p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">{selected.name}</h2>\n <p className=\"text-sm text-text-secondary\">\n ID {selected.id} · expected {selected.expectedLocation ?? 'all active locations'}{' '}\n · started {formatDate(selected.startedAt)}\n </p>\n {selected.completedAt && (\n <p className=\"text-sm text-text-secondary\">\n Completed {formatDate(selected.completedAt)}\n </p>\n )}\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" onClick={exportAudit}>\n <Download className=\"mr-2 h-4 w-4\" /> Export CSV\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => void removeAudit()}\n disabled={deleteState.loading}\n >\n <Trash2 className=\"mr-2 h-4 w-4\" /> Delete audit\n </Button>\n </div>\n </div>\n\n {selected.status === 'IN_PROGRESS' && (\n <form\n className=\"mt-5 grid gap-4 md:grid-cols-[1fr_1fr_auto]\"\n onSubmit={(event) => void submitScan(event)}\n >\n <div className=\"space-y-2\">\n <Label htmlFor=\"audit-tag\">Scan or enter tag ID</Label>\n <Input\n id=\"audit-tag\"\n value={tagId}\n onChange={(event) => setTagId(event.target.value)}\n required\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"observed-location\">Observed location</Label>\n <Input\n id=\"observed-location\"\n value={observedLocation}\n onChange={(event) => setObservedLocation(event.target.value)}\n required\n />\n </div>\n <Button\n className=\"self-end\"\n type=\"submit\"\n disabled={scanState.loading || !tagId.trim() || !observedLocation.trim()}\n >\n Reconcile scan\n </Button>\n </form>\n )}\n\n <div className=\"mt-5 overflow-x-auto\">\n <table className=\"w-full min-w-[980px] text-left text-sm\">\n <thead className=\"border-b border-border text-text-secondary\">\n <tr>\n <th className=\"px-3 py-2\">Tag</th>\n <th className=\"px-3 py-2\">Asset</th>\n <th className=\"px-3 py-2\">Expected</th>\n <th className=\"px-3 py-2\">Observed</th>\n <th className=\"px-3 py-2\">Outcome</th>\n <th className=\"px-3 py-2\">Resolution</th>\n </tr>\n </thead>\n <tbody>\n {selected.items.map((item) => (\n <tr key={item.id} className=\"border-b border-border/60\">\n <td className=\"px-3 py-3 font-mono text-xs\">{item.scannedTagId}</td>\n <td className=\"px-3 py-3\">\n {item.assetName ?? item.assetNumber ?? 'Unregistered tag'}\n </td>\n <td className=\"px-3 py-3\">{item.expectedLocation ?? '—'}</td>\n <td className=\"px-3 py-3\">{item.observedLocation ?? '—'}</td>\n <td className=\"px-3 py-3\">\n <span\n className={`rounded-full px-2 py-1 text-xs font-medium ${OUTCOME_TONE[item.outcome]}`}\n >\n {item.outcome}\n </span>\n </td>\n <td className=\"px-3 py-3\">{item.resolutionNotes ?? '—'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {selected.status === 'IN_PROGRESS' && (\n <Button\n className=\"mt-5\"\n onClick={() => void finishAudit()}\n disabled={completeState.loading}\n >\n Complete audit and mark unscanned items missing\n </Button>\n )}\n\n {selected.status === 'COMPLETED' && selected.unresolvedCount > 0 && (\n <div className=\"mt-5 space-y-3 rounded-lg border border-border p-4\">\n <Label htmlFor=\"resolution-notes\">Exception resolution evidence</Label>\n <Textarea\n id=\"resolution-notes\"\n value={resolutionNotes}\n onChange={(event) => setResolutionNotes(event.target.value)}\n placeholder=\"Record who verified the discrepancy and what changed.\"\n />\n <div className=\"flex flex-wrap gap-2\">\n {selected.items\n .filter(\n (item) =>\n ['MISSING', 'MOVED', 'UNEXPECTED'].includes(item.outcome) &&\n !item.resolvedAt\n )\n .map((item) => (\n <Button\n key={item.id}\n variant=\"outline\"\n disabled={!resolutionNotes.trim() || resolveState.loading}\n onClick={() => void resolveException(item, item.outcome === 'MOVED')}\n >\n Resolve {item.scannedTagId}\n {item.outcome === 'MOVED' ? ' and update location' : ''}\n </Button>\n ))}\n </div>\n </div>\n )}\n </GlassCard>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|