@burdenoff/microfe-assethandler 2026.1107.1 → 2026.1107.2
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/components/FieldWorkOrderItem.d.ts +27 -0
- package/dist/assethandler/components/FieldWorkOrderItem.d.ts.map +1 -0
- package/dist/assethandler/components/FieldWorkOrderItem.js +168 -0
- package/dist/assethandler/components/FieldWorkOrderItem.js.map +1 -0
- package/dist/assethandler/hooks/useFieldQueue.d.ts +3 -0
- package/dist/assethandler/hooks/useFieldQueue.d.ts.map +1 -1
- package/dist/assethandler/hooks/useFieldQueue.js +113 -47
- package/dist/assethandler/hooks/useFieldQueue.js.map +1 -1
- package/dist/assethandler/pages/FieldModePage.d.ts +6 -0
- package/dist/assethandler/pages/FieldModePage.d.ts.map +1 -1
- package/dist/assethandler/pages/FieldModePage.js +303 -206
- package/dist/assethandler/pages/FieldModePage.js.map +1 -1
- package/dist/assethandler/utils/fieldQueue.d.ts +37 -3
- package/dist/assethandler/utils/fieldQueue.d.ts.map +1 -1
- package/dist/assethandler/utils/fieldQueue.js +75 -42
- package/dist/assethandler/utils/fieldQueue.js.map +1 -1
- package/dist/assethandler/utils/fieldWorkOrders.d.ts +80 -0
- package/dist/assethandler/utils/fieldWorkOrders.d.ts.map +1 -0
- package/dist/assethandler/utils/fieldWorkOrders.js +109 -0
- package/dist/assethandler/utils/fieldWorkOrders.js.map +1 -0
- package/package.json +1 -1
|
@@ -6,18 +6,20 @@ import { SectionHeader as i } from "../components/SectionHeader.js";
|
|
|
6
6
|
import "../components/index.js";
|
|
7
7
|
import { useTr as a } from "../hooks/useTr.js";
|
|
8
8
|
import { CameraTagScanner as ee } from "../components/CameraTagScanner.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
9
|
+
import { fieldWorkOrderCacheKey as te, loadFieldWorkOrders as ne, saveFieldWorkOrders as re, technicianIdentities as ie, toFieldWorkOrder as ae, workOrdersForAsset as oe } from "../utils/fieldWorkOrders.js";
|
|
10
|
+
import { FieldWorkOrderItem as se } from "../components/FieldWorkOrderItem.js";
|
|
11
|
+
import { FieldQueueFullError as ce, projectedCustody as le, projectedHolder as ue, projectedWorkOrderStatus as de } from "../utils/fieldQueue.js";
|
|
12
|
+
import { browserStorage as o, useFieldQueue as fe } from "../hooks/useFieldQueue.js";
|
|
13
|
+
import { fieldAssetCacheKey as pe, filterFieldAssets as me, findFieldAsset as he, loadFieldAssets as ge, normalizeScannedTag as _e, saveFieldAssets as ve, toFieldAsset as s } from "../utils/fieldAssetCache.js";
|
|
14
|
+
import { useCallback as c, useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
|
|
15
|
+
import { ArrowDownToLine as ye, ArrowUpFromLine as be, Camera as xe, CloudOff as Se, RefreshCw as Ce, ScanLine as we, Smartphone as Te, Trash2 as Ee, Wifi as De, Wrench as Oe } from "lucide-react";
|
|
16
|
+
import { useSearchParams as ke } from "react-router";
|
|
17
|
+
import { gql as p } from "@apollo/client";
|
|
18
|
+
import { useApolloClient as Ae } from "@apollo/client/react";
|
|
19
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
20
|
+
import { Button as g, GlassCard as _, Input as v, Label as y, PagePurpose as je } from "@burdenoff/fe-libs/ui";
|
|
19
21
|
//#region src/assethandler/pages/FieldModePage.tsx
|
|
20
|
-
var
|
|
22
|
+
var Me = p`
|
|
21
23
|
query AssetHandlerFieldAssets {
|
|
22
24
|
assets {
|
|
23
25
|
id
|
|
@@ -30,7 +32,7 @@ var we = f`
|
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
`;
|
|
33
|
-
function
|
|
35
|
+
function b(e) {
|
|
34
36
|
return s({
|
|
35
37
|
id: e.id,
|
|
36
38
|
name: e.name,
|
|
@@ -41,7 +43,19 @@ function y(e) {
|
|
|
41
43
|
status: e.status
|
|
42
44
|
});
|
|
43
45
|
}
|
|
44
|
-
var
|
|
46
|
+
var Ne = p`
|
|
47
|
+
query AssetHandlerFieldWorkOrders($filter: WorkOrderFilterInput, $limit: Int) {
|
|
48
|
+
workOrders(filter: $filter, pagination: { limit: $limit }) {
|
|
49
|
+
id
|
|
50
|
+
title
|
|
51
|
+
status
|
|
52
|
+
priority
|
|
53
|
+
assetId
|
|
54
|
+
assignedTo
|
|
55
|
+
checklist
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
`, Pe = p`
|
|
45
59
|
query AssetHandlerFieldAssetByTag($tagId: String!) {
|
|
46
60
|
assetByTag(tagId: $tagId) {
|
|
47
61
|
id
|
|
@@ -53,7 +67,7 @@ var Te = f`
|
|
|
53
67
|
assignedTo
|
|
54
68
|
}
|
|
55
69
|
}
|
|
56
|
-
`,
|
|
70
|
+
`, Fe = p`
|
|
57
71
|
query AssetHandlerFieldLatestAssignment($assetId: ID!) {
|
|
58
72
|
assetAssignments(assetId: $assetId, pagination: { limit: 1 }) {
|
|
59
73
|
id
|
|
@@ -61,364 +75,447 @@ var Te = f`
|
|
|
61
75
|
assignedTo
|
|
62
76
|
}
|
|
63
77
|
}
|
|
64
|
-
`,
|
|
65
|
-
function
|
|
78
|
+
`, x = "assethandler.field.lastAssignee", Ie = 50;
|
|
79
|
+
function Le() {
|
|
66
80
|
try {
|
|
67
|
-
return o()?.getItem(
|
|
81
|
+
return o()?.getItem(x) ?? "";
|
|
68
82
|
} catch {
|
|
69
83
|
return "";
|
|
70
84
|
}
|
|
71
85
|
}
|
|
72
|
-
function
|
|
86
|
+
function Re(e) {
|
|
73
87
|
try {
|
|
74
|
-
o()?.setItem(
|
|
88
|
+
o()?.setItem(x, e);
|
|
75
89
|
} catch {}
|
|
76
90
|
}
|
|
77
|
-
function
|
|
91
|
+
function S() {
|
|
78
92
|
let { workspaceId: e } = t();
|
|
79
|
-
return /* @__PURE__ */
|
|
93
|
+
return /* @__PURE__ */ m(C, { workspaceId: e }, e || "default");
|
|
80
94
|
}
|
|
81
|
-
function
|
|
82
|
-
let
|
|
95
|
+
function C({ workspaceId: s }) {
|
|
96
|
+
let p = a(), x = Ae(), { currentUser: S } = t(), C = e((e) => e.refetchBootstrap), w = pe(s), [ze] = f(() => ge(o(), w).assets), T = te(s), [E, Be] = f(() => ne(o(), T).workOrders), D = u(() => ie(S), [S]), O = D.join("\0"), [Ve, k] = f(!1), [He, A] = f(""), [j, Ue] = f(""), [M, We] = f(null), [N, Ge] = f(null), [Ke, qe] = f(Le), [P, F] = f(""), [Je, I] = f(!1), Ye = d(null), Xe = d(null), L = d(0), [Ze, Qe] = f(null), R = d(!1), z = d(0), B = d(0);
|
|
83
97
|
l(() => (R.current = !0, () => {
|
|
84
|
-
R.current = !1, z.current += 1;
|
|
98
|
+
R.current = !1, z.current += 1, B.current += 1;
|
|
85
99
|
}), []);
|
|
86
|
-
let
|
|
100
|
+
let V = c(() => {
|
|
101
|
+
if (!R.current) return;
|
|
102
|
+
let e = O ? O.split("\0") : [];
|
|
103
|
+
if (e.length === 0) return;
|
|
104
|
+
B.current += 1;
|
|
105
|
+
let t = B.current;
|
|
106
|
+
x.query({
|
|
107
|
+
query: Ne,
|
|
108
|
+
variables: {
|
|
109
|
+
filter: {
|
|
110
|
+
openOnly: !0,
|
|
111
|
+
assignedToIn: e
|
|
112
|
+
},
|
|
113
|
+
limit: 100
|
|
114
|
+
},
|
|
115
|
+
fetchPolicy: "network-only"
|
|
116
|
+
}).then((e) => {
|
|
117
|
+
if (!R.current || B.current !== t || !e.data?.workOrders) return;
|
|
118
|
+
let n = e.data.workOrders.map(ae);
|
|
119
|
+
Be(n), re(o(), T, n);
|
|
120
|
+
}, () => {});
|
|
121
|
+
}, [
|
|
122
|
+
x,
|
|
123
|
+
O,
|
|
124
|
+
T
|
|
125
|
+
]), H = c(() => {
|
|
87
126
|
if (!R.current) return;
|
|
88
127
|
z.current += 1;
|
|
89
128
|
let e = z.current;
|
|
90
|
-
|
|
91
|
-
query:
|
|
129
|
+
x.query({
|
|
130
|
+
query: Me,
|
|
92
131
|
fetchPolicy: "network-only"
|
|
93
132
|
}).then((t) => {
|
|
94
133
|
if (!R.current || z.current !== e || !t.data?.assets) return;
|
|
95
|
-
let n = t.data.assets.map(
|
|
96
|
-
|
|
134
|
+
let n = t.data.assets.map(b);
|
|
135
|
+
Qe(n), ve(o(), w, n);
|
|
97
136
|
}, () => {});
|
|
98
|
-
}, [
|
|
137
|
+
}, [x, w]), U = c(async (e, t) => {
|
|
99
138
|
let n = {
|
|
100
139
|
checkedOut: e.assignedTo !== "",
|
|
101
140
|
holder: e.assignedTo,
|
|
102
141
|
confirmed: !1
|
|
103
142
|
};
|
|
104
|
-
if (
|
|
105
|
-
let t = await
|
|
106
|
-
query:
|
|
143
|
+
if (Xe.current = e.id, Ge(n), t) try {
|
|
144
|
+
let t = await x.query({
|
|
145
|
+
query: Fe,
|
|
107
146
|
variables: { assetId: e.id },
|
|
108
147
|
fetchPolicy: "network-only"
|
|
109
148
|
});
|
|
110
|
-
if (
|
|
149
|
+
if (Xe.current !== e.id) return;
|
|
111
150
|
let n = t.data?.assetAssignments?.[0];
|
|
112
|
-
|
|
151
|
+
Ge({
|
|
113
152
|
checkedOut: !!n && n.status !== "RETURNED",
|
|
114
153
|
holder: n && n.status !== "RETURNED" ? n.assignedTo : "",
|
|
115
154
|
confirmed: !0
|
|
116
155
|
});
|
|
117
156
|
} catch {}
|
|
118
|
-
}, [
|
|
157
|
+
}, [x]), { queue: W, pending: $e, online: G, syncing: et, sendingId: tt, persisted: nt, enqueue: rt, syncNow: it, remove: at, retry: ot } = fe({
|
|
119
158
|
workspaceId: s,
|
|
120
|
-
client:
|
|
159
|
+
client: x,
|
|
121
160
|
onFlushed: (e) => {
|
|
122
|
-
e.synced.length > 0 && (r.success(
|
|
123
|
-
for (let t of e.rejected) r.error(
|
|
124
|
-
|
|
161
|
+
e.synced.length > 0 && (r.success(p("assethandler.field.synced", "{{count}} field action(s) synced", { count: e.synced.length })), C(), H(), V());
|
|
162
|
+
for (let t of e.rejected) r.error(p("assethandler.field.rejected", "Could not apply action for {{asset}}", { asset: t.assetName }), t.lastError);
|
|
163
|
+
M && U(M, !0);
|
|
125
164
|
}
|
|
126
165
|
});
|
|
127
166
|
l(() => {
|
|
128
|
-
|
|
129
|
-
}, [
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
167
|
+
G && H();
|
|
168
|
+
}, [G, H]), l(() => {
|
|
169
|
+
G && V();
|
|
170
|
+
}, [G, V]);
|
|
171
|
+
let K = Ze ?? ze, q = c((e) => {
|
|
172
|
+
L.current += 1, I(!1), We(e), F(""), U(e, G);
|
|
173
|
+
}, [U, G]), J = c(async (e) => {
|
|
174
|
+
let t = _e(e);
|
|
134
175
|
if (!t) {
|
|
135
|
-
r.warning(
|
|
176
|
+
r.warning(p("assethandler.field.enterTag", "Enter a tag"), p("assethandler.field.enterTagHint", "Scan or type the asset tag to continue."));
|
|
136
177
|
return;
|
|
137
178
|
}
|
|
138
|
-
let n =
|
|
179
|
+
let n = he(K, t);
|
|
139
180
|
if (n) {
|
|
140
|
-
|
|
181
|
+
q(n), A("");
|
|
141
182
|
return;
|
|
142
183
|
}
|
|
143
|
-
if (!
|
|
144
|
-
r.warning(
|
|
184
|
+
if (!G) {
|
|
185
|
+
r.warning(p("assethandler.field.unknownOffline", "Tag not in the offline registry"), p("assethandler.field.unknownOfflineHint", "Reconnect once so this device can refresh its copy of the registry."));
|
|
145
186
|
return;
|
|
146
187
|
}
|
|
147
188
|
L.current += 1;
|
|
148
189
|
let i = L.current, a = () => L.current === i;
|
|
149
|
-
|
|
190
|
+
I(!0);
|
|
150
191
|
try {
|
|
151
|
-
let e = await
|
|
152
|
-
query:
|
|
192
|
+
let e = await x.query({
|
|
193
|
+
query: Pe,
|
|
153
194
|
variables: { tagId: t },
|
|
154
195
|
fetchPolicy: "network-only"
|
|
155
196
|
});
|
|
156
197
|
if (!a()) return;
|
|
157
198
|
let n = e.data?.assetByTag;
|
|
158
199
|
if (!n) {
|
|
159
|
-
r.error(
|
|
200
|
+
r.error(p("assethandler.field.notFound", "No asset found"), p("assethandler.field.notFoundHint", "No asset matches tag \"{{tag}}\".", { tag: t }));
|
|
160
201
|
return;
|
|
161
202
|
}
|
|
162
|
-
|
|
203
|
+
q(b(n)), A("");
|
|
163
204
|
} catch (e) {
|
|
164
205
|
if (!a()) return;
|
|
165
|
-
r.error(
|
|
206
|
+
r.error(p("assethandler.field.lookupFailed", "Tag lookup failed"), e instanceof Error ? e.message : void 0);
|
|
166
207
|
} finally {
|
|
167
|
-
a() &&
|
|
208
|
+
a() && I(!1);
|
|
168
209
|
}
|
|
169
210
|
}, [
|
|
170
|
-
|
|
211
|
+
x,
|
|
212
|
+
K,
|
|
213
|
+
G,
|
|
171
214
|
q,
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
f
|
|
175
|
-
]), [Ue] = xe(), X = Ue.get("tag")?.trim() ?? "", We = u("");
|
|
215
|
+
p
|
|
216
|
+
]), [st] = ke(), Y = st.get("tag")?.trim() ?? "", ct = d("");
|
|
176
217
|
l(() => {
|
|
177
|
-
!
|
|
178
|
-
}, [
|
|
179
|
-
let
|
|
180
|
-
|
|
181
|
-
}, [
|
|
182
|
-
if (!O) return;
|
|
183
|
-
let t = j.trim();
|
|
184
|
-
if (e === "CHECK_OUT" && !t) {
|
|
185
|
-
r.warning(f("assethandler.field.assigneeRequired", "Recipient required"), f("assethandler.field.assigneeRequiredHint", "Enter who is receiving the asset."));
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
218
|
+
!Y || ct.current === Y || (ct.current = Y, J(Y));
|
|
219
|
+
}, [Y, J]);
|
|
220
|
+
let lt = c((e) => {
|
|
221
|
+
k(!1), J(e);
|
|
222
|
+
}, [J]), X = M ? le(W, M.tagId, N?.checkedOut ?? !1) : !1, ut = M ? ue(W, M.tagId, N?.holder ?? "") : "", Z = (e) => {
|
|
188
223
|
try {
|
|
189
|
-
|
|
190
|
-
kind: e,
|
|
191
|
-
tagId: O.tagId,
|
|
192
|
-
assetName: O.name,
|
|
193
|
-
...e === "CHECK_OUT" ? { assignedTo: t } : {},
|
|
194
|
-
...M.trim() ? { notes: M.trim() } : {}
|
|
195
|
-
});
|
|
224
|
+
rt(e);
|
|
196
225
|
} catch (e) {
|
|
197
|
-
if (e instanceof
|
|
198
|
-
r.error(f("assethandler.field.queueFull", "Offline queue is full"), f("assethandler.field.queueFullHint", "Reconnect to sync the queued actions before recording more."));
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
226
|
+
if (e instanceof ce) return r.error(p("assethandler.field.queueFull", "Offline queue is full"), p("assethandler.field.queueFullHint", "Reconnect to sync the queued actions before recording more.")), !1;
|
|
201
227
|
throw e;
|
|
202
228
|
}
|
|
203
|
-
|
|
204
|
-
},
|
|
205
|
-
|
|
229
|
+
return G || r.info(p("assethandler.field.savedOffline", "Saved on this device"), p("assethandler.field.savedOfflineHint", "It will sync automatically when you are back online.")), !0;
|
|
230
|
+
}, dt = (e) => {
|
|
231
|
+
if (!M) return;
|
|
232
|
+
let t = Ke.trim();
|
|
233
|
+
if (e === "CHECK_OUT" && !t) {
|
|
234
|
+
r.warning(p("assethandler.field.assigneeRequired", "Recipient required"), p("assethandler.field.assigneeRequiredHint", "Enter who is receiving the asset."));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
Z({
|
|
238
|
+
kind: e,
|
|
239
|
+
tagId: M.tagId,
|
|
240
|
+
assetName: M.name,
|
|
241
|
+
...e === "CHECK_OUT" ? { assignedTo: t } : {},
|
|
242
|
+
...P.trim() ? { notes: P.trim() } : {}
|
|
243
|
+
}) && (e === "CHECK_OUT" && Re(t), F(""), Ye.current?.focus());
|
|
244
|
+
}, ft = u(() => new Map(K.map((e) => [e.id, e])), [K]), pt = (e) => ({
|
|
245
|
+
tagId: ft.get(e.assetId)?.tagId ?? "",
|
|
246
|
+
assetName: e.title,
|
|
247
|
+
workOrderId: e.id
|
|
248
|
+
}), mt = (e) => {
|
|
249
|
+
Z({
|
|
250
|
+
kind: "WO_START",
|
|
251
|
+
...pt(e)
|
|
252
|
+
});
|
|
253
|
+
}, ht = (e, t) => Z({
|
|
254
|
+
kind: "WO_COMPLETE",
|
|
255
|
+
...pt(e),
|
|
256
|
+
...t.notes ? { notes: t.notes } : {},
|
|
257
|
+
...t.actualCost === void 0 ? {} : { actualCost: t.actualCost },
|
|
258
|
+
checklist: t.checklist
|
|
259
|
+
}), gt = (e, t) => /* @__PURE__ */ m(se, {
|
|
260
|
+
workOrder: e,
|
|
261
|
+
projectedStatus: de(W, e.id, e.status),
|
|
262
|
+
queued: W.some((t) => t.workOrderId === e.id && t.state === "pending"),
|
|
263
|
+
assetName: t ? ft.get(e.assetId)?.name : void 0,
|
|
264
|
+
onStart: mt,
|
|
265
|
+
onComplete: ht
|
|
266
|
+
}, e.id), _t = M ? oe(E, M.id) : [], Q = u(() => me(K, j).slice(0, Ie), [K, j]), $ = (e) => {
|
|
267
|
+
switch (e) {
|
|
268
|
+
case "CHECK_OUT": return p("assethandler.field.kind.checkOut", "Check out");
|
|
269
|
+
case "CHECK_IN": return p("assethandler.field.kind.checkIn", "Check in");
|
|
270
|
+
case "WO_START": return p("assethandler.field.kind.woStart", "Start work");
|
|
271
|
+
case "WO_COMPLETE": return p("assethandler.field.kind.woComplete", "Complete work order");
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
return /* @__PURE__ */ h("div", {
|
|
206
275
|
className: "mx-auto max-w-2xl space-y-4 p-3 sm:p-6",
|
|
207
276
|
children: [
|
|
208
|
-
/* @__PURE__ */
|
|
277
|
+
/* @__PURE__ */ m(i, {
|
|
209
278
|
hero: !0,
|
|
210
|
-
icon:
|
|
211
|
-
title:
|
|
212
|
-
description:
|
|
279
|
+
icon: Te,
|
|
280
|
+
title: p("assethandler.field.title", "Field Mode"),
|
|
281
|
+
description: p("assethandler.field.description", "Scan, check out and check in assets on site, with or without signal")
|
|
213
282
|
}),
|
|
214
|
-
/* @__PURE__ */
|
|
215
|
-
/* @__PURE__ */
|
|
283
|
+
/* @__PURE__ */ m(je, { children: p("assethandler.field.purpose", "Built for the phone in your hand. Scan a tag to open the asset, then check it out or in with one tap. Actions are saved on this device first and sync automatically, so a dead spot never loses a record.") }),
|
|
284
|
+
/* @__PURE__ */ h("div", {
|
|
216
285
|
role: "status",
|
|
217
286
|
"data-testid": "field-connectivity",
|
|
218
|
-
className: n("flex flex-wrap items-center justify-between gap-2 rounded-xl px-3 py-2 text-sm",
|
|
219
|
-
children: [/* @__PURE__ */
|
|
287
|
+
className: n("flex flex-wrap items-center justify-between gap-2 rounded-xl px-3 py-2 text-sm", G ? "bg-status-success-subtle text-status-success-text" : "bg-status-warning-subtle text-status-warning-text"),
|
|
288
|
+
children: [/* @__PURE__ */ h("span", {
|
|
220
289
|
className: "flex items-center gap-2 font-medium",
|
|
221
|
-
children: [
|
|
290
|
+
children: [m(G ? De : Se, {
|
|
222
291
|
className: "h-4 w-4",
|
|
223
292
|
"aria-hidden": "true"
|
|
224
|
-
}),
|
|
225
|
-
}), /* @__PURE__ */
|
|
293
|
+
}), G ? p("assethandler.field.online", "Online") : p("assethandler.field.offline", "Offline — actions are saved on this device")]
|
|
294
|
+
}), /* @__PURE__ */ h("span", {
|
|
226
295
|
className: "flex items-center gap-2",
|
|
227
|
-
children: [/* @__PURE__ */
|
|
296
|
+
children: [/* @__PURE__ */ m("span", {
|
|
228
297
|
"data-testid": "field-pending-count",
|
|
229
|
-
children:
|
|
230
|
-
}),
|
|
298
|
+
children: p("assethandler.field.pending", "{{count}} waiting to sync", { count: $e })
|
|
299
|
+
}), $e > 0 && G ? /* @__PURE__ */ h(g, {
|
|
231
300
|
type: "button",
|
|
232
301
|
size: "sm",
|
|
233
302
|
variant: "outline",
|
|
234
|
-
onClick: () => void
|
|
235
|
-
disabled:
|
|
236
|
-
children: [/* @__PURE__ */
|
|
237
|
-
className: n("h-4 w-4",
|
|
303
|
+
onClick: () => void it(),
|
|
304
|
+
disabled: et,
|
|
305
|
+
children: [/* @__PURE__ */ m(Ce, {
|
|
306
|
+
className: n("h-4 w-4", et && "animate-spin"),
|
|
238
307
|
"aria-hidden": "true"
|
|
239
|
-
}),
|
|
308
|
+
}), p("assethandler.field.syncNow", "Sync now")]
|
|
240
309
|
}) : null]
|
|
241
310
|
})]
|
|
242
311
|
}),
|
|
243
|
-
|
|
312
|
+
nt ? null : /* @__PURE__ */ m("p", {
|
|
244
313
|
role: "alert",
|
|
245
314
|
className: "text-sm text-status-error-text",
|
|
246
|
-
children:
|
|
315
|
+
children: p("assethandler.field.notPersisted", "This browser is not letting the app save data, so queued actions will be lost if you close the page. Stay on this page until they sync.")
|
|
247
316
|
}),
|
|
248
|
-
/* @__PURE__ */
|
|
317
|
+
/* @__PURE__ */ h(_, {
|
|
249
318
|
className: "space-y-3 p-4",
|
|
250
319
|
children: [
|
|
251
|
-
/* @__PURE__ */
|
|
320
|
+
/* @__PURE__ */ h("div", {
|
|
252
321
|
className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
253
|
-
children: [/* @__PURE__ */
|
|
322
|
+
children: [/* @__PURE__ */ m(we, {
|
|
254
323
|
className: "h-4 w-4",
|
|
255
324
|
"aria-hidden": "true"
|
|
256
|
-
}),
|
|
325
|
+
}), p("assethandler.field.scanTitle", "Scan a tag")]
|
|
257
326
|
}),
|
|
258
|
-
|
|
259
|
-
onDetected:
|
|
260
|
-
onClose: () =>
|
|
261
|
-
}) : /* @__PURE__ */
|
|
327
|
+
Ve ? /* @__PURE__ */ m(ee, {
|
|
328
|
+
onDetected: lt,
|
|
329
|
+
onClose: () => k(!1)
|
|
330
|
+
}) : /* @__PURE__ */ h(g, {
|
|
262
331
|
type: "button",
|
|
263
332
|
className: "h-14 w-full text-base",
|
|
264
|
-
onClick: () =>
|
|
265
|
-
children: [/* @__PURE__ */
|
|
333
|
+
onClick: () => k(!0),
|
|
334
|
+
children: [/* @__PURE__ */ m(xe, {
|
|
266
335
|
className: "h-5 w-5",
|
|
267
336
|
"aria-hidden": "true"
|
|
268
|
-
}),
|
|
337
|
+
}), p("assethandler.field.openCamera", "Scan with camera")]
|
|
269
338
|
}),
|
|
270
|
-
/* @__PURE__ */
|
|
339
|
+
/* @__PURE__ */ h("form", {
|
|
271
340
|
className: "flex gap-2",
|
|
272
341
|
onSubmit: (e) => {
|
|
273
|
-
e.preventDefault(),
|
|
342
|
+
e.preventDefault(), J(He);
|
|
274
343
|
},
|
|
275
344
|
children: [
|
|
276
|
-
/* @__PURE__ */
|
|
345
|
+
/* @__PURE__ */ m(y, {
|
|
277
346
|
htmlFor: "field-tag-input",
|
|
278
347
|
className: "sr-only",
|
|
279
|
-
children:
|
|
348
|
+
children: p("assethandler.field.tagLabel", "Asset tag")
|
|
280
349
|
}),
|
|
281
|
-
/* @__PURE__ */
|
|
350
|
+
/* @__PURE__ */ m(v, {
|
|
282
351
|
id: "field-tag-input",
|
|
283
|
-
ref:
|
|
284
|
-
value:
|
|
285
|
-
onChange: (e) =>
|
|
286
|
-
placeholder:
|
|
352
|
+
ref: Ye,
|
|
353
|
+
value: He,
|
|
354
|
+
onChange: (e) => A(e.target.value),
|
|
355
|
+
placeholder: p("assethandler.field.tagPlaceholder", "Type or scan a tag"),
|
|
287
356
|
autoComplete: "off",
|
|
288
357
|
autoCapitalize: "off",
|
|
289
358
|
enterKeyHint: "search",
|
|
290
359
|
className: "h-12 flex-1"
|
|
291
360
|
}),
|
|
292
|
-
/* @__PURE__ */
|
|
361
|
+
/* @__PURE__ */ m(g, {
|
|
293
362
|
type: "submit",
|
|
294
363
|
variant: "outline",
|
|
295
364
|
className: "h-12",
|
|
296
|
-
disabled:
|
|
297
|
-
children:
|
|
365
|
+
disabled: Je,
|
|
366
|
+
children: p("assethandler.field.find", "Find")
|
|
298
367
|
})
|
|
299
368
|
]
|
|
300
369
|
})
|
|
301
370
|
]
|
|
302
371
|
}),
|
|
303
|
-
|
|
372
|
+
M ? /* @__PURE__ */ h(_, {
|
|
304
373
|
className: "space-y-4 p-4",
|
|
305
374
|
"data-testid": "field-selected-asset",
|
|
306
375
|
children: [
|
|
307
|
-
/* @__PURE__ */
|
|
376
|
+
/* @__PURE__ */ h("div", {
|
|
308
377
|
className: "flex items-start justify-between gap-3",
|
|
309
|
-
children: [/* @__PURE__ */
|
|
378
|
+
children: [/* @__PURE__ */ h("div", {
|
|
310
379
|
className: "min-w-0",
|
|
311
|
-
children: [/* @__PURE__ */
|
|
380
|
+
children: [/* @__PURE__ */ m("h2", {
|
|
312
381
|
className: "truncate text-lg font-semibold text-text-primary",
|
|
313
|
-
children:
|
|
314
|
-
}), /* @__PURE__ */
|
|
382
|
+
children: M.name
|
|
383
|
+
}), /* @__PURE__ */ h("p", {
|
|
315
384
|
className: "truncate text-xs text-text-secondary",
|
|
316
|
-
children: [
|
|
385
|
+
children: [p("assethandler.field.tagValue", "Tag {{tag}}", { tag: M.tagId }), M.location ? ` · ${M.location}` : ""]
|
|
317
386
|
})]
|
|
318
|
-
}), /* @__PURE__ */
|
|
387
|
+
}), /* @__PURE__ */ m("span", {
|
|
319
388
|
"data-testid": "field-custody",
|
|
320
|
-
className: n("shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium",
|
|
321
|
-
children:
|
|
389
|
+
className: n("shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium", X ? "bg-status-warning-subtle text-status-warning-text" : "bg-status-success-subtle text-status-success-text"),
|
|
390
|
+
children: X ? p("assethandler.field.checkedOut", "Checked out") : p("assethandler.field.available", "Available")
|
|
322
391
|
})]
|
|
323
392
|
}),
|
|
324
|
-
|
|
393
|
+
ut && X ? /* @__PURE__ */ m("p", {
|
|
325
394
|
className: "text-sm text-text-secondary",
|
|
326
|
-
children:
|
|
395
|
+
children: p("assethandler.field.heldBy", "Held by {{holder}}", { holder: ut })
|
|
327
396
|
}) : null,
|
|
328
|
-
|
|
397
|
+
N && !N.confirmed ? /* @__PURE__ */ m("p", {
|
|
329
398
|
className: "text-xs text-text-secondary",
|
|
330
|
-
children:
|
|
399
|
+
children: p("assethandler.field.unconfirmed", "Custody shown from this device’s last sync; the server confirms it when the action syncs.")
|
|
331
400
|
}) : null,
|
|
332
|
-
|
|
401
|
+
X ? null : /* @__PURE__ */ h("div", {
|
|
333
402
|
className: "space-y-1",
|
|
334
|
-
children: [/* @__PURE__ */
|
|
403
|
+
children: [/* @__PURE__ */ m(y, {
|
|
335
404
|
htmlFor: "field-assignee",
|
|
336
|
-
children:
|
|
337
|
-
}), /* @__PURE__ */
|
|
405
|
+
children: p("assethandler.field.assignee", "Checking out to")
|
|
406
|
+
}), /* @__PURE__ */ m(v, {
|
|
338
407
|
id: "field-assignee",
|
|
339
|
-
value:
|
|
340
|
-
onChange: (e) =>
|
|
341
|
-
placeholder:
|
|
408
|
+
value: Ke,
|
|
409
|
+
onChange: (e) => qe(e.target.value),
|
|
410
|
+
placeholder: S?.email ?? "name@company.com",
|
|
342
411
|
autoComplete: "email",
|
|
343
412
|
className: "h-12"
|
|
344
413
|
})]
|
|
345
414
|
}),
|
|
346
|
-
/* @__PURE__ */
|
|
415
|
+
/* @__PURE__ */ h("div", {
|
|
347
416
|
className: "space-y-1",
|
|
348
|
-
children: [/* @__PURE__ */
|
|
417
|
+
children: [/* @__PURE__ */ m(y, {
|
|
349
418
|
htmlFor: "field-notes",
|
|
350
|
-
children:
|
|
351
|
-
}), /* @__PURE__ */
|
|
419
|
+
children: p("assethandler.field.notes", "Notes (optional)")
|
|
420
|
+
}), /* @__PURE__ */ m(v, {
|
|
352
421
|
id: "field-notes",
|
|
353
|
-
value:
|
|
354
|
-
onChange: (e) =>
|
|
355
|
-
placeholder:
|
|
422
|
+
value: P,
|
|
423
|
+
onChange: (e) => F(e.target.value),
|
|
424
|
+
placeholder: p("assethandler.field.notesPlaceholder", "Condition, location, job…"),
|
|
356
425
|
className: "h-12"
|
|
357
426
|
})]
|
|
358
427
|
}),
|
|
359
|
-
/* @__PURE__ */
|
|
428
|
+
/* @__PURE__ */ h("div", {
|
|
360
429
|
className: "grid grid-cols-2 gap-3",
|
|
361
|
-
children: [/* @__PURE__ */
|
|
430
|
+
children: [/* @__PURE__ */ h(g, {
|
|
362
431
|
type: "button",
|
|
363
432
|
className: "h-14 text-base",
|
|
364
|
-
variant:
|
|
365
|
-
onClick: () =>
|
|
366
|
-
children: [/* @__PURE__ */
|
|
433
|
+
variant: X ? "outline" : "default",
|
|
434
|
+
onClick: () => dt("CHECK_OUT"),
|
|
435
|
+
children: [/* @__PURE__ */ m(be, {
|
|
367
436
|
className: "h-5 w-5",
|
|
368
437
|
"aria-hidden": "true"
|
|
369
438
|
}), $("CHECK_OUT")]
|
|
370
|
-
}), /* @__PURE__ */
|
|
439
|
+
}), /* @__PURE__ */ h(g, {
|
|
371
440
|
type: "button",
|
|
372
441
|
className: "h-14 text-base",
|
|
373
|
-
variant:
|
|
374
|
-
onClick: () =>
|
|
375
|
-
children: [/* @__PURE__ */
|
|
442
|
+
variant: X ? "default" : "outline",
|
|
443
|
+
onClick: () => dt("CHECK_IN"),
|
|
444
|
+
children: [/* @__PURE__ */ m(ye, {
|
|
376
445
|
className: "h-5 w-5",
|
|
377
446
|
"aria-hidden": "true"
|
|
378
447
|
}), $("CHECK_IN")]
|
|
379
448
|
})]
|
|
380
|
-
})
|
|
449
|
+
}),
|
|
450
|
+
_t.length > 0 ? /* @__PURE__ */ h("div", {
|
|
451
|
+
className: "space-y-2",
|
|
452
|
+
"data-testid": "field-asset-work-orders",
|
|
453
|
+
children: [/* @__PURE__ */ m("h3", {
|
|
454
|
+
className: "text-sm font-semibold text-text-primary",
|
|
455
|
+
children: p("assethandler.field.wo.forAsset", "Your work orders on this asset")
|
|
456
|
+
}), /* @__PURE__ */ m("ul", {
|
|
457
|
+
className: "space-y-2",
|
|
458
|
+
children: _t.map((e) => gt(e, !1))
|
|
459
|
+
})]
|
|
460
|
+
}) : null
|
|
381
461
|
]
|
|
382
462
|
}) : null,
|
|
383
|
-
|
|
463
|
+
/* @__PURE__ */ h(_, {
|
|
464
|
+
className: "space-y-3 p-4",
|
|
465
|
+
"data-testid": "field-work-orders",
|
|
466
|
+
children: [/* @__PURE__ */ h("h2", {
|
|
467
|
+
className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
468
|
+
children: [/* @__PURE__ */ m(Oe, {
|
|
469
|
+
className: "h-4 w-4",
|
|
470
|
+
"aria-hidden": "true"
|
|
471
|
+
}), p("assethandler.field.wo.title", "My open work orders")]
|
|
472
|
+
}), E.length === 0 ? /* @__PURE__ */ m("p", {
|
|
473
|
+
className: "py-2 text-center text-sm text-text-secondary",
|
|
474
|
+
children: D.length === 0 ? p("assethandler.field.wo.noIdentity", "Sign in to see the work orders assigned to you.") : p("assethandler.field.wo.empty", "No open work orders are assigned to you. Open this page while online to refresh them.")
|
|
475
|
+
}) : /* @__PURE__ */ m("ul", {
|
|
476
|
+
className: "space-y-2",
|
|
477
|
+
children: E.map((e) => gt(e, !0))
|
|
478
|
+
})]
|
|
479
|
+
}),
|
|
480
|
+
W.length > 0 ? /* @__PURE__ */ h(_, {
|
|
384
481
|
className: "space-y-2 p-4",
|
|
385
482
|
"data-testid": "field-queue",
|
|
386
|
-
children: [/* @__PURE__ */
|
|
483
|
+
children: [/* @__PURE__ */ m("h2", {
|
|
387
484
|
className: "text-sm font-semibold text-text-primary",
|
|
388
|
-
children:
|
|
389
|
-
}), /* @__PURE__ */
|
|
485
|
+
children: p("assethandler.field.queueTitle", "On this device")
|
|
486
|
+
}), /* @__PURE__ */ m("ul", {
|
|
390
487
|
className: "divide-y divide-border-seam",
|
|
391
|
-
children:
|
|
488
|
+
children: W.map((e) => /* @__PURE__ */ h("li", {
|
|
392
489
|
className: "flex items-center justify-between gap-3 py-2",
|
|
393
|
-
children: [/* @__PURE__ */
|
|
490
|
+
children: [/* @__PURE__ */ h("div", {
|
|
394
491
|
className: "min-w-0",
|
|
395
|
-
children: [/* @__PURE__ */
|
|
492
|
+
children: [/* @__PURE__ */ h("p", {
|
|
396
493
|
className: "truncate text-sm text-text-primary",
|
|
397
494
|
children: [
|
|
398
495
|
$(e.kind),
|
|
399
496
|
" · ",
|
|
400
497
|
e.assetName
|
|
401
498
|
]
|
|
402
|
-
}), /* @__PURE__ */
|
|
499
|
+
}), /* @__PURE__ */ m("p", {
|
|
403
500
|
className: n("truncate text-xs", e.state === "rejected" ? "text-status-error-text" : "text-text-secondary"),
|
|
404
|
-
children: e.state === "rejected" ? e.lastError ??
|
|
501
|
+
children: e.state === "rejected" ? e.lastError ?? p("assethandler.field.refused", "Refused by the server") : e.id === tt ? p("assethandler.field.sending", "Sending…") : new Date(e.scannedAt).toLocaleString()
|
|
405
502
|
})]
|
|
406
|
-
}), /* @__PURE__ */
|
|
503
|
+
}), /* @__PURE__ */ h("div", {
|
|
407
504
|
className: "flex shrink-0 gap-1",
|
|
408
|
-
children: [e.state === "rejected" ? /* @__PURE__ */
|
|
505
|
+
children: [e.state === "rejected" ? /* @__PURE__ */ m(g, {
|
|
409
506
|
type: "button",
|
|
410
507
|
size: "sm",
|
|
411
508
|
variant: "outline",
|
|
412
|
-
onClick: () =>
|
|
413
|
-
children:
|
|
414
|
-
}) : null, /* @__PURE__ */
|
|
509
|
+
onClick: () => ot(e.id),
|
|
510
|
+
children: p("assethandler.field.retry", "Retry")
|
|
511
|
+
}) : null, /* @__PURE__ */ m(g, {
|
|
415
512
|
type: "button",
|
|
416
513
|
size: "icon",
|
|
417
514
|
variant: "ghost",
|
|
418
|
-
onClick: () =>
|
|
419
|
-
disabled: e.id ===
|
|
420
|
-
"aria-label":
|
|
421
|
-
children: /* @__PURE__ */
|
|
515
|
+
onClick: () => at(e.id),
|
|
516
|
+
disabled: e.id === tt,
|
|
517
|
+
"aria-label": p("assethandler.field.discard", "Discard queued action"),
|
|
518
|
+
children: /* @__PURE__ */ m(Ee, {
|
|
422
519
|
className: "h-4 w-4",
|
|
423
520
|
"aria-hidden": "true"
|
|
424
521
|
})
|
|
@@ -427,41 +524,41 @@ function S({ workspaceId: s }) {
|
|
|
427
524
|
}, e.id))
|
|
428
525
|
})]
|
|
429
526
|
}) : null,
|
|
430
|
-
/* @__PURE__ */
|
|
527
|
+
/* @__PURE__ */ h(_, {
|
|
431
528
|
className: "space-y-3 p-4",
|
|
432
529
|
children: [
|
|
433
|
-
/* @__PURE__ */
|
|
530
|
+
/* @__PURE__ */ m(y, {
|
|
434
531
|
htmlFor: "field-search",
|
|
435
532
|
className: "text-sm font-semibold",
|
|
436
|
-
children:
|
|
533
|
+
children: p("assethandler.field.browse", "Browse assets")
|
|
437
534
|
}),
|
|
438
|
-
/* @__PURE__ */
|
|
535
|
+
/* @__PURE__ */ m(v, {
|
|
439
536
|
id: "field-search",
|
|
440
|
-
value:
|
|
441
|
-
onChange: (e) =>
|
|
442
|
-
placeholder:
|
|
537
|
+
value: j,
|
|
538
|
+
onChange: (e) => Ue(e.target.value),
|
|
539
|
+
placeholder: p("assethandler.field.searchPlaceholder", "Name, tag, location or holder"),
|
|
443
540
|
className: "h-12"
|
|
444
541
|
}),
|
|
445
|
-
Q.length === 0 ? /* @__PURE__ */
|
|
542
|
+
Q.length === 0 ? /* @__PURE__ */ m("p", {
|
|
446
543
|
className: "py-4 text-center text-sm text-text-secondary",
|
|
447
|
-
children:
|
|
448
|
-
}) : /* @__PURE__ */
|
|
544
|
+
children: K.length === 0 ? p("assethandler.field.noAssets", "No assets on this device yet. Open this page once while online to load the registry.") : p("assethandler.field.noMatches", "No assets match your search.")
|
|
545
|
+
}) : /* @__PURE__ */ m("ul", {
|
|
449
546
|
className: "space-y-2",
|
|
450
547
|
"data-testid": "field-asset-list",
|
|
451
|
-
children: Q.map((e) => /* @__PURE__ */
|
|
548
|
+
children: Q.map((e) => /* @__PURE__ */ m("li", { children: /* @__PURE__ */ h("button", {
|
|
452
549
|
type: "button",
|
|
453
|
-
onClick: () =>
|
|
454
|
-
className: n("flex min-h-14 w-full items-center justify-between gap-3 rounded-xl border border-border-seam px-3 py-2 text-left transition-colors hover:bg-bg-sunken",
|
|
455
|
-
children: [/* @__PURE__ */
|
|
550
|
+
onClick: () => q(e),
|
|
551
|
+
className: n("flex min-h-14 w-full items-center justify-between gap-3 rounded-xl border border-border-seam px-3 py-2 text-left transition-colors hover:bg-bg-sunken", M?.id === e.id && "border-action-primary-bg"),
|
|
552
|
+
children: [/* @__PURE__ */ h("span", {
|
|
456
553
|
className: "min-w-0",
|
|
457
|
-
children: [/* @__PURE__ */
|
|
554
|
+
children: [/* @__PURE__ */ m("span", {
|
|
458
555
|
className: "block truncate text-sm font-medium text-text-primary",
|
|
459
556
|
children: e.name
|
|
460
|
-
}), /* @__PURE__ */
|
|
557
|
+
}), /* @__PURE__ */ h("span", {
|
|
461
558
|
className: "block truncate text-xs text-text-secondary",
|
|
462
559
|
children: [e.assetTag || e.tagId, e.location ? ` · ${e.location}` : ""]
|
|
463
560
|
})]
|
|
464
|
-
}), e.assignedTo ? /* @__PURE__ */
|
|
561
|
+
}), e.assignedTo ? /* @__PURE__ */ m("span", {
|
|
465
562
|
className: "max-w-[40%] shrink-0 truncate rounded-full bg-status-warning-subtle px-2 py-0.5 text-[11px] text-status-warning-text",
|
|
466
563
|
children: e.assignedTo
|
|
467
564
|
}) : null]
|
|
@@ -473,6 +570,6 @@ function S({ workspaceId: s }) {
|
|
|
473
570
|
});
|
|
474
571
|
}
|
|
475
572
|
//#endregion
|
|
476
|
-
export {
|
|
573
|
+
export { S as FieldModePage };
|
|
477
574
|
|
|
478
575
|
//# sourceMappingURL=FieldModePage.js.map
|