@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.
@@ -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 { FieldQueueFullError as te, projectedCustody as ne, projectedHolder as re } from "../utils/fieldQueue.js";
10
- import { browserStorage as o, useFieldQueue as ie } from "../hooks/useFieldQueue.js";
11
- import { fieldAssetCacheKey as ae, filterFieldAssets as oe, findFieldAsset as se, loadFieldAssets as ce, normalizeScannedTag as le, saveFieldAssets as ue, toFieldAsset as s } from "../utils/fieldAssetCache.js";
12
- import { useCallback as c, useEffect as l, useMemo as de, useRef as u, useState as d } from "react";
13
- import { ArrowDownToLine as fe, ArrowUpFromLine as pe, Camera as me, CloudOff as he, RefreshCw as ge, ScanLine as _e, Smartphone as ve, Trash2 as ye, Wifi as be } from "lucide-react";
14
- import { useSearchParams as xe } from "react-router";
15
- import { gql as f } from "@apollo/client";
16
- import { useApolloClient as Se } from "@apollo/client/react";
17
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
18
- import { Button as h, GlassCard as g, Input as _, Label as v, PagePurpose as Ce } from "@burdenoff/fe-libs/ui";
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 we = f`
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 y(e) {
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 Te = f`
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
- `, Ee = f`
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
- `, b = "assethandler.field.lastAssignee", De = 50;
65
- function Oe() {
78
+ `, x = "assethandler.field.lastAssignee", Ie = 50;
79
+ function Le() {
66
80
  try {
67
- return o()?.getItem(b) ?? "";
81
+ return o()?.getItem(x) ?? "";
68
82
  } catch {
69
83
  return "";
70
84
  }
71
85
  }
72
- function ke(e) {
86
+ function Re(e) {
73
87
  try {
74
- o()?.setItem(b, e);
88
+ o()?.setItem(x, e);
75
89
  } catch {}
76
90
  }
77
- function x() {
91
+ function S() {
78
92
  let { workspaceId: e } = t();
79
- return /* @__PURE__ */ p(S, { workspaceId: e }, e || "default");
93
+ return /* @__PURE__ */ m(C, { workspaceId: e }, e || "default");
80
94
  }
81
- function S({ workspaceId: s }) {
82
- let f = a(), b = Se(), { currentUser: x } = t(), S = e((e) => e.refetchBootstrap), C = ae(s), [Ae] = d(() => ce(o(), C).assets), [je, w] = d(!1), [T, E] = d(""), [D, Me] = d(""), [O, Ne] = d(null), [k, A] = d(null), [j, Pe] = d(Oe), [M, N] = d(""), [Fe, P] = d(!1), F = u(null), I = u(null), L = u(0), [Ie, Le] = d(null), R = u(!1), z = u(0);
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 B = c(() => {
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
- b.query({
91
- query: we,
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(y);
96
- Le(n), ue(o(), C, n);
134
+ let n = t.data.assets.map(b);
135
+ Qe(n), ve(o(), w, n);
97
136
  }, () => {});
98
- }, [b, C]), V = c(async (e, t) => {
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 (I.current = e.id, A(n), t) try {
105
- let t = await b.query({
106
- query: Ee,
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 (I.current !== e.id) return;
149
+ if (Xe.current !== e.id) return;
111
150
  let n = t.data?.assetAssignments?.[0];
112
- A({
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
- }, [b]), { queue: H, pending: U, online: W, syncing: G, sendingId: K, persisted: Re, enqueue: ze, syncNow: Be, remove: Ve, retry: He } = ie({
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: b,
159
+ client: x,
121
160
  onFlushed: (e) => {
122
- e.synced.length > 0 && (r.success(f("assethandler.field.synced", "{{count}} field action(s) synced", { count: e.synced.length })), S(), B());
123
- for (let t of e.rejected) r.error(f("assethandler.field.rejected", "Could not apply action for {{asset}}", { asset: t.assetName }), t.lastError);
124
- O && V(O, !0);
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
- W && B();
129
- }, [W, B]);
130
- let q = Ie ?? Ae, J = c((e) => {
131
- L.current += 1, P(!1), Ne(e), N(""), V(e, W);
132
- }, [V, W]), Y = c(async (e) => {
133
- let t = le(e);
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(f("assethandler.field.enterTag", "Enter a tag"), f("assethandler.field.enterTagHint", "Scan or type the asset tag to continue."));
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 = se(q, t);
179
+ let n = he(K, t);
139
180
  if (n) {
140
- J(n), E("");
181
+ q(n), A("");
141
182
  return;
142
183
  }
143
- if (!W) {
144
- r.warning(f("assethandler.field.unknownOffline", "Tag not in the offline registry"), f("assethandler.field.unknownOfflineHint", "Reconnect once so this device can refresh its copy of the registry."));
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
- P(!0);
190
+ I(!0);
150
191
  try {
151
- let e = await b.query({
152
- query: Te,
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(f("assethandler.field.notFound", "No asset found"), f("assethandler.field.notFoundHint", "No asset matches tag \"{{tag}}\".", { tag: t }));
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
- J(y(n)), E("");
203
+ q(b(n)), A("");
163
204
  } catch (e) {
164
205
  if (!a()) return;
165
- r.error(f("assethandler.field.lookupFailed", "Tag lookup failed"), e instanceof Error ? e.message : void 0);
206
+ r.error(p("assethandler.field.lookupFailed", "Tag lookup failed"), e instanceof Error ? e.message : void 0);
166
207
  } finally {
167
- a() && P(!1);
208
+ a() && I(!1);
168
209
  }
169
210
  }, [
170
- b,
211
+ x,
212
+ K,
213
+ G,
171
214
  q,
172
- W,
173
- J,
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
- !X || We.current === X || (We.current = X, Y(X));
178
- }, [X, Y]);
179
- let Ge = c((e) => {
180
- w(!1), Y(e);
181
- }, [Y]), Z = O ? ne(H, O.tagId, k?.checkedOut ?? !1) : !1, Ke = O ? re(H, O.tagId, k?.holder ?? "") : "", qe = (e) => {
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
- ze({
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 te) {
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
- e === "CHECK_OUT" && ke(t), N(""), W || r.info(f("assethandler.field.savedOffline", "Saved on this device"), f("assethandler.field.savedOfflineHint", "It will sync automatically when you are back online.")), F.current?.focus();
204
- }, Q = de(() => oe(q, D).slice(0, De), [q, D]), $ = (e) => e === "CHECK_OUT" ? f("assethandler.field.kind.checkOut", "Check out") : f("assethandler.field.kind.checkIn", "Check in");
205
- return /* @__PURE__ */ m("div", {
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__ */ p(i, {
277
+ /* @__PURE__ */ m(i, {
209
278
  hero: !0,
210
- icon: ve,
211
- title: f("assethandler.field.title", "Field Mode"),
212
- description: f("assethandler.field.description", "Scan, check out and check in assets on site, with or without signal")
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__ */ p(Ce, { children: f("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.") }),
215
- /* @__PURE__ */ m("div", {
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", W ? "bg-status-success-subtle text-status-success-text" : "bg-status-warning-subtle text-status-warning-text"),
219
- children: [/* @__PURE__ */ m("span", {
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: [p(W ? be : he, {
290
+ children: [m(G ? De : Se, {
222
291
  className: "h-4 w-4",
223
292
  "aria-hidden": "true"
224
- }), W ? f("assethandler.field.online", "Online") : f("assethandler.field.offline", "Offline — actions are saved on this device")]
225
- }), /* @__PURE__ */ m("span", {
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__ */ p("span", {
296
+ children: [/* @__PURE__ */ m("span", {
228
297
  "data-testid": "field-pending-count",
229
- children: f("assethandler.field.pending", "{{count}} waiting to sync", { count: U })
230
- }), U > 0 && W ? /* @__PURE__ */ m(h, {
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 Be(),
235
- disabled: G,
236
- children: [/* @__PURE__ */ p(ge, {
237
- className: n("h-4 w-4", G && "animate-spin"),
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
- }), f("assethandler.field.syncNow", "Sync now")]
308
+ }), p("assethandler.field.syncNow", "Sync now")]
240
309
  }) : null]
241
310
  })]
242
311
  }),
243
- Re ? null : /* @__PURE__ */ p("p", {
312
+ nt ? null : /* @__PURE__ */ m("p", {
244
313
  role: "alert",
245
314
  className: "text-sm text-status-error-text",
246
- children: f("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.")
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__ */ m(g, {
317
+ /* @__PURE__ */ h(_, {
249
318
  className: "space-y-3 p-4",
250
319
  children: [
251
- /* @__PURE__ */ m("div", {
320
+ /* @__PURE__ */ h("div", {
252
321
  className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
253
- children: [/* @__PURE__ */ p(_e, {
322
+ children: [/* @__PURE__ */ m(we, {
254
323
  className: "h-4 w-4",
255
324
  "aria-hidden": "true"
256
- }), f("assethandler.field.scanTitle", "Scan a tag")]
325
+ }), p("assethandler.field.scanTitle", "Scan a tag")]
257
326
  }),
258
- je ? /* @__PURE__ */ p(ee, {
259
- onDetected: Ge,
260
- onClose: () => w(!1)
261
- }) : /* @__PURE__ */ m(h, {
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: () => w(!0),
265
- children: [/* @__PURE__ */ p(me, {
333
+ onClick: () => k(!0),
334
+ children: [/* @__PURE__ */ m(xe, {
266
335
  className: "h-5 w-5",
267
336
  "aria-hidden": "true"
268
- }), f("assethandler.field.openCamera", "Scan with camera")]
337
+ }), p("assethandler.field.openCamera", "Scan with camera")]
269
338
  }),
270
- /* @__PURE__ */ m("form", {
339
+ /* @__PURE__ */ h("form", {
271
340
  className: "flex gap-2",
272
341
  onSubmit: (e) => {
273
- e.preventDefault(), Y(T);
342
+ e.preventDefault(), J(He);
274
343
  },
275
344
  children: [
276
- /* @__PURE__ */ p(v, {
345
+ /* @__PURE__ */ m(y, {
277
346
  htmlFor: "field-tag-input",
278
347
  className: "sr-only",
279
- children: f("assethandler.field.tagLabel", "Asset tag")
348
+ children: p("assethandler.field.tagLabel", "Asset tag")
280
349
  }),
281
- /* @__PURE__ */ p(_, {
350
+ /* @__PURE__ */ m(v, {
282
351
  id: "field-tag-input",
283
- ref: F,
284
- value: T,
285
- onChange: (e) => E(e.target.value),
286
- placeholder: f("assethandler.field.tagPlaceholder", "Type or scan a tag"),
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__ */ p(h, {
361
+ /* @__PURE__ */ m(g, {
293
362
  type: "submit",
294
363
  variant: "outline",
295
364
  className: "h-12",
296
- disabled: Fe,
297
- children: f("assethandler.field.find", "Find")
365
+ disabled: Je,
366
+ children: p("assethandler.field.find", "Find")
298
367
  })
299
368
  ]
300
369
  })
301
370
  ]
302
371
  }),
303
- O ? /* @__PURE__ */ m(g, {
372
+ M ? /* @__PURE__ */ h(_, {
304
373
  className: "space-y-4 p-4",
305
374
  "data-testid": "field-selected-asset",
306
375
  children: [
307
- /* @__PURE__ */ m("div", {
376
+ /* @__PURE__ */ h("div", {
308
377
  className: "flex items-start justify-between gap-3",
309
- children: [/* @__PURE__ */ m("div", {
378
+ children: [/* @__PURE__ */ h("div", {
310
379
  className: "min-w-0",
311
- children: [/* @__PURE__ */ p("h2", {
380
+ children: [/* @__PURE__ */ m("h2", {
312
381
  className: "truncate text-lg font-semibold text-text-primary",
313
- children: O.name
314
- }), /* @__PURE__ */ m("p", {
382
+ children: M.name
383
+ }), /* @__PURE__ */ h("p", {
315
384
  className: "truncate text-xs text-text-secondary",
316
- children: [f("assethandler.field.tagValue", "Tag {{tag}}", { tag: O.tagId }), O.location ? ` · ${O.location}` : ""]
385
+ children: [p("assethandler.field.tagValue", "Tag {{tag}}", { tag: M.tagId }), M.location ? ` · ${M.location}` : ""]
317
386
  })]
318
- }), /* @__PURE__ */ p("span", {
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", Z ? "bg-status-warning-subtle text-status-warning-text" : "bg-status-success-subtle text-status-success-text"),
321
- children: Z ? f("assethandler.field.checkedOut", "Checked out") : f("assethandler.field.available", "Available")
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
- Ke && Z ? /* @__PURE__ */ p("p", {
393
+ ut && X ? /* @__PURE__ */ m("p", {
325
394
  className: "text-sm text-text-secondary",
326
- children: f("assethandler.field.heldBy", "Held by {{holder}}", { holder: Ke })
395
+ children: p("assethandler.field.heldBy", "Held by {{holder}}", { holder: ut })
327
396
  }) : null,
328
- k && !k.confirmed ? /* @__PURE__ */ p("p", {
397
+ N && !N.confirmed ? /* @__PURE__ */ m("p", {
329
398
  className: "text-xs text-text-secondary",
330
- children: f("assethandler.field.unconfirmed", "Custody shown from this device’s last sync; the server confirms it when the action syncs.")
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
- Z ? null : /* @__PURE__ */ m("div", {
401
+ X ? null : /* @__PURE__ */ h("div", {
333
402
  className: "space-y-1",
334
- children: [/* @__PURE__ */ p(v, {
403
+ children: [/* @__PURE__ */ m(y, {
335
404
  htmlFor: "field-assignee",
336
- children: f("assethandler.field.assignee", "Checking out to")
337
- }), /* @__PURE__ */ p(_, {
405
+ children: p("assethandler.field.assignee", "Checking out to")
406
+ }), /* @__PURE__ */ m(v, {
338
407
  id: "field-assignee",
339
- value: j,
340
- onChange: (e) => Pe(e.target.value),
341
- placeholder: x?.email ?? "name@company.com",
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__ */ m("div", {
415
+ /* @__PURE__ */ h("div", {
347
416
  className: "space-y-1",
348
- children: [/* @__PURE__ */ p(v, {
417
+ children: [/* @__PURE__ */ m(y, {
349
418
  htmlFor: "field-notes",
350
- children: f("assethandler.field.notes", "Notes (optional)")
351
- }), /* @__PURE__ */ p(_, {
419
+ children: p("assethandler.field.notes", "Notes (optional)")
420
+ }), /* @__PURE__ */ m(v, {
352
421
  id: "field-notes",
353
- value: M,
354
- onChange: (e) => N(e.target.value),
355
- placeholder: f("assethandler.field.notesPlaceholder", "Condition, location, job…"),
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__ */ m("div", {
428
+ /* @__PURE__ */ h("div", {
360
429
  className: "grid grid-cols-2 gap-3",
361
- children: [/* @__PURE__ */ m(h, {
430
+ children: [/* @__PURE__ */ h(g, {
362
431
  type: "button",
363
432
  className: "h-14 text-base",
364
- variant: Z ? "outline" : "default",
365
- onClick: () => qe("CHECK_OUT"),
366
- children: [/* @__PURE__ */ p(pe, {
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__ */ m(h, {
439
+ }), /* @__PURE__ */ h(g, {
371
440
  type: "button",
372
441
  className: "h-14 text-base",
373
- variant: Z ? "default" : "outline",
374
- onClick: () => qe("CHECK_IN"),
375
- children: [/* @__PURE__ */ p(fe, {
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
- H.length > 0 ? /* @__PURE__ */ m(g, {
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__ */ p("h2", {
483
+ children: [/* @__PURE__ */ m("h2", {
387
484
  className: "text-sm font-semibold text-text-primary",
388
- children: f("assethandler.field.queueTitle", "On this device")
389
- }), /* @__PURE__ */ p("ul", {
485
+ children: p("assethandler.field.queueTitle", "On this device")
486
+ }), /* @__PURE__ */ m("ul", {
390
487
  className: "divide-y divide-border-seam",
391
- children: H.map((e) => /* @__PURE__ */ m("li", {
488
+ children: W.map((e) => /* @__PURE__ */ h("li", {
392
489
  className: "flex items-center justify-between gap-3 py-2",
393
- children: [/* @__PURE__ */ m("div", {
490
+ children: [/* @__PURE__ */ h("div", {
394
491
  className: "min-w-0",
395
- children: [/* @__PURE__ */ m("p", {
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__ */ p("p", {
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 ?? f("assethandler.field.refused", "Refused by the server") : e.id === K ? f("assethandler.field.sending", "Sending…") : new Date(e.scannedAt).toLocaleString()
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__ */ m("div", {
503
+ }), /* @__PURE__ */ h("div", {
407
504
  className: "flex shrink-0 gap-1",
408
- children: [e.state === "rejected" ? /* @__PURE__ */ p(h, {
505
+ children: [e.state === "rejected" ? /* @__PURE__ */ m(g, {
409
506
  type: "button",
410
507
  size: "sm",
411
508
  variant: "outline",
412
- onClick: () => He(e.id),
413
- children: f("assethandler.field.retry", "Retry")
414
- }) : null, /* @__PURE__ */ p(h, {
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: () => Ve(e.id),
419
- disabled: e.id === K,
420
- "aria-label": f("assethandler.field.discard", "Discard queued action"),
421
- children: /* @__PURE__ */ p(ye, {
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__ */ m(g, {
527
+ /* @__PURE__ */ h(_, {
431
528
  className: "space-y-3 p-4",
432
529
  children: [
433
- /* @__PURE__ */ p(v, {
530
+ /* @__PURE__ */ m(y, {
434
531
  htmlFor: "field-search",
435
532
  className: "text-sm font-semibold",
436
- children: f("assethandler.field.browse", "Browse assets")
533
+ children: p("assethandler.field.browse", "Browse assets")
437
534
  }),
438
- /* @__PURE__ */ p(_, {
535
+ /* @__PURE__ */ m(v, {
439
536
  id: "field-search",
440
- value: D,
441
- onChange: (e) => Me(e.target.value),
442
- placeholder: f("assethandler.field.searchPlaceholder", "Name, tag, location or holder"),
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__ */ p("p", {
542
+ Q.length === 0 ? /* @__PURE__ */ m("p", {
446
543
  className: "py-4 text-center text-sm text-text-secondary",
447
- children: q.length === 0 ? f("assethandler.field.noAssets", "No assets on this device yet. Open this page once while online to load the registry.") : f("assethandler.field.noMatches", "No assets match your search.")
448
- }) : /* @__PURE__ */ p("ul", {
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__ */ p("li", { children: /* @__PURE__ */ m("button", {
548
+ children: Q.map((e) => /* @__PURE__ */ m("li", { children: /* @__PURE__ */ h("button", {
452
549
  type: "button",
453
- onClick: () => J(e),
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", O?.id === e.id && "border-action-primary-bg"),
455
- children: [/* @__PURE__ */ m("span", {
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__ */ p("span", {
554
+ children: [/* @__PURE__ */ m("span", {
458
555
  className: "block truncate text-sm font-medium text-text-primary",
459
556
  children: e.name
460
- }), /* @__PURE__ */ m("span", {
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__ */ p("span", {
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 { x as FieldModePage };
573
+ export { S as FieldModePage };
477
574
 
478
575
  //# sourceMappingURL=FieldModePage.js.map