@burdenoff/microfe-proserviceworld 2026.703.1 → 2026.706.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.
Files changed (79) hide show
  1. package/dist/index.js +2 -3
  2. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  3. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  4. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  5. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  6. package/dist/proserviceworld/ProServiceWorldRoot.js +92 -136
  7. package/dist/proserviceworld/ProServiceWorldRoot.js.map +1 -1
  8. package/dist/proserviceworld/ProServiceWorldRoutes.js +18 -26
  9. package/dist/proserviceworld/ProServiceWorldRoutes.js.map +1 -1
  10. package/dist/proserviceworld/components/DiscussionThread.js +76 -0
  11. package/dist/proserviceworld/components/DiscussionThread.js.map +1 -0
  12. package/dist/proserviceworld/components/ui.js +273 -0
  13. package/dist/proserviceworld/components/ui.js.map +1 -0
  14. package/dist/proserviceworld/hooks/useEntityComments.js +56 -0
  15. package/dist/proserviceworld/hooks/useEntityComments.js.map +1 -0
  16. package/dist/proserviceworld/hooks/useFiles.js +45 -0
  17. package/dist/proserviceworld/hooks/useFiles.js.map +1 -0
  18. package/dist/proserviceworld/hooks/useProServiceWorldApi.js +416 -0
  19. package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -0
  20. package/dist/proserviceworld/index.js +0 -1
  21. package/dist/proserviceworld/pages/AnalyticsPage.js +163 -475
  22. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  23. package/dist/proserviceworld/pages/ClientDetailPage.js +243 -0
  24. package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -0
  25. package/dist/proserviceworld/pages/ClientsPage.js +295 -0
  26. package/dist/proserviceworld/pages/ClientsPage.js.map +1 -0
  27. package/dist/proserviceworld/pages/CompliancePage.js +307 -0
  28. package/dist/proserviceworld/pages/CompliancePage.js.map +1 -0
  29. package/dist/proserviceworld/pages/ConflictsPage.js +234 -0
  30. package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -0
  31. package/dist/proserviceworld/pages/DashboardPage.js +179 -632
  32. package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
  33. package/dist/proserviceworld/pages/DocumentsPage.js +235 -539
  34. package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
  35. package/dist/proserviceworld/pages/EngagementDetailPage.js +449 -0
  36. package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -0
  37. package/dist/proserviceworld/pages/EngagementsPage.js +256 -0
  38. package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -0
  39. package/dist/proserviceworld/pages/InvoicesPage.js +303 -0
  40. package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -0
  41. package/dist/proserviceworld/pages/MattersPage.js +275 -0
  42. package/dist/proserviceworld/pages/MattersPage.js.map +1 -0
  43. package/dist/proserviceworld/pages/PracticeAreasPage.js +176 -0
  44. package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -0
  45. package/dist/proserviceworld/pages/TimePage.js +310 -0
  46. package/dist/proserviceworld/pages/TimePage.js.map +1 -0
  47. package/dist/proserviceworld/utils/cn.js +10 -0
  48. package/dist/proserviceworld/utils/cn.js.map +1 -0
  49. package/dist/proserviceworld/utils/nav.js +11 -0
  50. package/dist/proserviceworld/utils/nav.js.map +1 -0
  51. package/package.json +1 -1
  52. package/dist/proserviceworld/pages/AdminReportsPage.js +0 -579
  53. package/dist/proserviceworld/pages/AdminReportsPage.js.map +0 -1
  54. package/dist/proserviceworld/pages/AdminUsersPage.js +0 -468
  55. package/dist/proserviceworld/pages/AdminUsersPage.js.map +0 -1
  56. package/dist/proserviceworld/pages/BookingsPage.js +0 -446
  57. package/dist/proserviceworld/pages/BookingsPage.js.map +0 -1
  58. package/dist/proserviceworld/pages/MessagesPage.js +0 -238
  59. package/dist/proserviceworld/pages/MessagesPage.js.map +0 -1
  60. package/dist/proserviceworld/pages/PaymentsPage.js +0 -537
  61. package/dist/proserviceworld/pages/PaymentsPage.js.map +0 -1
  62. package/dist/proserviceworld/pages/ProjectsPage.js +0 -627
  63. package/dist/proserviceworld/pages/ProjectsPage.js.map +0 -1
  64. package/dist/proserviceworld/pages/ProviderDetailPage.js +0 -538
  65. package/dist/proserviceworld/pages/ProviderDetailPage.js.map +0 -1
  66. package/dist/proserviceworld/pages/ProvidersPage.js +0 -347
  67. package/dist/proserviceworld/pages/ProvidersPage.js.map +0 -1
  68. package/dist/proserviceworld/pages/ReviewsPage.js +0 -356
  69. package/dist/proserviceworld/pages/ReviewsPage.js.map +0 -1
  70. package/dist/proserviceworld/pages/ServiceDetailsPage.js +0 -631
  71. package/dist/proserviceworld/pages/ServiceDetailsPage.js.map +0 -1
  72. package/dist/proserviceworld/pages/ServicesPage.js +0 -344
  73. package/dist/proserviceworld/pages/ServicesPage.js.map +0 -1
  74. package/dist/proserviceworld/pages/VerificationPage.js +0 -370
  75. package/dist/proserviceworld/pages/VerificationPage.js.map +0 -1
  76. package/dist/proserviceworld/store/proserviceworldStore.js +0 -2490
  77. package/dist/proserviceworld/store/proserviceworldStore.js.map +0 -1
  78. package/dist/proserviceworld/utils/i18n.js +0 -15
  79. package/dist/proserviceworld/utils/i18n.js.map +0 -1
@@ -0,0 +1,295 @@
1
+ import { useArchiveClient as e, useClients as t, useCreateClient as n, useUpdateClient as r } from "../hooks/useProServiceWorldApi.js";
2
+ import { useNav as i } from "../utils/nav.js";
3
+ 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";
4
+ import { useMemo as S, useState as C } from "react";
5
+ import { Archive as w, Pencil as T, Plus as E, Search as D, Users as O } from "lucide-react";
6
+ import { Fragment as k, jsx as A, jsxs as j } from "react/jsx-runtime";
7
+ import { Button as M } from "@burdenoff/fe-libs/ui";
8
+ //#region src/proserviceworld/pages/ClientsPage.tsx
9
+ var N = ["ORGANIZATION", "INDIVIDUAL"], P = [
10
+ "PROSPECT",
11
+ "ACTIVE",
12
+ "INACTIVE",
13
+ "ARCHIVED"
14
+ ], F = {
15
+ name: "",
16
+ type: "ORGANIZATION",
17
+ status: "PROSPECT",
18
+ industry: "",
19
+ contactName: "",
20
+ contactEmail: "",
21
+ contactPhone: "",
22
+ notes: ""
23
+ }, I = () => {
24
+ let e = i(), [n, r] = C(""), [c, u] = C(""), [_, S] = C(null), [w, k] = C(!1), [N, F] = C(null), { data: I, isLoading: z, error: B, refetch: V } = t({
25
+ search: n.trim() || void 0,
26
+ status: c || void 0
27
+ });
28
+ return /* @__PURE__ */ j("div", {
29
+ className: "space-y-6",
30
+ children: [
31
+ /* @__PURE__ */ A(f, {
32
+ title: "Clients",
33
+ subtitle: "Every person or organization your firm serves — the record engagements, matters, documents and invoices hang off.",
34
+ icon: /* @__PURE__ */ A(O, { className: "h-6 w-6" }),
35
+ actions: /* @__PURE__ */ j(M, {
36
+ onClick: () => k(!0),
37
+ children: [/* @__PURE__ */ A(E, { className: "mr-1.5 h-4 w-4" }), " New client"]
38
+ })
39
+ }),
40
+ N && /* @__PURE__ */ A(a, {
41
+ tone: N.tone,
42
+ onClose: () => F(null),
43
+ children: N.text
44
+ }),
45
+ /* @__PURE__ */ j("div", {
46
+ className: "flex flex-col gap-2 sm:flex-row sm:items-center",
47
+ children: [/* @__PURE__ */ j("div", {
48
+ className: "relative flex-1",
49
+ children: [/* @__PURE__ */ A(D, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ A(v, {
50
+ placeholder: "Search clients…",
51
+ value: n,
52
+ onChange: (e) => r(e.target.value),
53
+ className: "pl-9"
54
+ })]
55
+ }), /* @__PURE__ */ j(d, {
56
+ value: c,
57
+ onChange: (e) => u(e.target.value),
58
+ className: "sm:w-48",
59
+ children: [/* @__PURE__ */ A("option", {
60
+ value: "",
61
+ children: "All statuses"
62
+ }), b(P)]
63
+ })]
64
+ }),
65
+ z ? /* @__PURE__ */ A(l, {}) : B ? /* @__PURE__ */ A(s, {
66
+ error: B,
67
+ onRetry: () => void V()
68
+ }) : !I || I.items.length === 0 ? /* @__PURE__ */ A(o, {
69
+ title: "No clients yet",
70
+ description: "Add your first client to start scoping engagements and matters.",
71
+ icon: /* @__PURE__ */ A(O, { className: "h-8 w-8" }),
72
+ action: /* @__PURE__ */ j(M, {
73
+ onClick: () => k(!0),
74
+ children: [/* @__PURE__ */ A(E, { className: "mr-1.5 h-4 w-4" }), " New client"]
75
+ })
76
+ }) : /* @__PURE__ */ A(p, {
77
+ title: `${I.totalCount} client${I.totalCount === 1 ? "" : "s"}`,
78
+ children: /* @__PURE__ */ j(h, { children: [/* @__PURE__ */ A("thead", { children: /* @__PURE__ */ j("tr", { children: [
79
+ /* @__PURE__ */ A(y, { children: "Name" }),
80
+ /* @__PURE__ */ A(y, { children: "Type" }),
81
+ /* @__PURE__ */ A(y, { children: "Industry" }),
82
+ /* @__PURE__ */ A(y, { children: "Status" }),
83
+ /* @__PURE__ */ A(y, { children: "Added" }),
84
+ /* @__PURE__ */ A(y, {
85
+ className: "text-right",
86
+ children: "Actions"
87
+ })
88
+ ] }) }), /* @__PURE__ */ A("tbody", { children: I.items.map((t) => /* @__PURE__ */ j("tr", {
89
+ className: "hover:bg-bg-sunken/50",
90
+ children: [
91
+ /* @__PURE__ */ j(g, { children: [/* @__PURE__ */ A("button", {
92
+ type: "button",
93
+ className: "text-left font-medium text-text-primary hover:text-accent",
94
+ onClick: () => e(`clients/${t.id}`),
95
+ children: t.name
96
+ }), t.contactName ? /* @__PURE__ */ A("div", {
97
+ className: "text-xs text-text-tertiary",
98
+ children: t.contactName
99
+ }) : null] }),
100
+ /* @__PURE__ */ A(g, { children: t.type === "ORGANIZATION" ? "Organization" : "Individual" }),
101
+ /* @__PURE__ */ A(g, { children: t.industry || "—" }),
102
+ /* @__PURE__ */ A(g, { children: /* @__PURE__ */ A(m, { status: t.status }) }),
103
+ /* @__PURE__ */ A(g, { children: x(t.createdAt) }),
104
+ /* @__PURE__ */ A(g, {
105
+ className: "text-right",
106
+ children: /* @__PURE__ */ j("div", {
107
+ className: "flex justify-end gap-1",
108
+ children: [/* @__PURE__ */ A(M, {
109
+ variant: "ghost",
110
+ size: "sm",
111
+ onClick: () => S(t),
112
+ "aria-label": "Edit",
113
+ children: /* @__PURE__ */ A(T, { className: "h-4 w-4" })
114
+ }), t.status !== "ARCHIVED" && /* @__PURE__ */ A(L, {
115
+ id: t.id,
116
+ onDone: (e) => F(e ? {
117
+ tone: "success",
118
+ text: `${t.name} archived.`
119
+ } : {
120
+ tone: "danger",
121
+ text: "Could not archive client."
122
+ })
123
+ })]
124
+ })
125
+ })
126
+ ]
127
+ }, t.id)) })] })
128
+ }),
129
+ w && /* @__PURE__ */ A(R, {
130
+ onClose: () => k(!1),
131
+ onSaved: (e) => F({
132
+ tone: "success",
133
+ text: `${e} created.`
134
+ })
135
+ }),
136
+ _ && /* @__PURE__ */ A(R, {
137
+ client: _,
138
+ onClose: () => S(null),
139
+ onSaved: (e) => F({
140
+ tone: "success",
141
+ text: `${e} updated.`
142
+ })
143
+ })
144
+ ]
145
+ });
146
+ }, L = ({ id: t, onDone: n }) => {
147
+ let r = e();
148
+ return /* @__PURE__ */ A(M, {
149
+ variant: "ghost",
150
+ size: "sm",
151
+ "aria-label": "Archive",
152
+ disabled: r.isPending,
153
+ onClick: () => {
154
+ window.confirm("Archive this client? Their engagements and matters remain.") && r.mutate(t, {
155
+ onSuccess: (e) => n(!!e),
156
+ onError: () => n(!1)
157
+ });
158
+ },
159
+ children: /* @__PURE__ */ A(w, { className: "h-4 w-4" })
160
+ });
161
+ }, R = ({ client: e, onClose: t, onSaved: i }) => {
162
+ let o = n(), s = r(), [l, f] = C(e ? {
163
+ name: e.name,
164
+ type: e.type,
165
+ status: e.status,
166
+ industry: e.industry ?? "",
167
+ contactName: e.contactName ?? "",
168
+ contactEmail: e.contactEmail ?? "",
169
+ contactPhone: e.contactPhone ?? "",
170
+ notes: e.notes ?? ""
171
+ } : F), [p, m] = C(null), h = (e) => (t) => f((n) => ({
172
+ ...n,
173
+ [e]: t.target.value
174
+ })), g = o.isPending || s.isPending, y = S(() => ({
175
+ name: l.name.trim(),
176
+ type: l.type,
177
+ status: l.status,
178
+ industry: l.industry.trim() || null,
179
+ contactName: l.contactName.trim() || null,
180
+ contactEmail: l.contactEmail.trim() || null,
181
+ contactPhone: l.contactPhone.trim() || null,
182
+ notes: l.notes.trim() || null
183
+ }), [l]);
184
+ return /* @__PURE__ */ A(u, {
185
+ open: !0,
186
+ onClose: t,
187
+ title: e ? "Edit client" : "New client",
188
+ footer: /* @__PURE__ */ j(k, { children: [/* @__PURE__ */ A(M, {
189
+ variant: "outline",
190
+ onClick: t,
191
+ disabled: g,
192
+ children: "Cancel"
193
+ }), /* @__PURE__ */ A(M, {
194
+ onClick: () => {
195
+ if (m(null), !y.name) return m("Client name is required.");
196
+ let n = (e) => m(e instanceof Error ? e.message : "Save failed.");
197
+ e ? s.mutate({
198
+ id: e.id,
199
+ input: y
200
+ }, {
201
+ onSuccess: () => {
202
+ i(y.name), t();
203
+ },
204
+ onError: n
205
+ }) : o.mutate(y, {
206
+ onSuccess: () => {
207
+ i(y.name), t();
208
+ },
209
+ onError: n
210
+ });
211
+ },
212
+ disabled: g,
213
+ children: g ? "Saving…" : e ? "Save changes" : "Create client"
214
+ })] }),
215
+ children: /* @__PURE__ */ j("div", {
216
+ className: "space-y-3",
217
+ children: [
218
+ p && /* @__PURE__ */ A(a, {
219
+ tone: "danger",
220
+ children: p
221
+ }),
222
+ /* @__PURE__ */ A(c, {
223
+ label: "Name",
224
+ required: !0,
225
+ children: /* @__PURE__ */ A(v, {
226
+ value: l.name,
227
+ onChange: h("name"),
228
+ placeholder: "Acme Holdings Ltd."
229
+ })
230
+ }),
231
+ /* @__PURE__ */ j("div", {
232
+ className: "grid grid-cols-2 gap-3",
233
+ children: [/* @__PURE__ */ A(c, {
234
+ label: "Type",
235
+ children: /* @__PURE__ */ A(d, {
236
+ value: l.type,
237
+ onChange: h("type"),
238
+ children: b(N)
239
+ })
240
+ }), /* @__PURE__ */ A(c, {
241
+ label: "Status",
242
+ children: /* @__PURE__ */ A(d, {
243
+ value: l.status,
244
+ onChange: h("status"),
245
+ children: b(P)
246
+ })
247
+ })]
248
+ }),
249
+ /* @__PURE__ */ A(c, {
250
+ label: "Industry",
251
+ children: /* @__PURE__ */ A(v, {
252
+ value: l.industry,
253
+ onChange: h("industry"),
254
+ placeholder: "Financial services"
255
+ })
256
+ }),
257
+ /* @__PURE__ */ j("div", {
258
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-2",
259
+ children: [/* @__PURE__ */ A(c, {
260
+ label: "Contact name",
261
+ children: /* @__PURE__ */ A(v, {
262
+ value: l.contactName,
263
+ onChange: h("contactName")
264
+ })
265
+ }), /* @__PURE__ */ A(c, {
266
+ label: "Contact email",
267
+ children: /* @__PURE__ */ A(v, {
268
+ type: "email",
269
+ value: l.contactEmail,
270
+ onChange: h("contactEmail")
271
+ })
272
+ })]
273
+ }),
274
+ /* @__PURE__ */ A(c, {
275
+ label: "Contact phone",
276
+ children: /* @__PURE__ */ A(v, {
277
+ value: l.contactPhone,
278
+ onChange: h("contactPhone")
279
+ })
280
+ }),
281
+ /* @__PURE__ */ A(c, {
282
+ label: "Notes",
283
+ children: /* @__PURE__ */ A(_, {
284
+ value: l.notes,
285
+ onChange: h("notes")
286
+ })
287
+ })
288
+ ]
289
+ })
290
+ });
291
+ };
292
+ //#endregion
293
+ export { I as ClientsPage };
294
+
295
+ //# sourceMappingURL=ClientsPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClientsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ClientsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, Users, Pencil, Archive } from 'lucide-react';\nimport {\n useClients,\n useCreateClient,\n useUpdateClient,\n useArchiveClient,\n type PswClient,\n type PswClientStatus,\n} from '../hooks/useProServiceWorldApi';\nimport { useNav } from '../utils/nav';\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 CLIENT_TYPES = ['ORGANIZATION', 'INDIVIDUAL'] as const;\nconst CLIENT_STATUSES: PswClientStatus[] = ['PROSPECT', 'ACTIVE', 'INACTIVE', 'ARCHIVED'];\n\ninterface FormState {\n name: string;\n type: string;\n status: string;\n industry: string;\n contactName: string;\n contactEmail: string;\n contactPhone: string;\n notes: string;\n}\nconst emptyForm: FormState = {\n name: '',\n type: 'ORGANIZATION',\n status: 'PROSPECT',\n industry: '',\n contactName: '',\n contactEmail: '',\n contactPhone: '',\n notes: '',\n};\n\nexport const ClientsPage: FC = () => {\n const nav = useNav();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswClientStatus | ''>('');\n const [editing, setEditing] = useState<PswClient | null>(null);\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n\n const { data, isLoading, error, refetch } = useClients({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n });\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Clients\"\n subtitle=\"Every person or organization your firm serves — the record engagements, matters, documents and invoices hang off.\"\n icon={<Users className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New client\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 clients…\"\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 PswClientStatus | '')}\n className=\"sm:w-48\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(CLIENT_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 clients yet\"\n description=\"Add your first client to start scoping engagements and matters.\"\n icon={<Users className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New client\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${data.totalCount} client${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Name</Th>\n <Th>Type</Th>\n <Th>Industry</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((c) => (\n <tr key={c.id} className=\"hover:bg-bg-sunken/50\">\n <Td>\n <button\n type=\"button\"\n className=\"text-left font-medium text-text-primary hover:text-accent\"\n onClick={() => nav(`clients/${c.id}`)}\n >\n {c.name}\n </button>\n {c.contactName ? (\n <div className=\"text-xs text-text-tertiary\">{c.contactName}</div>\n ) : null}\n </Td>\n <Td>{c.type === 'ORGANIZATION' ? 'Organization' : 'Individual'}</Td>\n <Td>{c.industry || '—'}</Td>\n <Td>\n <StatusPill status={c.status} />\n </Td>\n <Td>{fmtDate(c.createdAt)}</Td>\n <Td className=\"text-right\">\n <div className=\"flex justify-end gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setEditing(c)}\n aria-label=\"Edit\"\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n {c.status !== 'ARCHIVED' && (\n <ArchiveButton\n id={c.id}\n onDone={(ok) =>\n setBanner(\n ok\n ? { tone: 'success', text: `${c.name} archived.` }\n : { tone: 'danger', text: 'Could not archive client.' }\n )\n }\n />\n )}\n </div>\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <ClientModal\n onClose={() => setCreating(false)}\n onSaved={(name) => setBanner({ tone: 'success', text: `${name} created.` })}\n />\n )}\n {editing && (\n <ClientModal\n client={editing}\n onClose={() => setEditing(null)}\n onSaved={(name) => setBanner({ tone: 'success', text: `${name} updated.` })}\n />\n )}\n </div>\n );\n};\n\nconst ArchiveButton: FC<{ id: string; onDone: (ok: boolean) => void }> = ({ id, onDone }) => {\n const archive = useArchiveClient();\n return (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Archive\"\n disabled={archive.isPending}\n onClick={() => {\n if (!window.confirm('Archive this client? Their engagements and matters remain.')) return;\n archive.mutate(id, { onSuccess: (r) => onDone(Boolean(r)), onError: () => onDone(false) });\n }}\n >\n <Archive className=\"h-4 w-4\" />\n </Button>\n );\n};\n\nconst ClientModal: FC<{\n client?: PswClient;\n onClose: () => void;\n onSaved: (name: string) => void;\n}> = ({ client, onClose, onSaved }) => {\n const create = useCreateClient();\n const update = useUpdateClient();\n const [form, setForm] = useState<FormState>(\n client\n ? {\n name: client.name,\n type: client.type,\n status: client.status,\n industry: client.industry ?? '',\n contactName: client.contactName ?? '',\n contactEmail: client.contactEmail ?? '',\n contactPhone: client.contactPhone ?? '',\n notes: client.notes ?? '',\n }\n : emptyForm\n );\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof FormState) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n const pending = create.isPending || update.isPending;\n\n const payload = useMemo(\n () => ({\n name: form.name.trim(),\n type: form.type,\n status: form.status,\n industry: form.industry.trim() || null,\n contactName: form.contactName.trim() || null,\n contactEmail: form.contactEmail.trim() || null,\n contactPhone: form.contactPhone.trim() || null,\n notes: form.notes.trim() || null,\n }),\n [form]\n );\n\n const submit = () => {\n setErr(null);\n if (!payload.name) return setErr('Client name is required.');\n const onError = (e: unknown) => setErr(e instanceof Error ? e.message : 'Save failed.');\n if (client) {\n update.mutate(\n { id: client.id, input: payload },\n {\n onSuccess: () => {\n onSaved(payload.name);\n onClose();\n },\n onError,\n }\n );\n } else {\n create.mutate(payload, {\n onSuccess: () => {\n onSaved(payload.name);\n onClose();\n },\n onError,\n });\n }\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title={client ? 'Edit client' : 'New client'}\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={pending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={pending}>\n {pending ? 'Saving…' : client ? 'Save changes' : 'Create client'}\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 value={form.name} onChange={set('name')} placeholder=\"Acme Holdings Ltd.\" />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Type\">\n <NativeSelect value={form.type} onChange={set('type')}>\n {enumOptions(CLIENT_TYPES)}\n </NativeSelect>\n </Field>\n <Field label=\"Status\">\n <NativeSelect value={form.status} onChange={set('status')}>\n {enumOptions(CLIENT_STATUSES)}\n </NativeSelect>\n </Field>\n </div>\n <Field label=\"Industry\">\n <TextInput\n value={form.industry}\n onChange={set('industry')}\n placeholder=\"Financial services\"\n />\n </Field>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <Field label=\"Contact name\">\n <TextInput value={form.contactName} onChange={set('contactName')} />\n </Field>\n <Field label=\"Contact email\">\n <TextInput type=\"email\" value={form.contactEmail} onChange={set('contactEmail')} />\n </Field>\n </div>\n <Field label=\"Contact phone\">\n <TextInput value={form.contactPhone} onChange={set('contactPhone')} />\n </Field>\n <Field label=\"Notes\">\n <TextArea value={form.notes} onChange={set('notes')} />\n </Field>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,307 @@
1
+ import { useClients as e, useComplianceChecks as t, useCreateComplianceCheck as n, useEngagements as r, useMatters as i, useResolveComplianceCheck as a } from "../hooks/useProServiceWorldApi.js";
2
+ import { Banner as o, Empty as s, ErrorState as c, Field as l, LoadingBlock 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, humanize as C } from "../components/ui.js";
3
+ import { useState as w } from "react";
4
+ import { Plus as T, ShieldCheck as E } from "lucide-react";
5
+ import { Fragment as D, jsx as O, jsxs as k } from "react/jsx-runtime";
6
+ import { Button as A } from "@burdenoff/fe-libs/ui";
7
+ //#region src/proserviceworld/pages/CompliancePage.tsx
8
+ var j = [
9
+ "ENGAGEMENT_ACCEPTANCE",
10
+ "INDEPENDENCE",
11
+ "LICENSING",
12
+ "CONTINUING_EDUCATION",
13
+ "DATA_RETENTION",
14
+ "LEGAL_HOLD"
15
+ ], M = [
16
+ "IN_REVIEW",
17
+ "PASSED",
18
+ "FAILED",
19
+ "WAIVED"
20
+ ], N = [
21
+ "CLIENT",
22
+ "ENGAGEMENT",
23
+ "MATTER"
24
+ ], P = () => {
25
+ let [e, n] = w(""), [r, i] = w(!1), [a, l] = w(null), [d, v] = w(null), { data: y, isLoading: D, error: j, refetch: M } = t({ status: e || void 0 });
26
+ return /* @__PURE__ */ k("div", {
27
+ className: "space-y-6",
28
+ children: [
29
+ /* @__PURE__ */ O(p, {
30
+ title: "Compliance",
31
+ subtitle: "The duties that travel with the work — acceptance, independence, licensing, CE, retention and legal hold — as gates, not afterthoughts.",
32
+ icon: /* @__PURE__ */ O(E, { className: "h-6 w-6" }),
33
+ actions: /* @__PURE__ */ k(A, {
34
+ onClick: () => i(!0),
35
+ children: [/* @__PURE__ */ O(T, { className: "mr-1.5 h-4 w-4" }), "New check"]
36
+ })
37
+ }),
38
+ d && /* @__PURE__ */ O(o, {
39
+ tone: "success",
40
+ onClose: () => v(null),
41
+ children: d
42
+ }),
43
+ /* @__PURE__ */ O("div", {
44
+ className: "flex justify-end",
45
+ children: /* @__PURE__ */ k(f, {
46
+ value: e,
47
+ onChange: (e) => n(e.target.value),
48
+ className: "sm:w-52",
49
+ children: [/* @__PURE__ */ O("option", {
50
+ value: "",
51
+ children: "All statuses"
52
+ }), x([
53
+ "PENDING",
54
+ "IN_REVIEW",
55
+ "PASSED",
56
+ "FAILED",
57
+ "WAIVED"
58
+ ])]
59
+ })
60
+ }),
61
+ D ? /* @__PURE__ */ O(u, {}) : j ? /* @__PURE__ */ O(c, {
62
+ error: j,
63
+ onRetry: () => void M()
64
+ }) : !y || y.length === 0 ? /* @__PURE__ */ O(s, {
65
+ title: "No compliance checks",
66
+ description: "Raise a check to gate acceptance or track a professional obligation.",
67
+ icon: /* @__PURE__ */ O(E, { className: "h-8 w-8" }),
68
+ action: /* @__PURE__ */ k(A, {
69
+ onClick: () => i(!0),
70
+ children: [/* @__PURE__ */ O(T, { className: "mr-1.5 h-4 w-4" }), "New check"]
71
+ })
72
+ }) : /* @__PURE__ */ O(m, {
73
+ title: `${y.length} check${y.length === 1 ? "" : "s"}`,
74
+ children: /* @__PURE__ */ k(g, { children: [/* @__PURE__ */ O("thead", { children: /* @__PURE__ */ k("tr", { children: [
75
+ /* @__PURE__ */ O(b, { children: "Title" }),
76
+ /* @__PURE__ */ O(b, { children: "Type" }),
77
+ /* @__PURE__ */ O(b, { children: "Subject" }),
78
+ /* @__PURE__ */ O(b, { children: "Due" }),
79
+ /* @__PURE__ */ O(b, { children: "Status" }),
80
+ /* @__PURE__ */ O(b, {
81
+ className: "text-right",
82
+ children: "Actions"
83
+ })
84
+ ] }) }), /* @__PURE__ */ O("tbody", { children: y.map((e) => /* @__PURE__ */ k("tr", {
85
+ className: "hover:bg-bg-sunken/50",
86
+ children: [
87
+ /* @__PURE__ */ O(_, { children: /* @__PURE__ */ O("span", {
88
+ className: "font-medium text-text-primary",
89
+ children: e.title
90
+ }) }),
91
+ /* @__PURE__ */ O(_, { children: C(e.type) }),
92
+ /* @__PURE__ */ O(_, { children: C(e.subjectType) }),
93
+ /* @__PURE__ */ O(_, { children: S(e.dueDate) }),
94
+ /* @__PURE__ */ O(_, { children: /* @__PURE__ */ O(h, { status: e.status }) }),
95
+ /* @__PURE__ */ O(_, {
96
+ className: "text-right",
97
+ children: e.status === "PENDING" || e.status === "IN_REVIEW" ? /* @__PURE__ */ O(A, {
98
+ variant: "ghost",
99
+ size: "sm",
100
+ onClick: () => l({
101
+ id: e.id,
102
+ title: e.title
103
+ }),
104
+ children: "Resolve"
105
+ }) : /* @__PURE__ */ O("span", {
106
+ className: "text-xs text-text-tertiary",
107
+ children: e.resolvedAt ? S(e.resolvedAt) : ""
108
+ })
109
+ })
110
+ ]
111
+ }, e.id)) })] })
112
+ }),
113
+ r && /* @__PURE__ */ O(F, {
114
+ onClose: () => i(!1),
115
+ onDone: () => {
116
+ M(), v("Compliance check created.");
117
+ }
118
+ }),
119
+ a && /* @__PURE__ */ O(I, {
120
+ check: a,
121
+ onClose: () => l(null),
122
+ onDone: () => {
123
+ M(), v("Compliance check resolved.");
124
+ }
125
+ })
126
+ ]
127
+ });
128
+ }, F = ({ onClose: t, onDone: a }) => {
129
+ let s = n(), [c, u] = w({
130
+ type: "ENGAGEMENT_ACCEPTANCE",
131
+ subjectType: "ENGAGEMENT",
132
+ subjectId: "",
133
+ title: "",
134
+ dueDate: "",
135
+ details: ""
136
+ }), [p, m] = w(null), h = (e) => (t) => u((n) => ({
137
+ ...n,
138
+ [e]: t.target.value
139
+ })), g = e({ pagination: { limit: 100 } }), _ = r({ pagination: { limit: 100 } }), b = i({ pagination: { limit: 100 } }), S = c.subjectType === "CLIENT" ? (g.data?.items ?? []).map((e) => ({
140
+ id: e.id,
141
+ label: e.name
142
+ })) : c.subjectType === "ENGAGEMENT" ? (_.data?.items ?? []).map((e) => ({
143
+ id: e.id,
144
+ label: e.name
145
+ })) : (b.data?.items ?? []).map((e) => ({
146
+ id: e.id,
147
+ label: e.title
148
+ }));
149
+ return /* @__PURE__ */ O(d, {
150
+ open: !0,
151
+ onClose: t,
152
+ title: "New compliance check",
153
+ footer: /* @__PURE__ */ k(D, { children: [/* @__PURE__ */ O(A, {
154
+ variant: "outline",
155
+ onClick: t,
156
+ disabled: s.isPending,
157
+ children: "Cancel"
158
+ }), /* @__PURE__ */ O(A, {
159
+ onClick: () => {
160
+ if (m(null), !c.title.trim()) return m("Title is required.");
161
+ if (!c.subjectId) return m("Select a subject.");
162
+ s.mutate({
163
+ type: c.type,
164
+ subjectType: c.subjectType,
165
+ subjectId: c.subjectId,
166
+ title: c.title.trim(),
167
+ dueDate: c.dueDate ? new Date(c.dueDate).toISOString() : null,
168
+ details: c.details.trim() || null
169
+ }, {
170
+ onSuccess: () => {
171
+ a(), t();
172
+ },
173
+ onError: (e) => m(e instanceof Error ? e.message : "Failed.")
174
+ });
175
+ },
176
+ disabled: s.isPending,
177
+ children: s.isPending ? "Creating…" : "Create check"
178
+ })] }),
179
+ children: /* @__PURE__ */ k("div", {
180
+ className: "space-y-3",
181
+ children: [
182
+ p && /* @__PURE__ */ O(o, {
183
+ tone: "danger",
184
+ children: p
185
+ }),
186
+ /* @__PURE__ */ O(l, {
187
+ label: "Title",
188
+ required: !0,
189
+ children: /* @__PURE__ */ O(y, {
190
+ value: c.title,
191
+ onChange: h("title"),
192
+ placeholder: "Independence confirmation — FY26 audit"
193
+ })
194
+ }),
195
+ /* @__PURE__ */ O(l, {
196
+ label: "Type",
197
+ children: /* @__PURE__ */ O(f, {
198
+ value: c.type,
199
+ onChange: h("type"),
200
+ children: x(j)
201
+ })
202
+ }),
203
+ /* @__PURE__ */ k("div", {
204
+ className: "grid grid-cols-2 gap-3",
205
+ children: [/* @__PURE__ */ O(l, {
206
+ label: "Subject type",
207
+ children: /* @__PURE__ */ O(f, {
208
+ value: c.subjectType,
209
+ onChange: (e) => u((t) => ({
210
+ ...t,
211
+ subjectType: e.target.value,
212
+ subjectId: ""
213
+ })),
214
+ children: x(N)
215
+ })
216
+ }), /* @__PURE__ */ O(l, {
217
+ label: "Subject",
218
+ required: !0,
219
+ children: /* @__PURE__ */ k(f, {
220
+ value: c.subjectId,
221
+ onChange: h("subjectId"),
222
+ children: [/* @__PURE__ */ O("option", {
223
+ value: "",
224
+ children: "Select…"
225
+ }), S.map((e) => /* @__PURE__ */ O("option", {
226
+ value: e.id,
227
+ children: e.label
228
+ }, e.id))]
229
+ })
230
+ })]
231
+ }),
232
+ /* @__PURE__ */ O(l, {
233
+ label: "Due date",
234
+ children: /* @__PURE__ */ O(y, {
235
+ type: "date",
236
+ value: c.dueDate,
237
+ onChange: h("dueDate")
238
+ })
239
+ }),
240
+ /* @__PURE__ */ O(l, {
241
+ label: "Details",
242
+ children: /* @__PURE__ */ O(v, {
243
+ value: c.details,
244
+ onChange: h("details")
245
+ })
246
+ })
247
+ ]
248
+ })
249
+ });
250
+ }, I = ({ check: e, onClose: t, onDone: n }) => {
251
+ let r = a(), [i, s] = w("PASSED"), [c, u] = w(""), [p, m] = w(null);
252
+ return /* @__PURE__ */ O(d, {
253
+ open: !0,
254
+ onClose: t,
255
+ title: `Resolve: ${e.title}`,
256
+ footer: /* @__PURE__ */ k(D, { children: [/* @__PURE__ */ O(A, {
257
+ variant: "outline",
258
+ onClick: t,
259
+ disabled: r.isPending,
260
+ children: "Cancel"
261
+ }), /* @__PURE__ */ O(A, {
262
+ onClick: () => r.mutate({
263
+ id: e.id,
264
+ status: i,
265
+ details: c.trim() || void 0
266
+ }, {
267
+ onSuccess: () => {
268
+ n(), t();
269
+ },
270
+ onError: (e) => m(e instanceof Error ? e.message : "Failed.")
271
+ }),
272
+ disabled: r.isPending,
273
+ children: r.isPending ? "Saving…" : "Resolve"
274
+ })] }),
275
+ children: /* @__PURE__ */ k("div", {
276
+ className: "space-y-3",
277
+ children: [
278
+ p && /* @__PURE__ */ O(o, {
279
+ tone: "danger",
280
+ children: p
281
+ }),
282
+ /* @__PURE__ */ O(l, {
283
+ label: "Outcome",
284
+ children: /* @__PURE__ */ O(f, {
285
+ value: i,
286
+ onChange: (e) => s(e.target.value),
287
+ children: M.map((e) => /* @__PURE__ */ O("option", {
288
+ value: e,
289
+ children: C(e)
290
+ }, e))
291
+ })
292
+ }),
293
+ /* @__PURE__ */ O(l, {
294
+ label: "Notes",
295
+ children: /* @__PURE__ */ O(v, {
296
+ value: c,
297
+ onChange: (e) => u(e.target.value)
298
+ })
299
+ })
300
+ ]
301
+ })
302
+ });
303
+ };
304
+ //#endregion
305
+ export { P as CompliancePage };
306
+
307
+ //# sourceMappingURL=CompliancePage.js.map