@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.
@@ -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":";;;;;;;;;;;;AA6CA,IAAM,IAAe,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgClB,IAAe,CAAG;;;;;;IAMpB,EAAa;GAGX,IAAe,CAAG;;;;;;IAMpB,EAAa;GAGX,IAAiB,CAAG;;;;;;;GASpB,IAAiB,CAAG;;;;;;IAMtB,EAAa;GAGX,IAAqB,CAAG;;;;;;;;GAUxB,KAAe,CAAG;;;;GAMlB,IAA6C;CACjD,SAAS;CACT,SAAS;CACT,SAAS;CACT,OAAO;CACP,YAAY;AACd;AAEA,SAAS,GAAa,GAAuB;CAC3C,OAAO,EACJ,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,UAAU,EAAE;AACzB;AAEA,SAAS,EAAW,GAA8B;CAChD,OAAO,IAAQ,IAAI,KAAK,CAAK,EAAE,eAAe,IAAI;AACpD;AAEA,SAAgB,IAAqB;CACnC,IAAM,EAAE,SAAM,YAAS,UAAO,eAAY,EACxC,CACF,GACM,CAAC,GAAY,KAAiB,EAAwB,IAAI,GAC1D,CAAC,GAAM,KAAW,EAAS,EAAE,GAC7B,CAAC,GAAkB,KAAuB,EAAS,EAAE,GACrD,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAkB,KAAuB,EAAS,EAAE,GACrD,CAAC,GAAiB,KAAsB,EAAS,EAAE,GAEnD,IAAS,GAAM,kBAAkB,CAAC,GAClC,IAAW,SACT,EAAO,MAAM,MAAU,EAAM,OAAO,CAAU,KAAK,EAAO,MAAM,MACtE,CAAC,GAAQ,CAAU,CACrB,GAEM,CAAC,GAAa,KAAe,EAGjC,CAAY,GACR,CAAC,GAAc,KAAa,EAAY,CAAc,GACtD,CAAC,IAAe,MAAiB,EAAY,CAAc,GAC3D,CAAC,IAAa,MAAgB,EAAY,CAAkB,GAC5D,CAAC,IAAa,KAAe,EAAY,EAAY,GAErD,IAAU,YAA2B;EACzC,MAAM,EAAQ;CAChB,GAEM,KAAe,OAAO,MAAoC;EAC9D,EAAM,eAAe;EAUrB,IAAM,KAAU,MATK,EAAY,EAC/B,WAAW,EACT,OAAO;GACL,MAAM,EAAK,KAAK;GAChB,GAAI,EAAiB,KAAK,IAAI,EAAE,kBAAkB,EAAiB,KAAK,EAAE,IAAI,CAAC;GAC/E,GAAI,EAAM,KAAK,IAAI,EAAE,OAAO,EAAM,KAAK,EAAE,IAAI,CAAC;EAChD,EACF,EACF,CAAC,GACsB,MAAM;EACxB,MACL,EAAc,EAAQ,EAAE,GACxB,EAAQ,EAAE,GACV,EAAS,EAAE,GACX,EAAoB,EAAQ,oBAAoB,EAAE,GAClD,MAAM,EAAQ,GACd,EAAO,QACL,0BACA,GAAG,EAAQ,cAAc,8BAC3B;CACF,GAEM,KAAa,OAAO,MAAoC;EAC5D,EAAM,eAAe,GAChB,MACL,MAAM,EAAa,EACjB,WAAW,EACT,OAAO;GACL,SAAS,EAAS;GAClB,OAAO,EAAM,KAAK;GAClB,kBAAkB,EAAiB,KAAK;EAC1C,EACF,EACF,CAAC,GACD,EAAS,EAAE,GACX,MAAM,EAAQ,GACd,EAAO,QACL,kBACA,gEACF;CACF,GAEM,KAAc,YAA2B;EACxC,MACL,MAAM,GAAc,EAAE,WAAW,EAAE,IAAI,EAAS,GAAG,EAAE,CAAC,GACtD,MAAM,EAAQ,GACd,EAAO,QAAQ,mBAAmB,mDAAmD;CACvF,GAEM,KAAmB,OACvB,GACA,MACkB;EAWlB,AAVA,MAAM,GAAY,EAChB,WAAW,EACT,OAAO;GACL,QAAQ,EAAK;GACb,iBAAiB,EAAgB,KAAK;GACtC;EACF,EACF,EACF,CAAC,GACD,MAAM,EAAQ,GACd,EAAO,QACL,wBACA,IACI,+CACA,wBACN;CACF,GAEM,KAAc,YAA2B;EACzC,CAAC,KAAY,CAAC,OAAO,QAAQ,0BAA0B,EAAS,KAAK,GAAG,MAC5E,MAAM,GAAY,EAAE,WAAW,EAAE,IAAI,EAAS,GAAG,EAAE,CAAC,GACpD,EAAc,IAAI,GAClB,MAAM,EAAQ,GACd,EAAO,QAAQ,iBAAiB,+CAA+C;CACjF,GAEM,WAA0B;EACzB,KACL,EACE,kBAAkB,GAAa,EAAS,IAAI,KAAK,EAAS,GAAG,OAC7D;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,GACA,EAAS,MAAM,KAAK,MAAS;GAC3B,EAAS;GACT,EAAS;GACT,EAAS;GACT,EAAK;GACL,EAAK;GACL,EAAK;GACL,EAAK;GACL,EAAK;GACL,EAAK;GACL,EAAK;GACL,EAAK;GACL,EAAK;EACP,CAAC,CACH;CACF;CAEA,IAAI,GAAO,MAAM;CAEjB,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IACE,MAAA;IACA,MAAM;IACN,OAAM;IACN,aAAY;GACb,CAAA;GACD,kBAAC,GAAD,EAAA,UAAa,+IAGA,CAAA;GAEb,kBAAC,GAAD;IAAW,WAAU;cAArB,CACE,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;IACb,CAAA,GACD,kBAAC,QAAD;KACE,WAAU;KACV,WAAW,MAAU,KAAK,GAAa,CAAK;eAF9C;MAIE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBAAa;OAAiB,CAAA,GAC7C,kBAAC,GAAD;QACE,IAAG;QACH,OAAO;QACP,WAAW,MAAU,EAAQ,EAAM,OAAO,KAAK;QAC/C,UAAA;OACD,CAAA,CACE;;MACL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBAAoB;OAAwB,CAAA,GAC3D,kBAAC,GAAD;QACE,IAAG;QACH,OAAO;QACP,WAAW,MAAU,EAAoB,EAAM,OAAO,KAAK;QAC3D,aAAY;OACb,CAAA,CACE;;MACL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBAAc;OAAkB,CAAA,GAC/C,kBAAC,GAAD;QACE,IAAG;QACH,OAAO;QACP,WAAW,MAAU,EAAS,EAAM,OAAO,KAAK;OACjD,CAAA,CACE;;MACL,kBAAC,GAAD;OAAQ,MAAK;OAAS,UAAU,CAAC,EAAK,KAAK,KAAK,EAAY;iBAA5D,CACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,GAAC,uBAC/B;;KACJ;MACG;;GAEX,kBAAC,GAAD;IAAW,WAAU;cAArB,CACE,kBAAC,GAAD;KACE,OAAM;KACN,aAAa,IAAU,aAAa,GAAG,EAAO,OAAO;IACtD,CAAA,GACD,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAO,KAAK,MACX,kBAAC,GAAD;MAEE,SAAS,GAAU,OAAO,EAAM,KAAK,YAAY;MACjD,eAAe;OAEb,AADA,EAAc,EAAM,EAAE,GACtB,EAAoB,EAAM,oBAAoB,EAAE;MAClD;gBANF;OAQG,EAAM;OAAK;OAAI,EAAM,OAAO,QAAQ,KAAK,GAAG;MACvC;QARD,EAAM,EAQL,CACT,GACA,CAAC,KAAW,EAAO,WAAW,KAC7B,kBAAC,KAAD;MAAG,WAAU;gBAA8B;KAAiB,CAAA,CAE3D;MACI;;GAEV,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,OAAM;MAAW,OAAO,EAAS;MAAe,MAAM;KAAS,CAAA;KACzE,kBAAC,GAAD;MAAU,OAAM;MAAU,OAAO,EAAS;MAAc,MAAM;KAAW,CAAA;KACzE,kBAAC,GAAD;MAAU,OAAM;MAAU,OAAO,EAAS;MAAc,MAAM;KAAe,CAAA;KAC7E,kBAAC,GAAD;MAAU,OAAM;MAAU,OAAO,EAAS;MAAc,MAAM;KAAW,CAAA;KACzE,kBAAC,GAAD;MAAU,OAAM;MAAQ,OAAO,EAAS;MAAY,MAAM;KAAS,CAAA;KACnE,kBAAC,GAAD;MAAU,OAAM;MAAa,OAAO,EAAS;MAAiB,MAAM;KAAW,CAAA;KAC/E,kBAAC,GAAD;MAAU,OAAM;MAAa,OAAO,EAAS;MAAiB,MAAM;KAAW,CAAA;IAC5E;OAEL,kBAAC,GAAD;IAAW,WAAU;cAArB;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UAAA;OACE,kBAAC,MAAD;QAAI,WAAU;kBAA2C,EAAS;OAAS,CAAA;OAC3E,kBAAC,KAAD;QAAG,WAAU;kBAAb;SAA2C;SACrC,EAAS;SAAG;SAAa,EAAS,oBAAoB;SAAwB;SAAI;SAC3E,EAAW,EAAS,SAAS;QACvC;;OACF,EAAS,eACR,kBAAC,KAAD;QAAG,WAAU;kBAAb,CAA2C,cAC9B,EAAW,EAAS,WAAW,CACzC;;MAEF,EAAA,CAAA,GACL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAQ,SAAQ;QAAU,SAAS;kBAAnC,CACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,GAAC,aAC/B;WACR,kBAAC,GAAD;QACE,SAAQ;QACR,eAAe,KAAK,GAAY;QAChC,UAAU,EAAY;kBAHxB,CAKE,kBAAC,GAAD,EAAQ,WAAU,eAAgB,CAAA,GAAC,eAC7B;SACL;QACF;;KAEJ,EAAS,WAAW,iBACnB,kBAAC,QAAD;MACE,WAAU;MACV,WAAW,MAAU,KAAK,GAAW,CAAK;gBAF5C;OAIE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAY;QAA2B,CAAA,GACtD,kBAAC,GAAD;SACE,IAAG;SACH,OAAO;SACP,WAAW,MAAU,EAAS,EAAM,OAAO,KAAK;SAChD,UAAA;QACD,CAAA,CACE;;OACL,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAoB;QAAwB,CAAA,GAC3D,kBAAC,GAAD;SACE,IAAG;SACH,OAAO;SACP,WAAW,MAAU,EAAoB,EAAM,OAAO,KAAK;SAC3D,UAAA;QACD,CAAA,CACE;;OACL,kBAAC,GAAD;QACE,WAAU;QACV,MAAK;QACL,UAAU,EAAU,WAAW,CAAC,EAAM,KAAK,KAAK,CAAC,EAAiB,KAAK;kBACxE;OAEO,CAAA;MACJ;;KAGR,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,SAAD;QAAO,WAAU;kBACf,kBAAC,MAAD,EAAA,UAAA;SACE,kBAAC,MAAD;UAAI,WAAU;oBAAY;SAAO,CAAA;SACjC,kBAAC,MAAD;UAAI,WAAU;oBAAY;SAAS,CAAA;SACnC,kBAAC,MAAD;UAAI,WAAU;oBAAY;SAAY,CAAA;SACtC,kBAAC,MAAD;UAAI,WAAU;oBAAY;SAAY,CAAA;SACtC,kBAAC,MAAD;UAAI,WAAU;oBAAY;SAAW,CAAA;SACrC,kBAAC,MAAD;UAAI,WAAU;oBAAY;SAAc,CAAA;QACtC,EAAA,CAAA;OACC,CAAA,GACP,kBAAC,SAAD,EAAA,UACG,EAAS,MAAM,KAAK,MACnB,kBAAC,MAAD;QAAkB,WAAU;kBAA5B;SACE,kBAAC,MAAD;UAAI,WAAU;oBAA+B,EAAK;SAAiB,CAAA;SACnE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAK,aAAa,EAAK,eAAe;SACrC,CAAA;SACJ,kBAAC,MAAD;UAAI,WAAU;oBAAa,EAAK,oBAAoB;SAAQ,CAAA;SAC5D,kBAAC,MAAD;UAAI,WAAU;oBAAa,EAAK,oBAAoB;SAAQ,CAAA;SAC5D,kBAAC,MAAD;UAAI,WAAU;oBACZ,kBAAC,QAAD;WACE,WAAW,8CAA8C,EAAa,EAAK;qBAE1E,EAAK;UACF,CAAA;SACJ,CAAA;SACJ,kBAAC,MAAD;UAAI,WAAU;oBAAa,EAAK,mBAAmB;SAAQ,CAAA;QACzD;UAfK,EAAK,EAeV,CACL,EACI,CAAA,CACF;;KACJ,CAAA;KAEJ,EAAS,WAAW,iBACnB,kBAAC,GAAD;MACE,WAAU;MACV,eAAe,KAAK,GAAY;MAChC,UAAU,GAAc;gBACzB;KAEO,CAAA;KAGT,EAAS,WAAW,eAAe,EAAS,kBAAkB,KAC7D,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,GAAD;QAAO,SAAQ;kBAAmB;OAAoC,CAAA;OACtE,kBAAC,GAAD;QACE,IAAG;QACH,OAAO;QACP,WAAW,MAAU,EAAmB,EAAM,OAAO,KAAK;QAC1D,aAAY;OACb,CAAA;OACD,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAS,MACP,QACE,MACC;SAAC;SAAW;SAAS;QAAY,EAAE,SAAS,EAAK,OAAO,KACxD,CAAC,EAAK,UACV,EACC,KAAK,MACJ,kBAAC,GAAD;SAEE,SAAQ;SACR,UAAU,CAAC,EAAgB,KAAK,KAAK,GAAa;SAClD,eAAe,KAAK,GAAiB,GAAM,EAAK,YAAY,OAAO;mBAJrE;UAKC;UACU,EAAK;UACb,EAAK,YAAY,UAAU,yBAAyB;SAC/C;WAPD,EAAK,EAOJ,CACT;OACA,CAAA;MACF;;IAEE;KACX,EAAA,CAAA;EAED;;AAET"}