@burdenoff/microfe-proserviceworld 2026.706.2 → 2026.706.3

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 (26) hide show
  1. package/dist/proserviceworld/components/DiscussionThread.js +1 -1
  2. package/dist/proserviceworld/components/DiscussionThread.js.map +1 -1
  3. package/dist/proserviceworld/components/ui.js +18 -18
  4. package/dist/proserviceworld/components/ui.js.map +1 -1
  5. package/dist/proserviceworld/hooks/useEntityComments.js.map +1 -1
  6. package/dist/proserviceworld/pages/AnalyticsPage.js +277 -111
  7. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  8. package/dist/proserviceworld/pages/ClientDetailPage.js +219 -151
  9. package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
  10. package/dist/proserviceworld/pages/ClientsPage.js +148 -127
  11. package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
  12. package/dist/proserviceworld/pages/CompliancePage.js +140 -96
  13. package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
  14. package/dist/proserviceworld/pages/DashboardPage.js +221 -104
  15. package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
  16. package/dist/proserviceworld/pages/EngagementDetailPage.js +211 -181
  17. package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
  18. package/dist/proserviceworld/pages/EngagementsPage.js +144 -106
  19. package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
  20. package/dist/proserviceworld/pages/InvoicesPage.js +144 -129
  21. package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
  22. package/dist/proserviceworld/pages/MattersPage.js +163 -122
  23. package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
  24. package/dist/proserviceworld/pages/TimePage.js +112 -92
  25. package/dist/proserviceworld/pages/TimePage.js.map +1 -1
  26. package/package.json +1 -1
@@ -1,135 +1,173 @@
1
1
  import { useClients as e, useCloseMatter as t, useCreateMatter as n, useMatters as r, usePracticeAreas as i } from "../hooks/useProServiceWorldApi.js";
2
- import { Banner as a, Empty as o, ErrorState as s, Field as c, LoadingBlock as l, Modal as u, NativeSelect as d, PageHeader as f, SectionCard as p, StatusPill as m, TableWrap as h, Td as g, TextArea as _, TextInput as v, Th as y, enumOptions as b, fmtDate as x } from "../components/ui.js";
3
- import { useState as S } from "react";
4
- import { CheckCircle2 as C, FolderKanban as w, Lock as T, Plus as E, Search as D } from "lucide-react";
5
- import { Fragment as O, jsx as k, jsxs as A } from "react/jsx-runtime";
6
- import { Button as j } from "@burdenoff/fe-libs/ui";
2
+ import { Banner as a, Empty as o, ErrorState as s, Field as c, LoadingBlock as l, MetricCard as u, Modal as d, NativeSelect as f, PageHeader as p, SectionCard as m, StatusPill as h, TableWrap as g, Td as _, TextArea as v, TextInput as y, Th as b, enumOptions as x, fmtDate as S } from "../components/ui.js";
3
+ import { useState as C } from "react";
4
+ import { AlertTriangle as w, CheckCircle2 as T, CircleDot as E, FolderKanban as D, Lock as O, Plus as k, Search as A } from "lucide-react";
5
+ import { Fragment as j, jsx as M, jsxs as N } from "react/jsx-runtime";
6
+ import { Button as P } from "@burdenoff/fe-libs/ui";
7
7
  //#region src/proserviceworld/pages/MattersPage.tsx
8
- var M = [
8
+ var F = [
9
9
  "OPEN",
10
10
  "ON_HOLD",
11
11
  "CLOSED",
12
12
  "ARCHIVED"
13
- ], N = [
13
+ ], I = [
14
14
  "LOW",
15
15
  "MEDIUM",
16
16
  "HIGH",
17
17
  "CRITICAL"
18
- ], P = () => {
19
- let [e, n] = S(""), [i, c] = S(""), [u, _] = S(!1), [O, N] = S(null), { data: P, isLoading: I, error: L, refetch: R } = r({
18
+ ], L = () => /* @__PURE__ */ M("span", {
19
+ className: "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text",
20
+ title: "Privileged / confidential",
21
+ "aria-label": "Privileged",
22
+ children: /* @__PURE__ */ M(O, { className: "h-3 w-3" })
23
+ }), R = () => {
24
+ let [e, n] = C(""), [i, c] = C(""), [d, v] = C(!1), [I, R] = C(null), { data: B, isLoading: V, error: H, refetch: U } = r({
20
25
  search: e.trim() || void 0,
21
26
  status: i || void 0
22
- }), z = t();
23
- return /* @__PURE__ */ A("div", {
27
+ }), W = t(), G = B?.items ?? [], K = G.filter((e) => e.status === "OPEN").length, q = G.filter((e) => e.isPrivileged).length, J = G.filter((e) => e.priority === "HIGH" || e.priority === "CRITICAL").length;
28
+ return /* @__PURE__ */ N("div", {
24
29
  className: "space-y-6",
25
30
  children: [
26
- /* @__PURE__ */ k(f, {
31
+ /* @__PURE__ */ M(p, {
27
32
  title: "Matters",
28
33
  subtitle: "The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.",
29
- icon: /* @__PURE__ */ k(w, { className: "h-6 w-6" }),
30
- actions: /* @__PURE__ */ A(j, {
31
- onClick: () => _(!0),
32
- children: [/* @__PURE__ */ k(E, { className: "mr-1.5 h-4 w-4" }), "New matter"]
34
+ icon: /* @__PURE__ */ M(D, { className: "h-6 w-6" }),
35
+ actions: /* @__PURE__ */ N(P, {
36
+ onClick: () => v(!0),
37
+ children: [/* @__PURE__ */ M(k, { className: "mr-1.5 h-4 w-4" }), "New matter"]
33
38
  })
34
39
  }),
35
- O && /* @__PURE__ */ k(a, {
36
- tone: O.tone,
37
- onClose: () => N(null),
38
- children: O.text
40
+ I && /* @__PURE__ */ M(a, {
41
+ tone: I.tone,
42
+ onClose: () => R(null),
43
+ children: I.text
39
44
  }),
40
- /* @__PURE__ */ A("div", {
45
+ /* @__PURE__ */ N("div", {
41
46
  className: "flex flex-col gap-2 sm:flex-row sm:items-center",
42
- children: [/* @__PURE__ */ A("div", {
47
+ children: [/* @__PURE__ */ N("div", {
43
48
  className: "relative flex-1",
44
- children: [/* @__PURE__ */ k(D, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ k(v, {
49
+ children: [/* @__PURE__ */ M(A, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ M(y, {
45
50
  placeholder: "Search matters…",
46
51
  value: e,
47
52
  onChange: (e) => n(e.target.value),
48
53
  className: "pl-9"
49
54
  })]
50
- }), /* @__PURE__ */ A(d, {
55
+ }), /* @__PURE__ */ N(f, {
51
56
  value: i,
52
57
  onChange: (e) => c(e.target.value),
53
58
  className: "sm:w-48",
54
- children: [/* @__PURE__ */ k("option", {
59
+ children: [/* @__PURE__ */ M("option", {
55
60
  value: "",
56
61
  children: "All statuses"
57
- }), b(M)]
62
+ }), x(F)]
58
63
  })]
59
64
  }),
60
- I ? /* @__PURE__ */ k(l, {}) : L ? /* @__PURE__ */ k(s, {
61
- error: L,
62
- onRetry: () => void R()
63
- }) : !P || P.items.length === 0 ? /* @__PURE__ */ k(o, {
65
+ V ? /* @__PURE__ */ M(l, {}) : H ? /* @__PURE__ */ M(s, {
66
+ error: H,
67
+ onRetry: () => void U()
68
+ }) : !B || B.items.length === 0 ? /* @__PURE__ */ M(o, {
64
69
  title: "No matters yet",
65
70
  description: "Open a matter to track a regulated thread of work for a client.",
66
- icon: /* @__PURE__ */ k(w, { className: "h-8 w-8" }),
67
- action: /* @__PURE__ */ A(j, {
68
- onClick: () => _(!0),
69
- children: [/* @__PURE__ */ k(E, { className: "mr-1.5 h-4 w-4" }), "New matter"]
71
+ icon: /* @__PURE__ */ M(D, { className: "h-8 w-8" }),
72
+ action: /* @__PURE__ */ N(P, {
73
+ onClick: () => v(!0),
74
+ children: [/* @__PURE__ */ M(k, { className: "mr-1.5 h-4 w-4" }), "New matter"]
70
75
  })
71
- }) : /* @__PURE__ */ k(p, {
72
- title: `${P.totalCount} matter${P.totalCount === 1 ? "" : "s"}`,
73
- children: /* @__PURE__ */ A(h, { children: [/* @__PURE__ */ k("thead", { children: /* @__PURE__ */ A("tr", { children: [
74
- /* @__PURE__ */ k(y, { children: "Matter" }),
75
- /* @__PURE__ */ k(y, { children: "Client" }),
76
- /* @__PURE__ */ k(y, { children: "Priority" }),
77
- /* @__PURE__ */ k(y, { children: "Status" }),
78
- /* @__PURE__ */ k(y, { children: "Due" }),
79
- /* @__PURE__ */ k(y, {
76
+ }) : /* @__PURE__ */ N(j, { children: [/* @__PURE__ */ N("div", {
77
+ className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
78
+ children: [
79
+ /* @__PURE__ */ M(u, {
80
+ label: "Matters",
81
+ value: B.totalCount,
82
+ icon: /* @__PURE__ */ M(D, { className: "h-4 w-4" })
83
+ }),
84
+ /* @__PURE__ */ M(u, {
85
+ label: "Open",
86
+ value: K,
87
+ icon: /* @__PURE__ */ M(E, { className: "h-4 w-4" }),
88
+ tone: "accent"
89
+ }),
90
+ /* @__PURE__ */ M(u, {
91
+ label: "Privileged",
92
+ value: q,
93
+ icon: /* @__PURE__ */ M(O, { className: "h-4 w-4" }),
94
+ tone: "warning"
95
+ }),
96
+ /* @__PURE__ */ M(u, {
97
+ label: "High priority",
98
+ value: J,
99
+ icon: /* @__PURE__ */ M(w, { className: "h-4 w-4" }),
100
+ tone: J ? "danger" : "neutral"
101
+ })
102
+ ]
103
+ }), /* @__PURE__ */ M(m, {
104
+ title: `${B.totalCount} matter${B.totalCount === 1 ? "" : "s"}`,
105
+ children: /* @__PURE__ */ N(g, { children: [/* @__PURE__ */ M("thead", { children: /* @__PURE__ */ N("tr", { children: [
106
+ /* @__PURE__ */ M(b, { children: "Matter" }),
107
+ /* @__PURE__ */ M(b, { children: "Client" }),
108
+ /* @__PURE__ */ M(b, { children: "Priority" }),
109
+ /* @__PURE__ */ M(b, { children: "Status" }),
110
+ /* @__PURE__ */ M(b, { children: "Due" }),
111
+ /* @__PURE__ */ M(b, {
80
112
  className: "text-right",
81
113
  children: "Actions"
82
114
  })
83
- ] }) }), /* @__PURE__ */ k("tbody", { children: P.items.map((e) => /* @__PURE__ */ A("tr", {
84
- className: "hover:bg-bg-sunken/50",
115
+ ] }) }), /* @__PURE__ */ M("tbody", { children: B.items.map((e) => /* @__PURE__ */ N("tr", {
116
+ className: "transition-colors hover:bg-bg-sunken/60",
85
117
  children: [
86
- /* @__PURE__ */ A(g, { children: [/* @__PURE__ */ A("span", {
87
- className: "flex items-center gap-1.5 font-medium text-text-primary",
88
- children: [e.isPrivileged && /* @__PURE__ */ k(T, {
89
- className: "h-3.5 w-3.5 text-status-warning-text",
90
- "aria-label": "Privileged"
91
- }), e.title]
92
- }), e.reference ? /* @__PURE__ */ k("div", {
93
- className: "text-xs text-text-tertiary",
94
- children: e.reference
118
+ /* @__PURE__ */ N(_, { children: [/* @__PURE__ */ N("span", {
119
+ className: "flex items-center gap-2 font-medium text-text-primary",
120
+ children: [e.isPrivileged && /* @__PURE__ */ M(L, {}), /* @__PURE__ */ M("span", {
121
+ className: "truncate",
122
+ children: e.title
123
+ })]
124
+ }), e.reference ? /* @__PURE__ */ N("div", {
125
+ className: "mt-0.5 pl-0 text-xs text-text-tertiary",
126
+ children: ["Ref: ", e.reference]
95
127
  }) : null] }),
96
- /* @__PURE__ */ k(g, { children: e.client?.name ?? "—" }),
97
- /* @__PURE__ */ k(g, { children: /* @__PURE__ */ k(m, { status: e.priority }) }),
98
- /* @__PURE__ */ k(g, { children: /* @__PURE__ */ k(m, { status: e.status }) }),
99
- /* @__PURE__ */ k(g, { children: x(e.dueDate) }),
100
- /* @__PURE__ */ k(g, {
128
+ /* @__PURE__ */ M(_, {
129
+ className: "text-text-primary",
130
+ children: e.client?.name ?? "—"
131
+ }),
132
+ /* @__PURE__ */ M(_, { children: /* @__PURE__ */ M(h, { status: e.priority }) }),
133
+ /* @__PURE__ */ M(_, { children: /* @__PURE__ */ M(h, { status: e.status }) }),
134
+ /* @__PURE__ */ M(_, { children: S(e.dueDate) }),
135
+ /* @__PURE__ */ M(_, {
101
136
  className: "text-right",
102
- children: e.status !== "CLOSED" && e.status !== "ARCHIVED" && /* @__PURE__ */ A(j, {
137
+ children: e.status !== "CLOSED" && e.status !== "ARCHIVED" ? /* @__PURE__ */ N(P, {
103
138
  variant: "ghost",
104
139
  size: "sm",
105
- disabled: z.isPending,
106
- onClick: () => z.mutate(e.id, {
107
- onSuccess: () => N({
140
+ disabled: W.isPending,
141
+ onClick: () => W.mutate(e.id, {
142
+ onSuccess: () => R({
108
143
  tone: "success",
109
144
  text: `${e.title} closed.`
110
145
  }),
111
- onError: (e) => N({
146
+ onError: (e) => R({
112
147
  tone: "danger",
113
148
  text: e instanceof Error ? e.message : "Failed."
114
149
  })
115
150
  }),
116
- children: [/* @__PURE__ */ k(C, { className: "mr-1 h-4 w-4" }), " Close"]
151
+ children: [/* @__PURE__ */ M(T, { className: "mr-1 h-4 w-4" }), " Close"]
152
+ }) : /* @__PURE__ */ M("span", {
153
+ className: "text-xs text-text-tertiary",
154
+ children: e.closedAt ? `Closed ${S(e.closedAt)}` : "—"
117
155
  })
118
156
  })
119
157
  ]
120
158
  }, e.id)) })] })
121
- }),
122
- u && /* @__PURE__ */ k(F, {
123
- onClose: () => _(!1),
124
- onSaved: (e) => N({
159
+ })] }),
160
+ d && /* @__PURE__ */ M(z, {
161
+ onClose: () => v(!1),
162
+ onSaved: (e) => R({
125
163
  tone: "success",
126
164
  text: `${e} opened.`
127
165
  })
128
166
  })
129
167
  ]
130
168
  });
131
- }, F = ({ onClose: t, onSaved: r }) => {
132
- let o = n(), s = e({ pagination: { limit: 100 } }), l = i(), [f, p] = S({
169
+ }, z = ({ onClose: t, onSaved: r }) => {
170
+ let o = n(), s = e({ pagination: { limit: 100 } }), l = i(), [u, p] = C({
133
171
  clientId: "",
134
172
  practiceAreaId: "",
135
173
  title: "",
@@ -138,35 +176,35 @@ var M = [
138
176
  priority: "MEDIUM",
139
177
  dueDate: "",
140
178
  isPrivileged: !1
141
- }), [m, h] = S(null), g = (e) => (t) => p((n) => ({
179
+ }), [m, h] = C(null), g = (e) => (t) => p((n) => ({
142
180
  ...n,
143
181
  [e]: t.target.value
144
182
  }));
145
- return /* @__PURE__ */ k(u, {
183
+ return /* @__PURE__ */ M(d, {
146
184
  open: !0,
147
185
  onClose: t,
148
186
  title: "New matter",
149
- footer: /* @__PURE__ */ A(O, { children: [/* @__PURE__ */ k(j, {
187
+ footer: /* @__PURE__ */ N(j, { children: [/* @__PURE__ */ M(P, {
150
188
  variant: "outline",
151
189
  onClick: t,
152
190
  disabled: o.isPending,
153
191
  children: "Cancel"
154
- }), /* @__PURE__ */ k(j, {
192
+ }), /* @__PURE__ */ M(P, {
155
193
  onClick: () => {
156
- if (h(null), !f.clientId) return h("Select a client.");
157
- if (!f.title.trim()) return h("Matter title is required.");
194
+ if (h(null), !u.clientId) return h("Select a client.");
195
+ if (!u.title.trim()) return h("Matter title is required.");
158
196
  o.mutate({
159
- clientId: f.clientId,
160
- practiceAreaId: f.practiceAreaId || null,
161
- title: f.title.trim(),
162
- reference: f.reference.trim() || null,
163
- description: f.description.trim() || null,
164
- priority: f.priority,
165
- isPrivileged: f.isPrivileged,
166
- dueDate: f.dueDate ? new Date(f.dueDate).toISOString() : null
197
+ clientId: u.clientId,
198
+ practiceAreaId: u.practiceAreaId || null,
199
+ title: u.title.trim(),
200
+ reference: u.reference.trim() || null,
201
+ description: u.description.trim() || null,
202
+ priority: u.priority,
203
+ isPrivileged: u.isPrivileged,
204
+ dueDate: u.dueDate ? new Date(u.dueDate).toISOString() : null
167
205
  }, {
168
206
  onSuccess: () => {
169
- r(f.title.trim()), t();
207
+ r(u.title.trim()), t();
170
208
  },
171
209
  onError: (e) => h(e instanceof Error ? e.message : "Failed.")
172
210
  });
@@ -174,102 +212,105 @@ var M = [
174
212
  disabled: o.isPending,
175
213
  children: o.isPending ? "Opening…" : "Open matter"
176
214
  })] }),
177
- children: /* @__PURE__ */ A("div", {
215
+ children: /* @__PURE__ */ N("div", {
178
216
  className: "space-y-3",
179
217
  children: [
180
- m && /* @__PURE__ */ k(a, {
218
+ m && /* @__PURE__ */ M(a, {
181
219
  tone: "danger",
182
220
  children: m
183
221
  }),
184
- /* @__PURE__ */ k(c, {
222
+ /* @__PURE__ */ M(c, {
185
223
  label: "Client",
186
224
  required: !0,
187
- children: /* @__PURE__ */ A(d, {
188
- value: f.clientId,
225
+ children: /* @__PURE__ */ N(f, {
226
+ value: u.clientId,
189
227
  onChange: g("clientId"),
190
- children: [/* @__PURE__ */ k("option", {
228
+ children: [/* @__PURE__ */ M("option", {
191
229
  value: "",
192
230
  children: "Select a client…"
193
- }), s.data?.items.map((e) => /* @__PURE__ */ k("option", {
231
+ }), s.data?.items.map((e) => /* @__PURE__ */ M("option", {
194
232
  value: e.id,
195
233
  children: e.name
196
234
  }, e.id))]
197
235
  })
198
236
  }),
199
- /* @__PURE__ */ k(c, {
237
+ /* @__PURE__ */ M(c, {
200
238
  label: "Title",
201
239
  required: !0,
202
- children: /* @__PURE__ */ k(v, {
203
- value: f.title,
240
+ children: /* @__PURE__ */ M(y, {
241
+ value: u.title,
204
242
  onChange: g("title"),
205
243
  placeholder: "Regulatory investigation — SEC inquiry"
206
244
  })
207
245
  }),
208
- /* @__PURE__ */ A("div", {
246
+ /* @__PURE__ */ N("div", {
209
247
  className: "grid grid-cols-2 gap-3",
210
- children: [/* @__PURE__ */ k(c, {
248
+ children: [/* @__PURE__ */ M(c, {
211
249
  label: "Reference",
212
- children: /* @__PURE__ */ k(v, {
213
- value: f.reference,
250
+ children: /* @__PURE__ */ M(y, {
251
+ value: u.reference,
214
252
  onChange: g("reference"),
215
253
  placeholder: "MAT-2026-014"
216
254
  })
217
- }), /* @__PURE__ */ k(c, {
255
+ }), /* @__PURE__ */ M(c, {
218
256
  label: "Priority",
219
- children: /* @__PURE__ */ k(d, {
220
- value: f.priority,
257
+ children: /* @__PURE__ */ M(f, {
258
+ value: u.priority,
221
259
  onChange: g("priority"),
222
- children: b(N)
260
+ children: x(I)
223
261
  })
224
262
  })]
225
263
  }),
226
- /* @__PURE__ */ A("div", {
264
+ /* @__PURE__ */ N("div", {
227
265
  className: "grid grid-cols-2 gap-3",
228
- children: [/* @__PURE__ */ k(c, {
266
+ children: [/* @__PURE__ */ M(c, {
229
267
  label: "Practice area",
230
- children: /* @__PURE__ */ A(d, {
231
- value: f.practiceAreaId,
268
+ children: /* @__PURE__ */ N(f, {
269
+ value: u.practiceAreaId,
232
270
  onChange: g("practiceAreaId"),
233
- children: [/* @__PURE__ */ k("option", {
271
+ children: [/* @__PURE__ */ M("option", {
234
272
  value: "",
235
273
  children: "Unassigned"
236
- }), l.data?.map((e) => /* @__PURE__ */ k("option", {
274
+ }), l.data?.map((e) => /* @__PURE__ */ M("option", {
237
275
  value: e.id,
238
276
  children: e.name
239
277
  }, e.id))]
240
278
  })
241
- }), /* @__PURE__ */ k(c, {
279
+ }), /* @__PURE__ */ M(c, {
242
280
  label: "Due date",
243
- children: /* @__PURE__ */ k(v, {
281
+ children: /* @__PURE__ */ M(y, {
244
282
  type: "date",
245
- value: f.dueDate,
283
+ value: u.dueDate,
246
284
  onChange: g("dueDate")
247
285
  })
248
286
  })]
249
287
  }),
250
- /* @__PURE__ */ k(c, {
288
+ /* @__PURE__ */ M(c, {
251
289
  label: "Description",
252
- children: /* @__PURE__ */ k(_, {
253
- value: f.description,
290
+ children: /* @__PURE__ */ M(v, {
291
+ value: u.description,
254
292
  onChange: g("description")
255
293
  })
256
294
  }),
257
- /* @__PURE__ */ A("label", {
258
- className: "flex items-center gap-2 text-sm text-text-secondary",
259
- children: [/* @__PURE__ */ k("input", {
295
+ /* @__PURE__ */ N("label", {
296
+ className: "flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-canvas px-3 py-2.5 text-sm text-text-secondary",
297
+ children: [/* @__PURE__ */ M("input", {
260
298
  type: "checkbox",
261
- checked: f.isPrivileged,
299
+ checked: u.isPrivileged,
262
300
  onChange: (e) => p((t) => ({
263
301
  ...t,
264
302
  isPrivileged: e.target.checked
265
303
  }))
266
- }), "Privileged / confidential matter"]
304
+ }), /* @__PURE__ */ N("span", {
305
+ className: "flex items-center gap-1.5",
306
+ children: [/* @__PURE__ */ M(O, { className: "h-3.5 w-3.5 text-status-warning-text" }), "Privileged / confidential matter"]
307
+ })]
267
308
  })
268
309
  ]
269
310
  })
270
311
  });
271
312
  };
272
313
  //#endregion
273
- export { P as MattersPage };
314
+ export { R as MattersPage };
274
315
 
275
316
  //# sourceMappingURL=MattersPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MattersPage.js","names":[],"sources":["../../../src/proserviceworld/pages/MattersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, FolderKanban, Lock, CheckCircle2 } from 'lucide-react';\nimport {\n useMatters,\n useCreateMatter,\n useCloseMatter,\n useClients,\n usePracticeAreas,\n type PswMatterStatus,\n} from '../hooks/useProServiceWorldApi';\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} from '../components/ui';\n\nconst STATUSES: PswMatterStatus[] = ['OPEN', 'ON_HOLD', 'CLOSED', 'ARCHIVED'];\nconst PRIORITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const;\n\nexport const MattersPage: FC = () => {\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswMatterStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const { data, isLoading, error, refetch } = useMatters({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n });\n const close = useCloseMatter();\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Matters\"\n subtitle=\"The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.\"\n icon={<FolderKanban className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New matter\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 matters…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswMatterStatus | '')}\n className=\"sm:w-48\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\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 matters yet\"\n description=\"Open a matter to track a regulated thread of work for a client.\"\n icon={<FolderKanban className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New matter\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${data.totalCount} matter${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Matter</Th>\n <Th>Client</Th>\n <Th>Priority</Th>\n <Th>Status</Th>\n <Th>Due</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((m) => (\n <tr key={m.id} className=\"hover:bg-bg-sunken/50\">\n <Td>\n <span className=\"flex items-center gap-1.5 font-medium text-text-primary\">\n {m.isPrivileged && (\n <Lock\n className=\"h-3.5 w-3.5 text-status-warning-text\"\n aria-label=\"Privileged\"\n />\n )}\n {m.title}\n </span>\n {m.reference ? (\n <div className=\"text-xs text-text-tertiary\">{m.reference}</div>\n ) : null}\n </Td>\n <Td>{m.client?.name ?? '—'}</Td>\n <Td>\n <StatusPill status={m.priority} />\n </Td>\n <Td>\n <StatusPill status={m.status} />\n </Td>\n <Td>{fmtDate(m.dueDate)}</Td>\n <Td className=\"text-right\">\n {m.status !== 'CLOSED' && m.status !== 'ARCHIVED' && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={close.isPending}\n onClick={() =>\n close.mutate(m.id, {\n onSuccess: () =>\n setBanner({ tone: 'success', text: `${m.title} closed.` }),\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Failed.',\n }),\n })\n }\n >\n <CheckCircle2 className=\"mr-1 h-4 w-4\" /> Close\n </Button>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <MatterModal\n onClose={() => setCreating(false)}\n onSaved={(t) => setBanner({ tone: 'success', text: `${t} opened.` })}\n />\n )}\n </div>\n );\n};\n\nconst MatterModal: FC<{ onClose: () => void; onSaved: (title: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const create = useCreateMatter();\n const clients = useClients({ pagination: { limit: 100 } });\n const practiceAreas = usePracticeAreas();\n const [form, setForm] = useState({\n clientId: '',\n practiceAreaId: '',\n title: '',\n reference: '',\n description: '',\n priority: 'MEDIUM',\n dueDate: '',\n isPrivileged: false,\n });\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof typeof form) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n\n const submit = () => {\n setErr(null);\n if (!form.clientId) return setErr('Select a client.');\n if (!form.title.trim()) return setErr('Matter title is required.');\n create.mutate(\n {\n clientId: form.clientId,\n practiceAreaId: form.practiceAreaId || null,\n title: form.title.trim(),\n reference: form.reference.trim() || null,\n description: form.description.trim() || null,\n priority: form.priority,\n isPrivileged: form.isPrivileged,\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n },\n {\n onSuccess: () => {\n onSaved(form.title.trim());\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"New matter\"\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={create.isPending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={create.isPending}>\n {create.isPending ? 'Opening…' : 'Open matter'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Client\" required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\n <option value=\"\">Select a client…</option>\n {clients.data?.items.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Title\" required>\n <TextInput\n value={form.title}\n onChange={set('title')}\n placeholder=\"Regulatory investigation — SEC inquiry\"\n />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Reference\">\n <TextInput\n value={form.reference}\n onChange={set('reference')}\n placeholder=\"MAT-2026-014\"\n />\n </Field>\n <Field label=\"Priority\">\n <NativeSelect value={form.priority} onChange={set('priority')}>\n {enumOptions(PRIORITIES)}\n </NativeSelect>\n </Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Practice area\">\n <NativeSelect value={form.practiceAreaId} onChange={set('practiceAreaId')}>\n <option value=\"\">Unassigned</option>\n {practiceAreas.data?.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Due date\">\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n </div>\n <Field label=\"Description\">\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n <label className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.isPrivileged}\n onChange={(e) => setForm((f) => ({ ...f, isPrivileged: e.target.checked }))}\n />\n Privileged / confidential matter\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"MattersPage.js","names":[],"sources":["../../../src/proserviceworld/pages/MattersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n FolderKanban,\n Lock,\n CheckCircle2,\n CircleDot,\n AlertTriangle,\n} from 'lucide-react';\nimport {\n useMatters,\n useCreateMatter,\n useCloseMatter,\n useClients,\n usePracticeAreas,\n type PswMatterStatus,\n} from '../hooks/useProServiceWorldApi';\nimport {\n PageHeader,\n SectionCard,\n MetricCard,\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} from '../components/ui';\n\nconst STATUSES: PswMatterStatus[] = ['OPEN', 'ON_HOLD', 'CLOSED', 'ARCHIVED'];\nconst PRIORITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const;\n\n/** Amber padlock chip that flags privileged / confidential matters. */\nconst PrivilegeLock: FC = () => (\n <span\n className=\"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text\"\n title=\"Privileged / confidential\"\n aria-label=\"Privileged\"\n >\n <Lock className=\"h-3 w-3\" />\n </span>\n);\n\nexport const MattersPage: FC = () => {\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswMatterStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const { data, isLoading, error, refetch } = useMatters({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n });\n const close = useCloseMatter();\n\n const items = data?.items ?? [];\n const openCount = items.filter((m) => m.status === 'OPEN').length;\n const privilegedCount = items.filter((m) => m.isPrivileged).length;\n const highCount = items.filter((m) => m.priority === 'HIGH' || m.priority === 'CRITICAL').length;\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Matters\"\n subtitle=\"The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.\"\n icon={<FolderKanban className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New matter\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 matters…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswMatterStatus | '')}\n className=\"sm:w-48\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\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 matters yet\"\n description=\"Open a matter to track a regulated thread of work for a client.\"\n icon={<FolderKanban className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New matter\n </Button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <MetricCard\n label=\"Matters\"\n value={data.totalCount}\n icon={<FolderKanban className=\"h-4 w-4\" />}\n />\n <MetricCard\n label=\"Open\"\n value={openCount}\n icon={<CircleDot className=\"h-4 w-4\" />}\n tone=\"accent\"\n />\n <MetricCard\n label=\"Privileged\"\n value={privilegedCount}\n icon={<Lock className=\"h-4 w-4\" />}\n tone=\"warning\"\n />\n <MetricCard\n label=\"High priority\"\n value={highCount}\n icon={<AlertTriangle className=\"h-4 w-4\" />}\n tone={highCount ? 'danger' : 'neutral'}\n />\n </div>\n\n <SectionCard title={`${data.totalCount} matter${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Matter</Th>\n <Th>Client</Th>\n <Th>Priority</Th>\n <Th>Status</Th>\n <Th>Due</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((m) => (\n <tr key={m.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"flex items-center gap-2 font-medium text-text-primary\">\n {m.isPrivileged && <PrivilegeLock />}\n <span className=\"truncate\">{m.title}</span>\n </span>\n {m.reference ? (\n <div className=\"mt-0.5 pl-0 text-xs text-text-tertiary\">\n Ref: {m.reference}\n </div>\n ) : null}\n </Td>\n <Td className=\"text-text-primary\">{m.client?.name ?? '—'}</Td>\n <Td>\n <StatusPill status={m.priority} />\n </Td>\n <Td>\n <StatusPill status={m.status} />\n </Td>\n <Td>{fmtDate(m.dueDate)}</Td>\n <Td className=\"text-right\">\n {m.status !== 'CLOSED' && m.status !== 'ARCHIVED' ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={close.isPending}\n onClick={() =>\n close.mutate(m.id, {\n onSuccess: () =>\n setBanner({ tone: 'success', text: `${m.title} closed.` }),\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Failed.',\n }),\n })\n }\n >\n <CheckCircle2 className=\"mr-1 h-4 w-4\" /> Close\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {m.closedAt ? `Closed ${fmtDate(m.closedAt)}` : '—'}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n </>\n )}\n\n {creating && (\n <MatterModal\n onClose={() => setCreating(false)}\n onSaved={(t) => setBanner({ tone: 'success', text: `${t} opened.` })}\n />\n )}\n </div>\n );\n};\n\nconst MatterModal: FC<{ onClose: () => void; onSaved: (title: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const create = useCreateMatter();\n const clients = useClients({ pagination: { limit: 100 } });\n const practiceAreas = usePracticeAreas();\n const [form, setForm] = useState({\n clientId: '',\n practiceAreaId: '',\n title: '',\n reference: '',\n description: '',\n priority: 'MEDIUM',\n dueDate: '',\n isPrivileged: false,\n });\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof typeof form) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n\n const submit = () => {\n setErr(null);\n if (!form.clientId) return setErr('Select a client.');\n if (!form.title.trim()) return setErr('Matter title is required.');\n create.mutate(\n {\n clientId: form.clientId,\n practiceAreaId: form.practiceAreaId || null,\n title: form.title.trim(),\n reference: form.reference.trim() || null,\n description: form.description.trim() || null,\n priority: form.priority,\n isPrivileged: form.isPrivileged,\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n },\n {\n onSuccess: () => {\n onSaved(form.title.trim());\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"New matter\"\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={create.isPending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={create.isPending}>\n {create.isPending ? 'Opening…' : 'Open matter'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Client\" required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\n <option value=\"\">Select a client…</option>\n {clients.data?.items.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Title\" required>\n <TextInput\n value={form.title}\n onChange={set('title')}\n placeholder=\"Regulatory investigation — SEC inquiry\"\n />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Reference\">\n <TextInput\n value={form.reference}\n onChange={set('reference')}\n placeholder=\"MAT-2026-014\"\n />\n </Field>\n <Field label=\"Priority\">\n <NativeSelect value={form.priority} onChange={set('priority')}>\n {enumOptions(PRIORITIES)}\n </NativeSelect>\n </Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Practice area\">\n <NativeSelect value={form.practiceAreaId} onChange={set('practiceAreaId')}>\n <option value=\"\">Unassigned</option>\n {practiceAreas.data?.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Due date\">\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n </div>\n <Field label=\"Description\">\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n <label className=\"flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-canvas px-3 py-2.5 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.isPrivileged}\n onChange={(e) => setForm((f) => ({ ...f, isPrivileged: e.target.checked }))}\n />\n <span className=\"flex items-center gap-1.5\">\n <Lock className=\"h-3.5 w-3.5 text-status-warning-text\" />\n Privileged / confidential matter\n </span>\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}