@burdenoff/microfe-proserviceworld 2026.1026.2 → 2026.1031.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.
- package/dist/proserviceworld/components/CredentialDirectory.js +44 -43
- package/dist/proserviceworld/components/CredentialDirectory.js.map +1 -1
- package/dist/proserviceworld/components/CredentialReminderPanel.js +5 -4
- package/dist/proserviceworld/components/CredentialReminderPanel.js.map +1 -1
- package/dist/proserviceworld/components/ui.d.ts +7 -3
- package/dist/proserviceworld/components/ui.d.ts.map +1 -1
- package/dist/proserviceworld/components/ui.js +135 -121
- package/dist/proserviceworld/components/ui.js.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +28 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js +95 -73
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
- package/dist/proserviceworld/hooks/useTr.d.ts +49 -8
- package/dist/proserviceworld/hooks/useTr.d.ts.map +1 -1
- package/dist/proserviceworld/hooks/useTr.js +45 -21
- package/dist/proserviceworld/hooks/useTr.js.map +1 -1
- package/dist/proserviceworld/i18n/catalog/analytics.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/analytics.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/analytics.js +271 -0
- package/dist/proserviceworld/i18n/catalog/analytics.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/common.d.ts +9 -0
- package/dist/proserviceworld/i18n/catalog/common.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/common.js +163 -0
- package/dist/proserviceworld/i18n/catalog/common.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/compliance.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/compliance.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/compliance.js +157 -0
- package/dist/proserviceworld/i18n/catalog/compliance.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.js +145 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/documents.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/documents.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/documents.js +157 -0
- package/dist/proserviceworld/i18n/catalog/documents.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/enums.d.ts +10 -0
- package/dist/proserviceworld/i18n/catalog/enums.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/enums.js +481 -0
- package/dist/proserviceworld/i18n/catalog/enums.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/index.d.ts +9 -0
- package/dist/proserviceworld/i18n/catalog/index.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/index.js +25 -0
- package/dist/proserviceworld/i18n/catalog/index.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/invoices.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/invoices.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/invoices.js +247 -0
- package/dist/proserviceworld/i18n/catalog/invoices.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.js +97 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/time.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/time.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/time.js +301 -0
- package/dist/proserviceworld/i18n/catalog/time.js.map +1 -0
- package/dist/proserviceworld/i18n/index.d.ts +10 -9
- package/dist/proserviceworld/i18n/index.d.ts.map +1 -1
- package/dist/proserviceworld/i18n/index.js +16 -12
- package/dist/proserviceworld/i18n/index.js.map +1 -1
- package/dist/proserviceworld/i18n/types.d.ts +13 -0
- package/dist/proserviceworld/i18n/types.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/types.js +18 -0
- package/dist/proserviceworld/i18n/types.js.map +1 -0
- package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/AnalyticsPage.js +236 -152
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientDetailPage.js +99 -98
- package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/ClientsPage.js +181 -181
- package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.js +210 -209
- package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
- package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/ConflictsPage.js +139 -138
- package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.js +150 -149
- package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementDetailPage.js +105 -104
- package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/EngagementsPage.js +137 -137
- package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.js +275 -258
- package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
- package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/MattersPage.js +166 -166
- package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.js +100 -99
- package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -1
- package/dist/proserviceworld/pages/PractitionerCredentialsPage.js +30 -29
- package/dist/proserviceworld/pages/PractitionerCredentialsPage.js.map +1 -1
- package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/TimePage.js +343 -350
- package/dist/proserviceworld/pages/TimePage.js.map +1 -1
- package/dist/proserviceworld/utils/humanize.d.ts +3 -0
- package/dist/proserviceworld/utils/humanize.d.ts.map +1 -0
- package/dist/proserviceworld/utils/humanize.js +6 -0
- package/dist/proserviceworld/utils/humanize.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,277 +1,278 @@
|
|
|
1
1
|
import { useArchiveDocument as e, useCreateDocument as t, useDocuments as n } from "../hooks/useProServiceWorldApi.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { plural as r, useEnumLabel as i, useTr as a } from "../hooks/useTr.js";
|
|
3
|
+
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 } from "../components/ui.js";
|
|
4
|
+
import { useAnalytics as C } from "../hooks/useAnalytics.js";
|
|
5
|
+
import { getDocumentDownloadUrl as w, uploadDocumentFile as T } from "../hooks/useFiles.js";
|
|
6
|
+
import { useDeferredValue as E, useState as D } from "react";
|
|
7
|
+
import { Archive as O, Download as k, FileText as A, Lock as j, Plus as M, Search as N, Upload as P } from "lucide-react";
|
|
8
|
+
import { Fragment as F, jsx as I, jsxs as L } from "react/jsx-runtime";
|
|
9
|
+
import { Button as R } from "@burdenoff/fe-libs/ui";
|
|
9
10
|
//#region src/proserviceworld/pages/DocumentsPage.tsx
|
|
10
|
-
var
|
|
11
|
+
var z = [
|
|
11
12
|
"PUBLIC",
|
|
12
13
|
"INTERNAL",
|
|
13
14
|
"CONFIDENTIAL",
|
|
14
15
|
"PRIVILEGED"
|
|
15
|
-
],
|
|
16
|
-
let
|
|
17
|
-
classification:
|
|
18
|
-
search:
|
|
19
|
-
}), { emitFact:
|
|
16
|
+
], B = () => {
|
|
17
|
+
let t = a(), l = i(), [d, v] = D(""), [T, P] = D(""), F = E(T), [B, H] = D(!1), [U, W] = D(null), { data: G, isLoading: K, error: q, refetch: J } = n({
|
|
18
|
+
classification: d || void 0,
|
|
19
|
+
search: F.trim() || void 0
|
|
20
|
+
}), { emitFact: Y } = C(), X = e(), Z = async (e) => {
|
|
20
21
|
try {
|
|
21
|
-
let t = await
|
|
22
|
+
let t = await w(e);
|
|
22
23
|
window.open(t, "_blank", "noopener");
|
|
23
24
|
} catch (e) {
|
|
24
|
-
|
|
25
|
+
W({
|
|
25
26
|
tone: "danger",
|
|
26
|
-
text: e instanceof Error ? e.message : "Could not open document."
|
|
27
|
+
text: e instanceof Error ? e.message : t("psw.documents.openFailed", "Could not open document.")
|
|
27
28
|
});
|
|
28
29
|
}
|
|
29
30
|
};
|
|
30
|
-
return /* @__PURE__ */
|
|
31
|
+
return /* @__PURE__ */ L("div", {
|
|
31
32
|
className: "space-y-6",
|
|
32
33
|
children: [
|
|
33
|
-
/* @__PURE__ */
|
|
34
|
-
title: "Documents",
|
|
35
|
-
subtitle: "Engagement letters, opinions, filings and evidence — metadata, classification and legal hold here; the file itself lives in the shared Files service.",
|
|
36
|
-
icon: /* @__PURE__ */
|
|
37
|
-
actions: /* @__PURE__ */
|
|
38
|
-
onClick: () =>
|
|
39
|
-
children: [/* @__PURE__ */
|
|
34
|
+
/* @__PURE__ */ I(p, {
|
|
35
|
+
title: t("psw.documents.title", "Documents"),
|
|
36
|
+
subtitle: t("psw.documents.subtitle", "Engagement letters, opinions, filings and evidence — metadata, classification and legal hold here; the file itself lives in the shared Files service."),
|
|
37
|
+
icon: /* @__PURE__ */ I(A, { className: "h-6 w-6" }),
|
|
38
|
+
actions: /* @__PURE__ */ L(R, {
|
|
39
|
+
onClick: () => H(!0),
|
|
40
|
+
children: [/* @__PURE__ */ I(M, { className: "me-1.5 h-4 w-4" }), t("psw.documents.add", "Add document")]
|
|
40
41
|
})
|
|
41
42
|
}),
|
|
42
|
-
|
|
43
|
-
tone:
|
|
44
|
-
onClose: () =>
|
|
45
|
-
children:
|
|
43
|
+
U && /* @__PURE__ */ I(o, {
|
|
44
|
+
tone: U.tone,
|
|
45
|
+
onClose: () => W(null),
|
|
46
|
+
children: U.text
|
|
46
47
|
}),
|
|
47
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ L("div", {
|
|
48
49
|
className: "flex flex-col gap-2 sm:flex-row sm:items-center",
|
|
49
|
-
children: [/* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ L("div", {
|
|
50
51
|
className: "relative flex-1",
|
|
51
|
-
children: [/* @__PURE__ */
|
|
52
|
-
placeholder: "Search documents…",
|
|
53
|
-
value:
|
|
54
|
-
onChange: (e) =>
|
|
52
|
+
children: [/* @__PURE__ */ I(N, { className: "pointer-events-none absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ I(y, {
|
|
53
|
+
placeholder: t("psw.documents.searchPlaceholder", "Search documents…"),
|
|
54
|
+
value: T,
|
|
55
|
+
onChange: (e) => P(e.target.value),
|
|
55
56
|
onKeyDown: (e) => {
|
|
56
|
-
e.key === "Enter" &&
|
|
57
|
+
e.key === "Enter" && T.trim() && Y("psw.search.performed", {
|
|
57
58
|
entityType: "document",
|
|
58
|
-
queryLength:
|
|
59
|
+
queryLength: T.trim().length
|
|
59
60
|
});
|
|
60
61
|
},
|
|
61
|
-
className: "
|
|
62
|
+
className: "ps-9"
|
|
62
63
|
})]
|
|
63
|
-
}), /* @__PURE__ */
|
|
64
|
-
value:
|
|
65
|
-
onChange: (e) =>
|
|
64
|
+
}), /* @__PURE__ */ L(f, {
|
|
65
|
+
value: d,
|
|
66
|
+
onChange: (e) => v(e.target.value),
|
|
66
67
|
className: "sm:w-52",
|
|
67
|
-
children: [/* @__PURE__ */
|
|
68
|
+
children: [/* @__PURE__ */ I("option", {
|
|
68
69
|
value: "",
|
|
69
|
-
children: "All classifications"
|
|
70
|
-
}),
|
|
70
|
+
children: t("psw.documents.allClassifications", "All classifications")
|
|
71
|
+
}), x(z, l)]
|
|
71
72
|
})]
|
|
72
73
|
}),
|
|
73
|
-
|
|
74
|
-
error:
|
|
75
|
-
onRetry: () => void
|
|
76
|
-
}) : !
|
|
77
|
-
title: "No documents",
|
|
78
|
-
description: "Add a document — upload the file to the shared Files service and record it here.",
|
|
79
|
-
icon: /* @__PURE__ */
|
|
80
|
-
action: /* @__PURE__ */
|
|
81
|
-
onClick: () =>
|
|
82
|
-
children: [/* @__PURE__ */
|
|
74
|
+
K ? /* @__PURE__ */ I(u, {}) : q ? /* @__PURE__ */ I(c, {
|
|
75
|
+
error: q,
|
|
76
|
+
onRetry: () => void J()
|
|
77
|
+
}) : !G || G.items.length === 0 ? /* @__PURE__ */ I(s, {
|
|
78
|
+
title: t("psw.documents.emptyTitle", "No documents"),
|
|
79
|
+
description: t("psw.documents.emptyDescription", "Add a document — upload the file to the shared Files service and record it here."),
|
|
80
|
+
icon: /* @__PURE__ */ I(A, { className: "h-8 w-8" }),
|
|
81
|
+
action: /* @__PURE__ */ L(R, {
|
|
82
|
+
onClick: () => H(!0),
|
|
83
|
+
children: [/* @__PURE__ */ I(M, { className: "me-1.5 h-4 w-4" }), t("psw.documents.add", "Add document")]
|
|
83
84
|
})
|
|
84
|
-
}) : /* @__PURE__ */
|
|
85
|
-
title:
|
|
86
|
-
children: /* @__PURE__ */
|
|
87
|
-
/* @__PURE__ */
|
|
88
|
-
/* @__PURE__ */
|
|
89
|
-
/* @__PURE__ */
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
/* @__PURE__ */
|
|
92
|
-
className: "text-
|
|
93
|
-
children: "Actions"
|
|
85
|
+
}) : /* @__PURE__ */ I(m, {
|
|
86
|
+
title: r(t, "psw.documents.count", G.totalCount, "{{count}} document", "{{count}} documents"),
|
|
87
|
+
children: /* @__PURE__ */ L(g, { children: [/* @__PURE__ */ I("thead", { children: /* @__PURE__ */ L("tr", { children: [
|
|
88
|
+
/* @__PURE__ */ I(b, { children: t("psw.common.name", "Name") }),
|
|
89
|
+
/* @__PURE__ */ I(b, { children: t("psw.documents.classification", "Classification") }),
|
|
90
|
+
/* @__PURE__ */ I(b, { children: t("psw.common.status", "Status") }),
|
|
91
|
+
/* @__PURE__ */ I(b, { children: t("psw.common.added", "Added") }),
|
|
92
|
+
/* @__PURE__ */ I(b, {
|
|
93
|
+
className: "text-end",
|
|
94
|
+
children: t("psw.common.actions", "Actions")
|
|
94
95
|
})
|
|
95
|
-
] }) }), /* @__PURE__ */
|
|
96
|
+
] }) }), /* @__PURE__ */ I("tbody", { children: G.items.map((e) => /* @__PURE__ */ L("tr", {
|
|
96
97
|
className: "hover:bg-bg-sunken/50",
|
|
97
98
|
children: [
|
|
98
|
-
/* @__PURE__ */
|
|
99
|
+
/* @__PURE__ */ I(_, { children: /* @__PURE__ */ L("span", {
|
|
99
100
|
className: "flex items-center gap-1.5 font-medium text-text-primary",
|
|
100
101
|
children: [
|
|
101
|
-
e.legalHold && /* @__PURE__ */
|
|
102
|
+
e.legalHold && /* @__PURE__ */ I(j, {
|
|
102
103
|
className: "h-3.5 w-3.5 text-status-warning-text",
|
|
103
|
-
"aria-label": "Legal hold"
|
|
104
|
+
"aria-label": t("psw.documents.legalHold", "Legal hold")
|
|
104
105
|
}),
|
|
105
106
|
e.name,
|
|
106
107
|
" ",
|
|
107
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ L("span", {
|
|
108
109
|
className: "text-xs text-text-tertiary",
|
|
109
110
|
children: ["v", e.version]
|
|
110
111
|
})
|
|
111
112
|
]
|
|
112
113
|
}) }),
|
|
113
|
-
/* @__PURE__ */
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
-
className: "text-
|
|
118
|
-
children: /* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ I(_, { children: l(e.classification) }),
|
|
115
|
+
/* @__PURE__ */ I(_, { children: /* @__PURE__ */ I(h, { status: e.status }) }),
|
|
116
|
+
/* @__PURE__ */ I(_, { children: S(e.createdAt) }),
|
|
117
|
+
/* @__PURE__ */ I(_, {
|
|
118
|
+
className: "text-end",
|
|
119
|
+
children: /* @__PURE__ */ L("div", {
|
|
119
120
|
className: "flex justify-end gap-1",
|
|
120
|
-
children: [e.file?.id && /* @__PURE__ */
|
|
121
|
+
children: [e.file?.id && /* @__PURE__ */ I(R, {
|
|
121
122
|
variant: "ghost",
|
|
122
123
|
size: "sm",
|
|
123
|
-
onClick: () => void
|
|
124
|
-
"aria-label": "Download",
|
|
125
|
-
children: /* @__PURE__ */
|
|
126
|
-
}), e.status !== "ARCHIVED" && /* @__PURE__ */
|
|
124
|
+
onClick: () => void Z(e.file.id),
|
|
125
|
+
"aria-label": t("psw.documents.download", "Download"),
|
|
126
|
+
children: /* @__PURE__ */ I(k, { className: "h-4 w-4" })
|
|
127
|
+
}), e.status !== "ARCHIVED" && /* @__PURE__ */ I(R, {
|
|
127
128
|
variant: "ghost",
|
|
128
129
|
size: "sm",
|
|
129
|
-
"aria-label": "Archive",
|
|
130
|
-
disabled:
|
|
131
|
-
onClick: () =>
|
|
132
|
-
onSuccess: () =>
|
|
130
|
+
"aria-label": t("psw.common.archive", "Archive"),
|
|
131
|
+
disabled: X.isPending,
|
|
132
|
+
onClick: () => X.mutate(e.id, {
|
|
133
|
+
onSuccess: () => W({
|
|
133
134
|
tone: "success",
|
|
134
|
-
text:
|
|
135
|
+
text: t("psw.documents.archived", "{{name}} archived.", { name: e.name })
|
|
135
136
|
}),
|
|
136
|
-
onError: (e) =>
|
|
137
|
+
onError: (e) => W({
|
|
137
138
|
tone: "danger",
|
|
138
|
-
text: e instanceof Error ? e.message : "Failed."
|
|
139
|
+
text: e instanceof Error ? e.message : t("psw.common.failed", "Failed.")
|
|
139
140
|
})
|
|
140
141
|
}),
|
|
141
|
-
children: /* @__PURE__ */
|
|
142
|
+
children: /* @__PURE__ */ I(O, { className: "h-4 w-4" })
|
|
142
143
|
})]
|
|
143
144
|
})
|
|
144
145
|
})
|
|
145
146
|
]
|
|
146
147
|
}, e.id)) })] })
|
|
147
148
|
}),
|
|
148
|
-
|
|
149
|
-
onClose: () =>
|
|
149
|
+
B && /* @__PURE__ */ I(V, {
|
|
150
|
+
onClose: () => H(!1),
|
|
150
151
|
onDone: () => {
|
|
151
|
-
|
|
152
|
+
J(), W({
|
|
152
153
|
tone: "success",
|
|
153
|
-
text: "Document added."
|
|
154
|
+
text: t("psw.documents.added", "Document added.")
|
|
154
155
|
});
|
|
155
156
|
}
|
|
156
157
|
})
|
|
157
158
|
]
|
|
158
159
|
});
|
|
159
|
-
},
|
|
160
|
-
let i = t(), [
|
|
160
|
+
}, V = ({ onClose: e, onDone: n }) => {
|
|
161
|
+
let r = a(), s = i(), c = t(), [u, p] = D({
|
|
161
162
|
name: "",
|
|
162
163
|
classification: "INTERNAL",
|
|
163
164
|
description: "",
|
|
164
165
|
legalHold: !1
|
|
165
|
-
}), [
|
|
166
|
-
if (
|
|
166
|
+
}), [m, h] = D(null), [g, _] = D(!1), [b, S] = D(null), C = async () => {
|
|
167
|
+
if (S(null), !u.name.trim()) return S(r("psw.documents.nameRequired", "Document name is required."));
|
|
167
168
|
let t = null;
|
|
168
|
-
if (
|
|
169
|
+
if (m) {
|
|
169
170
|
try {
|
|
170
|
-
|
|
171
|
+
_(!0), t = (await T(m)).fileId;
|
|
171
172
|
} catch (e) {
|
|
172
|
-
return
|
|
173
|
+
return _(!1), S(e instanceof Error ? e.message : r("psw.documents.uploadFailed", "Upload failed."));
|
|
173
174
|
}
|
|
174
|
-
|
|
175
|
+
_(!1);
|
|
175
176
|
}
|
|
176
|
-
|
|
177
|
-
name:
|
|
178
|
-
classification:
|
|
179
|
-
description:
|
|
180
|
-
legalHold:
|
|
177
|
+
c.mutate({
|
|
178
|
+
name: u.name.trim(),
|
|
179
|
+
classification: u.classification,
|
|
180
|
+
description: u.description.trim() || null,
|
|
181
|
+
legalHold: u.legalHold,
|
|
181
182
|
fileId: t
|
|
182
183
|
}, {
|
|
183
184
|
onSuccess: () => {
|
|
184
185
|
n(), e();
|
|
185
186
|
},
|
|
186
|
-
onError: (e) =>
|
|
187
|
+
onError: (e) => S(e instanceof Error ? e.message : r("psw.common.failed", "Failed."))
|
|
187
188
|
});
|
|
188
|
-
},
|
|
189
|
-
return /* @__PURE__ */
|
|
189
|
+
}, w = g || c.isPending;
|
|
190
|
+
return /* @__PURE__ */ I(d, {
|
|
190
191
|
open: !0,
|
|
191
192
|
onClose: e,
|
|
192
|
-
title: "Add document",
|
|
193
|
-
footer: /* @__PURE__ */ F
|
|
193
|
+
title: r("psw.documents.add", "Add document"),
|
|
194
|
+
footer: /* @__PURE__ */ L(F, { children: [/* @__PURE__ */ I(R, {
|
|
194
195
|
variant: "outline",
|
|
195
196
|
onClick: e,
|
|
196
|
-
disabled:
|
|
197
|
-
children: "Cancel"
|
|
198
|
-
}), /* @__PURE__ */
|
|
199
|
-
onClick: () => void
|
|
200
|
-
disabled:
|
|
201
|
-
children:
|
|
197
|
+
disabled: w,
|
|
198
|
+
children: r("psw.common.cancel", "Cancel")
|
|
199
|
+
}), /* @__PURE__ */ I(R, {
|
|
200
|
+
onClick: () => void C(),
|
|
201
|
+
disabled: w,
|
|
202
|
+
children: g ? r("psw.documents.uploading", "Uploading…") : c.isPending ? r("psw.common.saving", "Saving…") : r("psw.documents.add", "Add document")
|
|
202
203
|
})] }),
|
|
203
|
-
children: /* @__PURE__ */
|
|
204
|
+
children: /* @__PURE__ */ L("div", {
|
|
204
205
|
className: "space-y-3",
|
|
205
206
|
children: [
|
|
206
|
-
|
|
207
|
+
b && /* @__PURE__ */ I(o, {
|
|
207
208
|
tone: "danger",
|
|
208
|
-
children:
|
|
209
|
+
children: b
|
|
209
210
|
}),
|
|
210
|
-
/* @__PURE__ */
|
|
211
|
-
label: "Name",
|
|
211
|
+
/* @__PURE__ */ I(l, {
|
|
212
|
+
label: r("psw.common.name", "Name"),
|
|
212
213
|
required: !0,
|
|
213
|
-
children: /* @__PURE__ */
|
|
214
|
-
value:
|
|
215
|
-
onChange: (e) =>
|
|
214
|
+
children: /* @__PURE__ */ I(y, {
|
|
215
|
+
value: u.name,
|
|
216
|
+
onChange: (e) => p((t) => ({
|
|
216
217
|
...t,
|
|
217
218
|
name: e.target.value
|
|
218
219
|
})),
|
|
219
|
-
placeholder: "Engagement letter — Acme FY26"
|
|
220
|
+
placeholder: r("psw.documents.namePlaceholder", "Engagement letter — Acme FY26")
|
|
220
221
|
})
|
|
221
222
|
}),
|
|
222
|
-
/* @__PURE__ */
|
|
223
|
-
label: "Classification",
|
|
224
|
-
children: /* @__PURE__ */
|
|
225
|
-
value:
|
|
226
|
-
onChange: (e) =>
|
|
223
|
+
/* @__PURE__ */ I(l, {
|
|
224
|
+
label: r("psw.documents.classification", "Classification"),
|
|
225
|
+
children: /* @__PURE__ */ I(f, {
|
|
226
|
+
value: u.classification,
|
|
227
|
+
onChange: (e) => p((t) => ({
|
|
227
228
|
...t,
|
|
228
229
|
classification: e.target.value
|
|
229
230
|
})),
|
|
230
|
-
children:
|
|
231
|
+
children: x(z, s)
|
|
231
232
|
})
|
|
232
233
|
}),
|
|
233
|
-
/* @__PURE__ */
|
|
234
|
-
label: "File",
|
|
235
|
-
hint: "Optional — stored in the shared Files service.",
|
|
236
|
-
children: /* @__PURE__ */
|
|
234
|
+
/* @__PURE__ */ I(l, {
|
|
235
|
+
label: r("psw.documents.file", "File"),
|
|
236
|
+
hint: r("psw.documents.fileHint", "Optional — stored in the shared Files service."),
|
|
237
|
+
children: /* @__PURE__ */ L("label", {
|
|
237
238
|
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",
|
|
238
239
|
children: [
|
|
239
|
-
/* @__PURE__ */ P
|
|
240
|
-
|
|
241
|
-
/* @__PURE__ */
|
|
240
|
+
/* @__PURE__ */ I(P, { className: "h-4 w-4 text-text-tertiary" }),
|
|
241
|
+
m ? m.name : r("psw.documents.chooseFile", "Choose a file…"),
|
|
242
|
+
/* @__PURE__ */ I("input", {
|
|
242
243
|
type: "file",
|
|
243
244
|
className: "hidden",
|
|
244
|
-
onChange: (e) =>
|
|
245
|
+
onChange: (e) => h(e.target.files?.[0] ?? null)
|
|
245
246
|
})
|
|
246
247
|
]
|
|
247
248
|
})
|
|
248
249
|
}),
|
|
249
|
-
/* @__PURE__ */
|
|
250
|
-
label: "Description",
|
|
251
|
-
children: /* @__PURE__ */
|
|
252
|
-
value:
|
|
253
|
-
onChange: (e) =>
|
|
250
|
+
/* @__PURE__ */ I(l, {
|
|
251
|
+
label: r("psw.common.description", "Description"),
|
|
252
|
+
children: /* @__PURE__ */ I(v, {
|
|
253
|
+
value: u.description,
|
|
254
|
+
onChange: (e) => p((t) => ({
|
|
254
255
|
...t,
|
|
255
256
|
description: e.target.value
|
|
256
257
|
}))
|
|
257
258
|
})
|
|
258
259
|
}),
|
|
259
|
-
/* @__PURE__ */
|
|
260
|
+
/* @__PURE__ */ L("label", {
|
|
260
261
|
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
261
|
-
children: [/* @__PURE__ */
|
|
262
|
+
children: [/* @__PURE__ */ I("input", {
|
|
262
263
|
type: "checkbox",
|
|
263
|
-
checked:
|
|
264
|
-
onChange: (e) =>
|
|
264
|
+
checked: u.legalHold,
|
|
265
|
+
onChange: (e) => p((t) => ({
|
|
265
266
|
...t,
|
|
266
267
|
legalHold: e.target.checked
|
|
267
268
|
}))
|
|
268
|
-
}), "Place under legal hold (cannot be disposed)"]
|
|
269
|
+
}), r("psw.documents.legalHoldLabel", "Place under legal hold (cannot be disposed)")]
|
|
269
270
|
})
|
|
270
271
|
]
|
|
271
272
|
})
|
|
272
273
|
});
|
|
273
274
|
};
|
|
274
275
|
//#endregion
|
|
275
|
-
export {
|
|
276
|
+
export { B as DocumentsPage };
|
|
276
277
|
|
|
277
278
|
//# 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 { 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
|
+
{"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} from '../components/ui';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport { plural, useEnumLabel, useTr } from '../hooks/useTr';\n\nconst CLASSIFICATIONS = ['PUBLIC', 'INTERNAL', 'CONFIDENTIAL', 'PRIVILEGED'] as const;\n\nexport const DocumentsPage: FC = () => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\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:\n e instanceof Error\n ? e.message\n : tr('psw.documents.openFailed', 'Could not open document.'),\n });\n }\n };\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={tr('psw.documents.title', 'Documents')}\n subtitle={tr(\n 'psw.documents.subtitle',\n 'Engagement letters, opinions, filings and evidence — metadata, classification and legal hold here; the file itself lives in the shared Files service.'\n )}\n icon={<FileText className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"me-1.5 h-4 w-4\" />\n {tr('psw.documents.add', '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 start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder={tr('psw.documents.searchPlaceholder', '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=\"ps-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=\"\">{tr('psw.documents.allClassifications', 'All classifications')}</option>\n {enumOptions(CLASSIFICATIONS, enumLabel)}\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={tr('psw.documents.emptyTitle', 'No documents')}\n description={tr(\n 'psw.documents.emptyDescription',\n 'Add a document — upload the file to the shared Files service and record it here.'\n )}\n icon={<FileText className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"me-1.5 h-4 w-4\" />\n {tr('psw.documents.add', 'Add document')}\n </Button>\n }\n />\n ) : (\n <SectionCard\n title={plural(\n tr,\n 'psw.documents.count',\n data.totalCount,\n '{{count}} document',\n '{{count}} documents'\n )}\n >\n <TableWrap>\n <thead>\n <tr>\n <Th>{tr('psw.common.name', 'Name')}</Th>\n <Th>{tr('psw.documents.classification', 'Classification')}</Th>\n <Th>{tr('psw.common.status', 'Status')}</Th>\n <Th>{tr('psw.common.added', 'Added')}</Th>\n <Th className=\"text-end\">{tr('psw.common.actions', '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={tr('psw.documents.legalHold', 'Legal hold')}\n />\n )}\n {d.name} <span className=\"text-xs text-text-tertiary\">v{d.version}</span>\n </span>\n </Td>\n <Td>{enumLabel(d.classification)}</Td>\n <Td>\n <StatusPill status={d.status} />\n </Td>\n <Td>{fmtDate(d.createdAt)}</Td>\n <Td className=\"text-end\">\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={tr('psw.documents.download', '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={tr('psw.common.archive', 'Archive')}\n disabled={archive.isPending}\n onClick={() =>\n archive.mutate(d.id, {\n onSuccess: () =>\n setBanner({\n tone: 'success',\n text: tr('psw.documents.archived', '{{name}} archived.', {\n name: d.name,\n }),\n }),\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text:\n e instanceof Error\n ? e.message\n : tr('psw.common.failed', '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: tr('psw.documents.added', 'Document added.') });\n }}\n />\n )}\n </div>\n );\n};\n\nconst DocumentModal: FC<{ onClose: () => void; onDone: () => void }> = ({ onClose, onDone }) => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\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())\n return setErr(tr('psw.documents.nameRequired', '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(\n e instanceof Error ? e.message : tr('psw.documents.uploadFailed', 'Upload failed.')\n );\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 : tr('psw.common.failed', 'Failed.')),\n }\n );\n };\n\n const busy = uploading || create.isPending;\n return (\n <Modal\n open\n onClose={onClose}\n title={tr('psw.documents.add', 'Add document')}\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={busy}>\n {tr('psw.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void submit()} disabled={busy}>\n {uploading\n ? tr('psw.documents.uploading', 'Uploading…')\n : create.isPending\n ? tr('psw.common.saving', 'Saving…')\n : tr('psw.documents.add', 'Add document')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.common.name', 'Name')} required>\n <TextInput\n value={form.name}\n onChange={(e) => setForm((f) => ({ ...f, name: e.target.value }))}\n placeholder={tr('psw.documents.namePlaceholder', 'Engagement letter — Acme FY26')}\n />\n </Field>\n <Field label={tr('psw.documents.classification', 'Classification')}>\n <NativeSelect\n value={form.classification}\n onChange={(e) => setForm((f) => ({ ...f, classification: e.target.value }))}\n >\n {enumOptions(CLASSIFICATIONS, enumLabel)}\n </NativeSelect>\n </Field>\n <Field\n label={tr('psw.documents.file', 'File')}\n hint={tr('psw.documents.fileHint', 'Optional — stored in the shared Files service.')}\n >\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 : tr('psw.documents.chooseFile', '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={tr('psw.common.description', '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 {tr('psw.documents.legalHoldLabel', 'Place under legal hold (cannot be disposed)')}\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
|