@burdenoff/microfe-proserviceworld 2026.1013.1 → 2026.1015.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/generated/wspace-types.d.ts +98750 -26838
  2. package/dist/generated/wspace-types.d.ts.map +1 -1
  3. package/dist/proserviceworld/ProServiceWorldRoot.d.ts.map +1 -1
  4. package/dist/proserviceworld/ProServiceWorldRoot.js +6 -0
  5. package/dist/proserviceworld/ProServiceWorldRoot.js.map +1 -1
  6. package/dist/proserviceworld/ProServiceWorldRoutes.d.ts.map +1 -1
  7. package/dist/proserviceworld/ProServiceWorldRoutes.js +42 -35
  8. package/dist/proserviceworld/ProServiceWorldRoutes.js.map +1 -1
  9. package/dist/proserviceworld/components/CredentialDirectory.d.ts +3 -0
  10. package/dist/proserviceworld/components/CredentialDirectory.d.ts.map +1 -0
  11. package/dist/proserviceworld/components/CredentialDirectory.js +253 -0
  12. package/dist/proserviceworld/components/CredentialDirectory.js.map +1 -0
  13. package/dist/proserviceworld/components/CredentialEvidencePicker.d.ts +9 -0
  14. package/dist/proserviceworld/components/CredentialEvidencePicker.d.ts.map +1 -0
  15. package/dist/proserviceworld/components/CredentialEvidencePicker.js +161 -0
  16. package/dist/proserviceworld/components/CredentialEvidencePicker.js.map +1 -0
  17. package/dist/proserviceworld/components/CredentialRecordForm.d.ts +24 -0
  18. package/dist/proserviceworld/components/CredentialRecordForm.d.ts.map +1 -0
  19. package/dist/proserviceworld/components/CredentialRecordForm.js +251 -0
  20. package/dist/proserviceworld/components/CredentialRecordForm.js.map +1 -0
  21. package/dist/proserviceworld/components/CredentialReferencePicker.d.ts +22 -0
  22. package/dist/proserviceworld/components/CredentialReferencePicker.d.ts.map +1 -0
  23. package/dist/proserviceworld/components/CredentialReferencePicker.js +122 -0
  24. package/dist/proserviceworld/components/CredentialReferencePicker.js.map +1 -0
  25. package/dist/proserviceworld/components/CredentialReminderPanel.d.ts +5 -0
  26. package/dist/proserviceworld/components/CredentialReminderPanel.d.ts.map +1 -0
  27. package/dist/proserviceworld/components/CredentialReminderPanel.js +141 -0
  28. package/dist/proserviceworld/components/CredentialReminderPanel.js.map +1 -0
  29. package/dist/proserviceworld/components/credentialFormDefinitions.d.ts +4 -0
  30. package/dist/proserviceworld/components/credentialFormDefinitions.d.ts.map +1 -0
  31. package/dist/proserviceworld/components/credentialFormDefinitions.js +344 -0
  32. package/dist/proserviceworld/components/credentialFormDefinitions.js.map +1 -0
  33. package/dist/proserviceworld/hooks/credentialWrites.d.ts +16 -0
  34. package/dist/proserviceworld/hooks/credentialWrites.d.ts.map +1 -0
  35. package/dist/proserviceworld/hooks/credentialWrites.js +38 -0
  36. package/dist/proserviceworld/hooks/credentialWrites.js.map +1 -0
  37. package/dist/proserviceworld/hooks/usePractitionerCredentials.d.ts +41 -0
  38. package/dist/proserviceworld/hooks/usePractitionerCredentials.d.ts.map +1 -0
  39. package/dist/proserviceworld/hooks/usePractitionerCredentials.js +105 -0
  40. package/dist/proserviceworld/hooks/usePractitionerCredentials.js.map +1 -0
  41. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +9 -0
  42. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
  43. package/dist/proserviceworld/hooks/useProServiceWorldApi.js +24 -15
  44. package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
  45. package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -1
  46. package/dist/proserviceworld/pages/CompliancePage.js +136 -118
  47. package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
  48. package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -1
  49. package/dist/proserviceworld/pages/ConflictsPage.js +87 -71
  50. package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -1
  51. package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -1
  52. package/dist/proserviceworld/pages/DocumentsPage.js +104 -86
  53. package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
  54. package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -1
  55. package/dist/proserviceworld/pages/InvoicesPage.js +122 -104
  56. package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
  57. package/dist/proserviceworld/pages/PractitionerCredentialsPage.d.ts +2 -0
  58. package/dist/proserviceworld/pages/PractitionerCredentialsPage.d.ts.map +1 -0
  59. package/dist/proserviceworld/pages/PractitionerCredentialsPage.js +268 -0
  60. package/dist/proserviceworld/pages/PractitionerCredentialsPage.js.map +1 -0
  61. package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -1
  62. package/dist/proserviceworld/pages/TimePage.js +132 -114
  63. package/dist/proserviceworld/pages/TimePage.js.map +1 -1
  64. package/dist/proserviceworld/pages/TrustPage.d.ts.map +1 -1
  65. package/dist/proserviceworld/pages/TrustPage.js +226 -207
  66. package/dist/proserviceworld/pages/TrustPage.js.map +1 -1
  67. package/dist/proserviceworld/utils/credentialSourceLink.d.ts +3 -0
  68. package/dist/proserviceworld/utils/credentialSourceLink.d.ts.map +1 -0
  69. package/dist/proserviceworld/utils/credentialSourceLink.js +17 -0
  70. package/dist/proserviceworld/utils/credentialSourceLink.js.map +1 -0
  71. package/package.json +21 -5
@@ -1,136 +1,154 @@
1
1
  import { useArchiveDocument as e, useCreateDocument as t, useDocuments as n } from "../hooks/useProServiceWorldApi.js";
2
2
  import { Banner as r, Empty as i, ErrorState as a, Field as o, LoadingBlock as s, Modal as c, NativeSelect as l, PageHeader as u, SectionCard as d, StatusPill as f, TableWrap as p, Td as m, TextArea as h, TextInput as g, Th as _, enumOptions as v, fmtDate as y, humanize as b } from "../components/ui.js";
3
- import { getDocumentDownloadUrl as x, uploadDocumentFile as S } from "../hooks/useFiles.js";
4
- import { useState as C } from "react";
5
- import { Archive as w, Download as T, FileText as E, Lock as D, Plus as O, Upload as k } from "lucide-react";
6
- import { Fragment as A, jsx as j, jsxs as M } from "react/jsx-runtime";
7
- import { Button as N } from "@burdenoff/fe-libs/ui";
3
+ import { useAnalytics as x } from "../hooks/useAnalytics.js";
4
+ import { getDocumentDownloadUrl as S, uploadDocumentFile as C } from "../hooks/useFiles.js";
5
+ import { useDeferredValue as w, useState as T } from "react";
6
+ import { Archive as E, Download as D, FileText as O, Lock as k, Plus as A, Search as j, Upload as M } from "lucide-react";
7
+ import { Fragment as N, jsx as P, jsxs as F } from "react/jsx-runtime";
8
+ import { Button as I } from "@burdenoff/fe-libs/ui";
8
9
  //#region src/proserviceworld/pages/DocumentsPage.tsx
9
- var P = [
10
+ var L = [
10
11
  "PUBLIC",
11
12
  "INTERNAL",
12
13
  "CONFIDENTIAL",
13
14
  "PRIVILEGED"
14
- ], F = () => {
15
- let [t, o] = C(""), [c, h] = C(!1), [g, S] = C(null), { data: k, isLoading: A, error: F, refetch: L } = n({ classification: t || void 0 }), R = e(), z = async (e) => {
15
+ ], R = () => {
16
+ let [t, o] = T(""), [c, h] = T(""), C = w(c), [M, N] = T(!1), [R, B] = T(null), { data: V, isLoading: H, error: U, refetch: W } = n({
17
+ classification: t || void 0,
18
+ search: C.trim() || void 0
19
+ }), { emitFact: G } = x(), K = e(), q = async (e) => {
16
20
  try {
17
- let t = await x(e);
21
+ let t = await S(e);
18
22
  window.open(t, "_blank", "noopener");
19
23
  } catch (e) {
20
- S({
24
+ B({
21
25
  tone: "danger",
22
26
  text: e instanceof Error ? e.message : "Could not open document."
23
27
  });
24
28
  }
25
29
  };
26
- return /* @__PURE__ */ M("div", {
30
+ return /* @__PURE__ */ F("div", {
27
31
  className: "space-y-6",
28
32
  children: [
29
- /* @__PURE__ */ j(u, {
33
+ /* @__PURE__ */ P(u, {
30
34
  title: "Documents",
31
35
  subtitle: "Engagement letters, opinions, filings and evidence — metadata, classification and legal hold here; the file itself lives in the shared Files service.",
32
- icon: /* @__PURE__ */ j(E, { className: "h-6 w-6" }),
33
- actions: /* @__PURE__ */ M(N, {
34
- onClick: () => h(!0),
35
- children: [/* @__PURE__ */ j(O, { className: "mr-1.5 h-4 w-4" }), "Add document"]
36
+ icon: /* @__PURE__ */ P(O, { className: "h-6 w-6" }),
37
+ actions: /* @__PURE__ */ F(I, {
38
+ onClick: () => N(!0),
39
+ children: [/* @__PURE__ */ P(A, { className: "mr-1.5 h-4 w-4" }), "Add document"]
36
40
  })
37
41
  }),
38
- g && /* @__PURE__ */ j(r, {
39
- tone: g.tone,
40
- onClose: () => S(null),
41
- children: g.text
42
+ R && /* @__PURE__ */ P(r, {
43
+ tone: R.tone,
44
+ onClose: () => B(null),
45
+ children: R.text
42
46
  }),
43
- /* @__PURE__ */ j("div", {
44
- className: "flex justify-end",
45
- children: /* @__PURE__ */ M(l, {
47
+ /* @__PURE__ */ F("div", {
48
+ className: "flex flex-col gap-2 sm:flex-row sm:items-center",
49
+ children: [/* @__PURE__ */ F("div", {
50
+ className: "relative flex-1",
51
+ children: [/* @__PURE__ */ P(j, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ P(g, {
52
+ placeholder: "Search documents…",
53
+ value: c,
54
+ onChange: (e) => h(e.target.value),
55
+ onKeyDown: (e) => {
56
+ e.key === "Enter" && c.trim() && G("psw.search.performed", {
57
+ entityType: "document",
58
+ queryLength: c.trim().length
59
+ });
60
+ },
61
+ className: "pl-9"
62
+ })]
63
+ }), /* @__PURE__ */ F(l, {
46
64
  value: t,
47
65
  onChange: (e) => o(e.target.value),
48
66
  className: "sm:w-52",
49
- children: [/* @__PURE__ */ j("option", {
67
+ children: [/* @__PURE__ */ P("option", {
50
68
  value: "",
51
69
  children: "All classifications"
52
- }), v(P)]
53
- })
70
+ }), v(L)]
71
+ })]
54
72
  }),
55
- A ? /* @__PURE__ */ j(s, {}) : F ? /* @__PURE__ */ j(a, {
56
- error: F,
57
- onRetry: () => void L()
58
- }) : !k || k.items.length === 0 ? /* @__PURE__ */ j(i, {
73
+ H ? /* @__PURE__ */ P(s, {}) : U ? /* @__PURE__ */ P(a, {
74
+ error: U,
75
+ onRetry: () => void W()
76
+ }) : !V || V.items.length === 0 ? /* @__PURE__ */ P(i, {
59
77
  title: "No documents",
60
78
  description: "Add a document — upload the file to the shared Files service and record it here.",
61
- icon: /* @__PURE__ */ j(E, { className: "h-8 w-8" }),
62
- action: /* @__PURE__ */ M(N, {
63
- onClick: () => h(!0),
64
- children: [/* @__PURE__ */ j(O, { className: "mr-1.5 h-4 w-4" }), "Add document"]
79
+ icon: /* @__PURE__ */ P(O, { className: "h-8 w-8" }),
80
+ action: /* @__PURE__ */ F(I, {
81
+ onClick: () => N(!0),
82
+ children: [/* @__PURE__ */ P(A, { className: "mr-1.5 h-4 w-4" }), "Add document"]
65
83
  })
66
- }) : /* @__PURE__ */ j(d, {
67
- title: `${k.totalCount} document${k.totalCount === 1 ? "" : "s"}`,
68
- children: /* @__PURE__ */ M(p, { children: [/* @__PURE__ */ j("thead", { children: /* @__PURE__ */ M("tr", { children: [
69
- /* @__PURE__ */ j(_, { children: "Name" }),
70
- /* @__PURE__ */ j(_, { children: "Classification" }),
71
- /* @__PURE__ */ j(_, { children: "Status" }),
72
- /* @__PURE__ */ j(_, { children: "Added" }),
73
- /* @__PURE__ */ j(_, {
84
+ }) : /* @__PURE__ */ P(d, {
85
+ title: `${V.totalCount} document${V.totalCount === 1 ? "" : "s"}`,
86
+ children: /* @__PURE__ */ F(p, { children: [/* @__PURE__ */ P("thead", { children: /* @__PURE__ */ F("tr", { children: [
87
+ /* @__PURE__ */ P(_, { children: "Name" }),
88
+ /* @__PURE__ */ P(_, { children: "Classification" }),
89
+ /* @__PURE__ */ P(_, { children: "Status" }),
90
+ /* @__PURE__ */ P(_, { children: "Added" }),
91
+ /* @__PURE__ */ P(_, {
74
92
  className: "text-right",
75
93
  children: "Actions"
76
94
  })
77
- ] }) }), /* @__PURE__ */ j("tbody", { children: k.items.map((e) => /* @__PURE__ */ M("tr", {
95
+ ] }) }), /* @__PURE__ */ P("tbody", { children: V.items.map((e) => /* @__PURE__ */ F("tr", {
78
96
  className: "hover:bg-bg-sunken/50",
79
97
  children: [
80
- /* @__PURE__ */ j(m, { children: /* @__PURE__ */ M("span", {
98
+ /* @__PURE__ */ P(m, { children: /* @__PURE__ */ F("span", {
81
99
  className: "flex items-center gap-1.5 font-medium text-text-primary",
82
100
  children: [
83
- e.legalHold && /* @__PURE__ */ j(D, {
101
+ e.legalHold && /* @__PURE__ */ P(k, {
84
102
  className: "h-3.5 w-3.5 text-status-warning-text",
85
103
  "aria-label": "Legal hold"
86
104
  }),
87
105
  e.name,
88
106
  " ",
89
- /* @__PURE__ */ M("span", {
107
+ /* @__PURE__ */ F("span", {
90
108
  className: "text-xs text-text-tertiary",
91
109
  children: ["v", e.version]
92
110
  })
93
111
  ]
94
112
  }) }),
95
- /* @__PURE__ */ j(m, { children: b(e.classification) }),
96
- /* @__PURE__ */ j(m, { children: /* @__PURE__ */ j(f, { status: e.status }) }),
97
- /* @__PURE__ */ j(m, { children: y(e.createdAt) }),
98
- /* @__PURE__ */ j(m, {
113
+ /* @__PURE__ */ P(m, { children: b(e.classification) }),
114
+ /* @__PURE__ */ P(m, { children: /* @__PURE__ */ P(f, { status: e.status }) }),
115
+ /* @__PURE__ */ P(m, { children: y(e.createdAt) }),
116
+ /* @__PURE__ */ P(m, {
99
117
  className: "text-right",
100
- children: /* @__PURE__ */ M("div", {
118
+ children: /* @__PURE__ */ F("div", {
101
119
  className: "flex justify-end gap-1",
102
- children: [e.file?.id && /* @__PURE__ */ j(N, {
120
+ children: [e.file?.id && /* @__PURE__ */ P(I, {
103
121
  variant: "ghost",
104
122
  size: "sm",
105
- onClick: () => void z(e.file.id),
123
+ onClick: () => void q(e.file.id),
106
124
  "aria-label": "Download",
107
- children: /* @__PURE__ */ j(T, { className: "h-4 w-4" })
108
- }), e.status !== "ARCHIVED" && /* @__PURE__ */ j(N, {
125
+ children: /* @__PURE__ */ P(D, { className: "h-4 w-4" })
126
+ }), e.status !== "ARCHIVED" && /* @__PURE__ */ P(I, {
109
127
  variant: "ghost",
110
128
  size: "sm",
111
129
  "aria-label": "Archive",
112
- disabled: R.isPending,
113
- onClick: () => R.mutate(e.id, {
114
- onSuccess: () => S({
130
+ disabled: K.isPending,
131
+ onClick: () => K.mutate(e.id, {
132
+ onSuccess: () => B({
115
133
  tone: "success",
116
134
  text: `${e.name} archived.`
117
135
  }),
118
- onError: (e) => S({
136
+ onError: (e) => B({
119
137
  tone: "danger",
120
138
  text: e instanceof Error ? e.message : "Failed."
121
139
  })
122
140
  }),
123
- children: /* @__PURE__ */ j(w, { className: "h-4 w-4" })
141
+ children: /* @__PURE__ */ P(E, { className: "h-4 w-4" })
124
142
  })]
125
143
  })
126
144
  })
127
145
  ]
128
146
  }, e.id)) })] })
129
147
  }),
130
- c && /* @__PURE__ */ j(I, {
131
- onClose: () => h(!1),
148
+ M && /* @__PURE__ */ P(z, {
149
+ onClose: () => N(!1),
132
150
  onDone: () => {
133
- L(), S({
151
+ W(), B({
134
152
  tone: "success",
135
153
  text: "Document added."
136
154
  });
@@ -138,18 +156,18 @@ var P = [
138
156
  })
139
157
  ]
140
158
  });
141
- }, I = ({ onClose: e, onDone: n }) => {
142
- let i = t(), [a, s] = C({
159
+ }, z = ({ onClose: e, onDone: n }) => {
160
+ let i = t(), [a, s] = T({
143
161
  name: "",
144
162
  classification: "INTERNAL",
145
163
  description: "",
146
164
  legalHold: !1
147
- }), [u, d] = C(null), [f, p] = C(!1), [m, _] = C(null), y = async () => {
165
+ }), [u, d] = T(null), [f, p] = T(!1), [m, _] = T(null), y = async () => {
148
166
  if (_(null), !a.name.trim()) return _("Document name is required.");
149
167
  let t = null;
150
168
  if (u) {
151
169
  try {
152
- p(!0), t = (await S(u)).fileId;
170
+ p(!0), t = (await C(u)).fileId;
153
171
  } catch (e) {
154
172
  return p(!1), _(e instanceof Error ? e.message : "Upload failed.");
155
173
  }
@@ -168,31 +186,31 @@ var P = [
168
186
  onError: (e) => _(e instanceof Error ? e.message : "Failed.")
169
187
  });
170
188
  }, b = f || i.isPending;
171
- return /* @__PURE__ */ j(c, {
189
+ return /* @__PURE__ */ P(c, {
172
190
  open: !0,
173
191
  onClose: e,
174
192
  title: "Add document",
175
- footer: /* @__PURE__ */ M(A, { children: [/* @__PURE__ */ j(N, {
193
+ footer: /* @__PURE__ */ F(N, { children: [/* @__PURE__ */ P(I, {
176
194
  variant: "outline",
177
195
  onClick: e,
178
196
  disabled: b,
179
197
  children: "Cancel"
180
- }), /* @__PURE__ */ j(N, {
198
+ }), /* @__PURE__ */ P(I, {
181
199
  onClick: () => void y(),
182
200
  disabled: b,
183
201
  children: f ? "Uploading…" : i.isPending ? "Saving…" : "Add document"
184
202
  })] }),
185
- children: /* @__PURE__ */ M("div", {
203
+ children: /* @__PURE__ */ F("div", {
186
204
  className: "space-y-3",
187
205
  children: [
188
- m && /* @__PURE__ */ j(r, {
206
+ m && /* @__PURE__ */ P(r, {
189
207
  tone: "danger",
190
208
  children: m
191
209
  }),
192
- /* @__PURE__ */ j(o, {
210
+ /* @__PURE__ */ P(o, {
193
211
  label: "Name",
194
212
  required: !0,
195
- children: /* @__PURE__ */ j(g, {
213
+ children: /* @__PURE__ */ P(g, {
196
214
  value: a.name,
197
215
  onChange: (e) => s((t) => ({
198
216
  ...t,
@@ -201,26 +219,26 @@ var P = [
201
219
  placeholder: "Engagement letter — Acme FY26"
202
220
  })
203
221
  }),
204
- /* @__PURE__ */ j(o, {
222
+ /* @__PURE__ */ P(o, {
205
223
  label: "Classification",
206
- children: /* @__PURE__ */ j(l, {
224
+ children: /* @__PURE__ */ P(l, {
207
225
  value: a.classification,
208
226
  onChange: (e) => s((t) => ({
209
227
  ...t,
210
228
  classification: e.target.value
211
229
  })),
212
- children: v(P)
230
+ children: v(L)
213
231
  })
214
232
  }),
215
- /* @__PURE__ */ j(o, {
233
+ /* @__PURE__ */ P(o, {
216
234
  label: "File",
217
235
  hint: "Optional — stored in the shared Files service.",
218
- children: /* @__PURE__ */ M("label", {
236
+ children: /* @__PURE__ */ F("label", {
219
237
  className: "flex cursor-pointer items-center gap-2 rounded-lg border border-dashed border-border-seam bg-bg-canvas px-3 py-3 text-sm text-text-secondary hover:border-accent",
220
238
  children: [
221
- /* @__PURE__ */ j(k, { className: "h-4 w-4 text-text-tertiary" }),
239
+ /* @__PURE__ */ P(M, { className: "h-4 w-4 text-text-tertiary" }),
222
240
  u ? u.name : "Choose a file…",
223
- /* @__PURE__ */ j("input", {
241
+ /* @__PURE__ */ P("input", {
224
242
  type: "file",
225
243
  className: "hidden",
226
244
  onChange: (e) => d(e.target.files?.[0] ?? null)
@@ -228,9 +246,9 @@ var P = [
228
246
  ]
229
247
  })
230
248
  }),
231
- /* @__PURE__ */ j(o, {
249
+ /* @__PURE__ */ P(o, {
232
250
  label: "Description",
233
- children: /* @__PURE__ */ j(h, {
251
+ children: /* @__PURE__ */ P(h, {
234
252
  value: a.description,
235
253
  onChange: (e) => s((t) => ({
236
254
  ...t,
@@ -238,9 +256,9 @@ var P = [
238
256
  }))
239
257
  })
240
258
  }),
241
- /* @__PURE__ */ M("label", {
259
+ /* @__PURE__ */ F("label", {
242
260
  className: "flex items-center gap-2 text-sm text-text-secondary",
243
- children: [/* @__PURE__ */ j("input", {
261
+ children: [/* @__PURE__ */ P("input", {
244
262
  type: "checkbox",
245
263
  checked: a.legalHold,
246
264
  onChange: (e) => s((t) => ({
@@ -254,6 +272,6 @@ var P = [
254
272
  });
255
273
  };
256
274
  //#endregion
257
- export { F as DocumentsPage };
275
+ export { R as DocumentsPage };
258
276
 
259
277
  //# sourceMappingURL=DocumentsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/DocumentsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, FileText, Download, Archive, Lock, Upload } from 'lucide-react';\nimport {\n useDocuments,\n useCreateDocument,\n useArchiveDocument,\n type PswDocumentClassification,\n} from '../hooks/useProServiceWorldApi';\nimport { uploadDocumentFile, getDocumentDownloadUrl } from '../hooks/useFiles';\nimport {\n PageHeader,\n SectionCard,\n LoadingBlock,\n ErrorState,\n Empty,\n StatusPill,\n Modal,\n Field,\n TextInput,\n TextArea,\n NativeSelect,\n Banner,\n TableWrap,\n Th,\n Td,\n enumOptions,\n fmtDate,\n humanize,\n} from '../components/ui';\n\nconst CLASSIFICATIONS = ['PUBLIC', 'INTERNAL', 'CONFIDENTIAL', 'PRIVILEGED'] as const;\n\nexport const DocumentsPage: FC = () => {\n const [classFilter, setClassFilter] = useState<PswDocumentClassification | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const { data, isLoading, error, refetch } = useDocuments({\n classification: classFilter || undefined,\n });\n const archive = useArchiveDocument();\n\n const download = async (fileId: string) => {\n try {\n const url = await getDocumentDownloadUrl(fileId);\n window.open(url, '_blank', 'noopener');\n } catch (e) {\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Could not open document.',\n });\n }\n };\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Documents\"\n subtitle=\"Engagement letters, opinions, filings and evidence — metadata, classification and legal hold here; the file itself lives in the shared Files service.\"\n icon={<FileText className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n Add document\n </Button>\n }\n />\n\n {banner && (\n <Banner tone={banner.tone} onClose={() => setBanner(null)}>\n {banner.text}\n </Banner>\n )}\n\n <div className=\"flex justify-end\">\n <NativeSelect\n value={classFilter}\n onChange={(e) => setClassFilter(e.target.value as PswDocumentClassification | '')}\n className=\"sm:w-52\"\n >\n <option value=\"\">All classifications</option>\n {enumOptions(CLASSIFICATIONS)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title=\"No documents\"\n description=\"Add a document — upload the file to the shared Files service and record it here.\"\n icon={<FileText className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n Add document\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${data.totalCount} document${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Name</Th>\n <Th>Classification</Th>\n <Th>Status</Th>\n <Th>Added</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((d) => (\n <tr key={d.id} className=\"hover:bg-bg-sunken/50\">\n <Td>\n <span className=\"flex items-center gap-1.5 font-medium text-text-primary\">\n {d.legalHold && (\n <Lock\n className=\"h-3.5 w-3.5 text-status-warning-text\"\n aria-label=\"Legal hold\"\n />\n )}\n {d.name} <span className=\"text-xs text-text-tertiary\">v{d.version}</span>\n </span>\n </Td>\n <Td>{humanize(d.classification)}</Td>\n <Td>\n <StatusPill status={d.status} />\n </Td>\n <Td>{fmtDate(d.createdAt)}</Td>\n <Td className=\"text-right\">\n <div className=\"flex justify-end gap-1\">\n {d.file?.id && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => void download(d.file!.id)}\n aria-label=\"Download\"\n >\n <Download className=\"h-4 w-4\" />\n </Button>\n )}\n {d.status !== 'ARCHIVED' && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Archive\"\n disabled={archive.isPending}\n onClick={() =>\n archive.mutate(d.id, {\n onSuccess: () =>\n setBanner({ tone: 'success', text: `${d.name} archived.` }),\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Failed.',\n }),\n })\n }\n >\n <Archive className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <DocumentModal\n onClose={() => setCreating(false)}\n onDone={() => {\n void refetch();\n setBanner({ tone: 'success', text: 'Document added.' });\n }}\n />\n )}\n </div>\n );\n};\n\nconst DocumentModal: FC<{ onClose: () => void; onDone: () => void }> = ({ onClose, onDone }) => {\n const create = useCreateDocument();\n const [form, setForm] = useState({\n name: '',\n classification: 'INTERNAL',\n description: '',\n legalHold: false,\n });\n const [file, setFile] = useState<File | null>(null);\n const [uploading, setUploading] = useState(false);\n const [err, setErr] = useState<string | null>(null);\n\n const submit = async () => {\n setErr(null);\n if (!form.name.trim()) return setErr('Document name is required.');\n let fileId: string | null = null;\n if (file) {\n try {\n setUploading(true);\n const uploaded = await uploadDocumentFile(file);\n fileId = uploaded.fileId;\n } catch (e) {\n setUploading(false);\n return setErr(e instanceof Error ? e.message : 'Upload failed.');\n }\n setUploading(false);\n }\n create.mutate(\n {\n name: form.name.trim(),\n classification: form.classification,\n description: form.description.trim() || null,\n legalHold: form.legalHold,\n fileId,\n },\n {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n\n const busy = uploading || create.isPending;\n return (\n <Modal\n open\n onClose={onClose}\n title=\"Add document\"\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={busy}>\n Cancel\n </Button>\n <Button onClick={() => void submit()} disabled={busy}>\n {uploading ? 'Uploading…' : create.isPending ? 'Saving…' : 'Add document'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Name\" required>\n <TextInput\n value={form.name}\n onChange={(e) => setForm((f) => ({ ...f, name: e.target.value }))}\n placeholder=\"Engagement letter — Acme FY26\"\n />\n </Field>\n <Field label=\"Classification\">\n <NativeSelect\n value={form.classification}\n onChange={(e) => setForm((f) => ({ ...f, classification: e.target.value }))}\n >\n {enumOptions(CLASSIFICATIONS)}\n </NativeSelect>\n </Field>\n <Field label=\"File\" hint=\"Optional — stored in the shared Files service.\">\n <label className=\"flex cursor-pointer items-center gap-2 rounded-lg border border-dashed border-border-seam bg-bg-canvas px-3 py-3 text-sm text-text-secondary hover:border-accent\">\n <Upload className=\"h-4 w-4 text-text-tertiary\" />\n {file ? file.name : 'Choose a file…'}\n <input\n type=\"file\"\n className=\"hidden\"\n onChange={(e) => setFile(e.target.files?.[0] ?? null)}\n />\n </label>\n </Field>\n <Field label=\"Description\">\n <TextArea\n value={form.description}\n onChange={(e) => setForm((f) => ({ ...f, description: e.target.value }))}\n />\n </Field>\n <label className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.legalHold}\n onChange={(e) => setForm((f) => ({ ...f, legalHold: e.target.checked }))}\n />\n Place under legal hold (cannot be disposed)\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"DocumentsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/DocumentsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useDeferredValue, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, FileText, Download, Archive, Lock, Upload, Search } from 'lucide-react';\nimport {\n useDocuments,\n useCreateDocument,\n useArchiveDocument,\n type PswDocumentClassification,\n} from '../hooks/useProServiceWorldApi';\nimport { uploadDocumentFile, getDocumentDownloadUrl } from '../hooks/useFiles';\nimport {\n PageHeader,\n SectionCard,\n LoadingBlock,\n ErrorState,\n Empty,\n StatusPill,\n Modal,\n Field,\n TextInput,\n TextArea,\n NativeSelect,\n Banner,\n TableWrap,\n Th,\n Td,\n enumOptions,\n fmtDate,\n humanize,\n} from '../components/ui';\nimport { useAnalytics } from '../hooks/useAnalytics';\n\nconst CLASSIFICATIONS = ['PUBLIC', 'INTERNAL', 'CONFIDENTIAL', 'PRIVILEGED'] as const;\n\nexport const DocumentsPage: FC = () => {\n const [classFilter, setClassFilter] = useState<PswDocumentClassification | ''>('');\n const [search, setSearch] = useState('');\n const deferredSearch = useDeferredValue(search);\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const { data, isLoading, error, refetch } = useDocuments({\n classification: classFilter || undefined,\n search: deferredSearch.trim() || undefined,\n });\n const { emitFact } = useAnalytics();\n const archive = useArchiveDocument();\n\n const download = async (fileId: string) => {\n try {\n const url = await getDocumentDownloadUrl(fileId);\n window.open(url, '_blank', 'noopener');\n } catch (e) {\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Could not open document.',\n });\n }\n };\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Documents\"\n subtitle=\"Engagement letters, opinions, filings and evidence — metadata, classification and legal hold here; the file itself lives in the shared Files service.\"\n icon={<FileText className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n Add document\n </Button>\n }\n />\n\n {banner && (\n <Banner tone={banner.tone} onClose={() => setBanner(null)}>\n {banner.text}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder=\"Search documents…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && search.trim()) {\n emitFact('psw.search.performed', {\n entityType: 'document',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={classFilter}\n onChange={(e) => setClassFilter(e.target.value as PswDocumentClassification | '')}\n className=\"sm:w-52\"\n >\n <option value=\"\">All classifications</option>\n {enumOptions(CLASSIFICATIONS)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title=\"No documents\"\n description=\"Add a document — upload the file to the shared Files service and record it here.\"\n icon={<FileText className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n Add document\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${data.totalCount} document${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Name</Th>\n <Th>Classification</Th>\n <Th>Status</Th>\n <Th>Added</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((d) => (\n <tr key={d.id} className=\"hover:bg-bg-sunken/50\">\n <Td>\n <span className=\"flex items-center gap-1.5 font-medium text-text-primary\">\n {d.legalHold && (\n <Lock\n className=\"h-3.5 w-3.5 text-status-warning-text\"\n aria-label=\"Legal hold\"\n />\n )}\n {d.name} <span className=\"text-xs text-text-tertiary\">v{d.version}</span>\n </span>\n </Td>\n <Td>{humanize(d.classification)}</Td>\n <Td>\n <StatusPill status={d.status} />\n </Td>\n <Td>{fmtDate(d.createdAt)}</Td>\n <Td className=\"text-right\">\n <div className=\"flex justify-end gap-1\">\n {d.file?.id && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => void download(d.file!.id)}\n aria-label=\"Download\"\n >\n <Download className=\"h-4 w-4\" />\n </Button>\n )}\n {d.status !== 'ARCHIVED' && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Archive\"\n disabled={archive.isPending}\n onClick={() =>\n archive.mutate(d.id, {\n onSuccess: () =>\n setBanner({ tone: 'success', text: `${d.name} archived.` }),\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Failed.',\n }),\n })\n }\n >\n <Archive className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <DocumentModal\n onClose={() => setCreating(false)}\n onDone={() => {\n void refetch();\n setBanner({ tone: 'success', text: 'Document added.' });\n }}\n />\n )}\n </div>\n );\n};\n\nconst DocumentModal: FC<{ onClose: () => void; onDone: () => void }> = ({ onClose, onDone }) => {\n const create = useCreateDocument();\n const [form, setForm] = useState({\n name: '',\n classification: 'INTERNAL',\n description: '',\n legalHold: false,\n });\n const [file, setFile] = useState<File | null>(null);\n const [uploading, setUploading] = useState(false);\n const [err, setErr] = useState<string | null>(null);\n\n const submit = async () => {\n setErr(null);\n if (!form.name.trim()) return setErr('Document name is required.');\n let fileId: string | null = null;\n if (file) {\n try {\n setUploading(true);\n const uploaded = await uploadDocumentFile(file);\n fileId = uploaded.fileId;\n } catch (e) {\n setUploading(false);\n return setErr(e instanceof Error ? e.message : 'Upload failed.');\n }\n setUploading(false);\n }\n create.mutate(\n {\n name: form.name.trim(),\n classification: form.classification,\n description: form.description.trim() || null,\n legalHold: form.legalHold,\n fileId,\n },\n {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n\n const busy = uploading || create.isPending;\n return (\n <Modal\n open\n onClose={onClose}\n title=\"Add document\"\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={busy}>\n Cancel\n </Button>\n <Button onClick={() => void submit()} disabled={busy}>\n {uploading ? 'Uploading…' : create.isPending ? 'Saving…' : 'Add document'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Name\" required>\n <TextInput\n value={form.name}\n onChange={(e) => setForm((f) => ({ ...f, name: e.target.value }))}\n placeholder=\"Engagement letter — Acme FY26\"\n />\n </Field>\n <Field label=\"Classification\">\n <NativeSelect\n value={form.classification}\n onChange={(e) => setForm((f) => ({ ...f, classification: e.target.value }))}\n >\n {enumOptions(CLASSIFICATIONS)}\n </NativeSelect>\n </Field>\n <Field label=\"File\" hint=\"Optional — stored in the shared Files service.\">\n <label className=\"flex cursor-pointer items-center gap-2 rounded-lg border border-dashed border-border-seam bg-bg-canvas px-3 py-3 text-sm text-text-secondary hover:border-accent\">\n <Upload className=\"h-4 w-4 text-text-tertiary\" />\n {file ? file.name : 'Choose a file…'}\n <input\n type=\"file\"\n className=\"hidden\"\n onChange={(e) => setFile(e.target.files?.[0] ?? null)}\n />\n </label>\n </Field>\n <Field label=\"Description\">\n <TextArea\n value={form.description}\n onChange={(e) => setForm((f) => ({ ...f, description: e.target.value }))}\n />\n </Field>\n <label className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.legalHold}\n onChange={(e) => setForm((f) => ({ ...f, legalHold: e.target.checked }))}\n />\n Place under legal hold (cannot be disposed)\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"InvoicesPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/InvoicesPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAqChC,eAAO,MAAM,YAAY,EAAE,EAgK1B,CAAC"}
1
+ {"version":3,"file":"InvoicesPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/InvoicesPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAsChC,eAAO,MAAM,YAAY,EAAE,EAuL1B,CAAC"}