@burdenoff/microfe-proserviceworld 2026.1028.1 → 2026.1031.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 (109) hide show
  1. package/dist/generated/global-types.d.ts +9699 -583
  2. package/dist/generated/global-types.d.ts.map +1 -1
  3. package/dist/generated/wspace-types.d.ts +18076 -2999
  4. package/dist/generated/wspace-types.d.ts.map +1 -1
  5. package/dist/proserviceworld/__tests__/schemaStub.d.ts +20 -0
  6. package/dist/proserviceworld/__tests__/schemaStub.d.ts.map +1 -0
  7. package/dist/proserviceworld/components/CredentialDirectory.js +44 -43
  8. package/dist/proserviceworld/components/CredentialDirectory.js.map +1 -1
  9. package/dist/proserviceworld/components/CredentialReminderPanel.js +5 -4
  10. package/dist/proserviceworld/components/CredentialReminderPanel.js.map +1 -1
  11. package/dist/proserviceworld/components/ui.d.ts +7 -3
  12. package/dist/proserviceworld/components/ui.d.ts.map +1 -1
  13. package/dist/proserviceworld/components/ui.js +135 -121
  14. package/dist/proserviceworld/components/ui.js.map +1 -1
  15. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
  16. package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
  17. package/dist/proserviceworld/hooks/useTr.d.ts +49 -8
  18. package/dist/proserviceworld/hooks/useTr.d.ts.map +1 -1
  19. package/dist/proserviceworld/hooks/useTr.js +45 -21
  20. package/dist/proserviceworld/hooks/useTr.js.map +1 -1
  21. package/dist/proserviceworld/i18n/catalog/analytics.d.ts +5 -0
  22. package/dist/proserviceworld/i18n/catalog/analytics.d.ts.map +1 -0
  23. package/dist/proserviceworld/i18n/catalog/analytics.js +271 -0
  24. package/dist/proserviceworld/i18n/catalog/analytics.js.map +1 -0
  25. package/dist/proserviceworld/i18n/catalog/common.d.ts +9 -0
  26. package/dist/proserviceworld/i18n/catalog/common.d.ts.map +1 -0
  27. package/dist/proserviceworld/i18n/catalog/common.js +163 -0
  28. package/dist/proserviceworld/i18n/catalog/common.js.map +1 -0
  29. package/dist/proserviceworld/i18n/catalog/compliance.d.ts +5 -0
  30. package/dist/proserviceworld/i18n/catalog/compliance.d.ts.map +1 -0
  31. package/dist/proserviceworld/i18n/catalog/compliance.js +157 -0
  32. package/dist/proserviceworld/i18n/catalog/compliance.js.map +1 -0
  33. package/dist/proserviceworld/i18n/catalog/conflicts.d.ts +5 -0
  34. package/dist/proserviceworld/i18n/catalog/conflicts.d.ts.map +1 -0
  35. package/dist/proserviceworld/i18n/catalog/conflicts.js +145 -0
  36. package/dist/proserviceworld/i18n/catalog/conflicts.js.map +1 -0
  37. package/dist/proserviceworld/i18n/catalog/documents.d.ts +5 -0
  38. package/dist/proserviceworld/i18n/catalog/documents.d.ts.map +1 -0
  39. package/dist/proserviceworld/i18n/catalog/documents.js +157 -0
  40. package/dist/proserviceworld/i18n/catalog/documents.js.map +1 -0
  41. package/dist/proserviceworld/i18n/catalog/enums.d.ts +10 -0
  42. package/dist/proserviceworld/i18n/catalog/enums.d.ts.map +1 -0
  43. package/dist/proserviceworld/i18n/catalog/enums.js +481 -0
  44. package/dist/proserviceworld/i18n/catalog/enums.js.map +1 -0
  45. package/dist/proserviceworld/i18n/catalog/index.d.ts +9 -0
  46. package/dist/proserviceworld/i18n/catalog/index.d.ts.map +1 -0
  47. package/dist/proserviceworld/i18n/catalog/index.js +25 -0
  48. package/dist/proserviceworld/i18n/catalog/index.js.map +1 -0
  49. package/dist/proserviceworld/i18n/catalog/invoices.d.ts +5 -0
  50. package/dist/proserviceworld/i18n/catalog/invoices.d.ts.map +1 -0
  51. package/dist/proserviceworld/i18n/catalog/invoices.js +247 -0
  52. package/dist/proserviceworld/i18n/catalog/invoices.js.map +1 -0
  53. package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts +5 -0
  54. package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts.map +1 -0
  55. package/dist/proserviceworld/i18n/catalog/practiceAreas.js +97 -0
  56. package/dist/proserviceworld/i18n/catalog/practiceAreas.js.map +1 -0
  57. package/dist/proserviceworld/i18n/catalog/time.d.ts +5 -0
  58. package/dist/proserviceworld/i18n/catalog/time.d.ts.map +1 -0
  59. package/dist/proserviceworld/i18n/catalog/time.js +301 -0
  60. package/dist/proserviceworld/i18n/catalog/time.js.map +1 -0
  61. package/dist/proserviceworld/i18n/index.d.ts +10 -9
  62. package/dist/proserviceworld/i18n/index.d.ts.map +1 -1
  63. package/dist/proserviceworld/i18n/index.js +16 -12
  64. package/dist/proserviceworld/i18n/index.js.map +1 -1
  65. package/dist/proserviceworld/i18n/types.d.ts +13 -0
  66. package/dist/proserviceworld/i18n/types.d.ts.map +1 -0
  67. package/dist/proserviceworld/i18n/types.js +18 -0
  68. package/dist/proserviceworld/i18n/types.js.map +1 -0
  69. package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -1
  70. package/dist/proserviceworld/pages/AnalyticsPage.js +209 -197
  71. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  72. package/dist/proserviceworld/pages/ClientDetailPage.js +99 -98
  73. package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
  74. package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -1
  75. package/dist/proserviceworld/pages/ClientsPage.js +181 -181
  76. package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
  77. package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -1
  78. package/dist/proserviceworld/pages/CompliancePage.js +210 -209
  79. package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
  80. package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -1
  81. package/dist/proserviceworld/pages/ConflictsPage.js +139 -138
  82. package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -1
  83. package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -1
  84. package/dist/proserviceworld/pages/DocumentsPage.js +150 -149
  85. package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
  86. package/dist/proserviceworld/pages/EngagementDetailPage.js +105 -104
  87. package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
  88. package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -1
  89. package/dist/proserviceworld/pages/EngagementsPage.js +137 -137
  90. package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
  91. package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -1
  92. package/dist/proserviceworld/pages/InvoicesPage.js +257 -256
  93. package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
  94. package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -1
  95. package/dist/proserviceworld/pages/MattersPage.js +166 -166
  96. package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
  97. package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -1
  98. package/dist/proserviceworld/pages/PracticeAreasPage.js +100 -99
  99. package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -1
  100. package/dist/proserviceworld/pages/PractitionerCredentialsPage.js +30 -29
  101. package/dist/proserviceworld/pages/PractitionerCredentialsPage.js.map +1 -1
  102. package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -1
  103. package/dist/proserviceworld/pages/TimePage.js +343 -350
  104. package/dist/proserviceworld/pages/TimePage.js.map +1 -1
  105. package/dist/proserviceworld/utils/humanize.d.ts +3 -0
  106. package/dist/proserviceworld/utils/humanize.d.ts.map +1 -0
  107. package/dist/proserviceworld/utils/humanize.js +6 -0
  108. package/dist/proserviceworld/utils/humanize.js.map +1 -0
  109. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CompliancePage.js","names":[],"sources":["../../../src/proserviceworld/pages/CompliancePage.tsx"],"sourcesContent":["import type { FC, ReactNode } from 'react';\nimport { useDeferredValue, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n ShieldCheck,\n FileCheck,\n Scale,\n BadgeCheck,\n GraduationCap,\n Database,\n Lock,\n Clock,\n ListChecks,\n CheckCircle2,\n Search,\n} from 'lucide-react';\nimport {\n useComplianceChecks,\n useCreateComplianceCheck,\n useResolveComplianceCheck,\n useClients,\n useEngagements,\n useMatters,\n type PswComplianceStatus,\n type PswComplianceType,\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 humanize,\n} from '../components/ui';\nimport { useAnalytics } from '../hooks/useAnalytics';\n\nconst TYPES = [\n 'ENGAGEMENT_ACCEPTANCE',\n 'INDEPENDENCE',\n 'LICENSING',\n 'CONTINUING_EDUCATION',\n 'DATA_RETENTION',\n 'LEGAL_HOLD',\n] as const;\nconst RESOLVE_STATUSES: PswComplianceStatus[] = ['IN_REVIEW', 'PASSED', 'FAILED', 'WAIVED'];\nconst SUBJECT_TYPES = ['CLIENT', 'ENGAGEMENT', 'MATTER'] as const;\n\nconst TYPE_ICON: Record<PswComplianceType, ReactNode> = {\n ENGAGEMENT_ACCEPTANCE: <FileCheck className=\"h-3.5 w-3.5\" />,\n INDEPENDENCE: <Scale className=\"h-3.5 w-3.5\" />,\n LICENSING: <BadgeCheck className=\"h-3.5 w-3.5\" />,\n CONTINUING_EDUCATION: <GraduationCap className=\"h-3.5 w-3.5\" />,\n DATA_RETENTION: <Database className=\"h-3.5 w-3.5\" />,\n LEGAL_HOLD: <Lock className=\"h-3.5 w-3.5\" />,\n};\n\nexport const CompliancePage: FC = () => {\n const [statusFilter, setStatusFilter] = useState<PswComplianceStatus | ''>('');\n const [search, setSearch] = useState('');\n const deferredSearch = useDeferredValue(search);\n const [creating, setCreating] = useState(false);\n const [resolving, setResolving] = useState<{ id: string; title: string } | null>(null);\n const [banner, setBanner] = useState<string | null>(null);\n const { data, isLoading, error, refetch } = useComplianceChecks({\n status: statusFilter || undefined,\n search: deferredSearch.trim() || undefined,\n });\n const { emitFact } = useAnalytics();\n\n const checks = data?.items ?? [];\n const pendingCount = checks.filter((c) => c.status === 'PENDING').length;\n const inReviewCount = checks.filter((c) => c.status === 'IN_REVIEW').length;\n const resolvedCount = checks.filter(\n (c) => c.status === 'PASSED' || c.status === 'FAILED' || c.status === 'WAIVED'\n ).length;\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Compliance\"\n subtitle=\"The duties that travel with the work — acceptance, independence, licensing, CE, retention and legal hold — as gates, not afterthoughts.\"\n icon={<ShieldCheck className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New check\n </Button>\n }\n />\n\n {banner && (\n <Banner tone=\"success\" onClose={() => setBanner(null)}>\n {banner}\n </Banner>\n )}\n\n {checks.length > 0 && (\n <div className=\"grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <MetricCard\n label=\"Checks\"\n value={checks.length}\n icon={<ListChecks className=\"h-4 w-4\" />}\n />\n <MetricCard\n label=\"Pending\"\n value={pendingCount}\n icon={<Clock className=\"h-4 w-4\" />}\n tone={pendingCount ? 'warning' : 'neutral'}\n />\n <MetricCard\n label=\"In review\"\n value={inReviewCount}\n icon={<ShieldCheck className=\"h-4 w-4\" />}\n tone=\"info\"\n />\n <MetricCard\n label=\"Resolved\"\n value={resolvedCount}\n icon={<CheckCircle2 className=\"h-4 w-4\" />}\n tone=\"success\"\n />\n </div>\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 compliance checks…\"\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: 'compliance-check',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswComplianceStatus | '')}\n className=\"sm:w-52\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(['PENDING', 'IN_REVIEW', 'PASSED', 'FAILED', 'WAIVED'])}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : checks.length === 0 ? (\n <Empty\n title=\"No compliance checks\"\n description=\"Raise a check to gate acceptance or track a professional obligation.\"\n icon={<ShieldCheck className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New check\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${checks.length} check${checks.length === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Title</Th>\n <Th>Type</Th>\n <Th>Subject</Th>\n <Th>Due</Th>\n <Th>Status</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {checks.map((c) => (\n <tr key={c.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"font-medium text-text-primary\">{c.title}</span>\n </Td>\n <Td>\n <span className=\"inline-flex items-center gap-2 whitespace-nowrap\">\n <span className=\"flex h-6 w-6 items-center justify-center rounded-md bg-bg-sunken text-accent\">\n {TYPE_ICON[c.type]}\n </span>\n {humanize(c.type)}\n </span>\n </Td>\n <Td>{humanize(c.subjectType)}</Td>\n <Td className=\"whitespace-nowrap\">{fmtDate(c.dueDate)}</Td>\n <Td>\n <StatusPill status={c.status} />\n </Td>\n <Td className=\"text-right\">\n {c.status === 'PENDING' || c.status === 'IN_REVIEW' ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setResolving({ id: c.id, title: c.title })}\n >\n Resolve\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {c.resolvedAt ? fmtDate(c.resolvedAt) : ''}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <ComplianceModal\n onClose={() => setCreating(false)}\n onDone={() => {\n void refetch();\n setBanner('Compliance check created.');\n }}\n />\n )}\n {resolving && (\n <ResolveModal\n check={resolving}\n onClose={() => setResolving(null)}\n onDone={() => {\n void refetch();\n setBanner('Compliance check resolved.');\n }}\n />\n )}\n </div>\n );\n};\n\nconst ComplianceModal: FC<{ onClose: () => void; onDone: () => void }> = ({ onClose, onDone }) => {\n const create = useCreateComplianceCheck();\n const [form, setForm] = useState({\n type: 'ENGAGEMENT_ACCEPTANCE',\n subjectType: 'ENGAGEMENT',\n subjectId: '',\n title: '',\n dueDate: '',\n details: '',\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 clients = useClients({ pagination: { limit: 100 } });\n const engagements = useEngagements({ pagination: { limit: 100 } });\n const matters = useMatters({ pagination: { limit: 100 } });\n const subjects =\n form.subjectType === 'CLIENT'\n ? (clients.data?.items ?? []).map((c) => ({ id: c.id, label: c.name }))\n : form.subjectType === 'ENGAGEMENT'\n ? (engagements.data?.items ?? []).map((e) => ({ id: e.id, label: e.name }))\n : (matters.data?.items ?? []).map((m) => ({ id: m.id, label: m.title }));\n\n const submit = () => {\n setErr(null);\n if (!form.title.trim()) return setErr('Title is required.');\n if (!form.subjectId) return setErr('Select a subject.');\n create.mutate(\n {\n type: form.type,\n subjectType: form.subjectType,\n subjectId: form.subjectId,\n title: form.title.trim(),\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n details: form.details.trim() || null,\n },\n {\n onSuccess: () => {\n onDone();\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 compliance check\"\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 ? 'Creating…' : 'Create check'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Title\" required>\n <TextInput\n value={form.title}\n onChange={set('title')}\n placeholder=\"Independence confirmation — FY26 audit\"\n />\n </Field>\n <Field label=\"Type\">\n <NativeSelect value={form.type} onChange={set('type')}>\n {enumOptions(TYPES)}\n </NativeSelect>\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Subject type\">\n <NativeSelect\n value={form.subjectType}\n onChange={(e) =>\n setForm((f) => ({ ...f, subjectType: e.target.value, subjectId: '' }))\n }\n >\n {enumOptions(SUBJECT_TYPES)}\n </NativeSelect>\n </Field>\n <Field label=\"Subject\" required>\n <NativeSelect value={form.subjectId} onChange={set('subjectId')}>\n <option value=\"\">Select…</option>\n {subjects.map((s) => (\n <option key={s.id} value={s.id}>\n {s.label}\n </option>\n ))}\n </NativeSelect>\n </Field>\n </div>\n <Field label=\"Due date\">\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n <Field label=\"Details\">\n <TextArea value={form.details} onChange={set('details')} />\n </Field>\n </div>\n </Modal>\n );\n};\n\nconst ResolveModal: FC<{\n check: { id: string; title: string };\n onClose: () => void;\n onDone: () => void;\n}> = ({ check, onClose, onDone }) => {\n const resolve = useResolveComplianceCheck();\n const [status, setStatus] = useState<PswComplianceStatus>('PASSED');\n const [details, setDetails] = useState('');\n const [err, setErr] = useState<string | null>(null);\n const submit = () =>\n resolve.mutate(\n { id: check.id, status, details: details.trim() || undefined },\n {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n return (\n <Modal\n open\n onClose={onClose}\n title={`Resolve: ${check.title}`}\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={resolve.isPending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={resolve.isPending}>\n {resolve.isPending ? 'Saving…' : 'Resolve'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Outcome\">\n <NativeSelect\n value={status}\n onChange={(e) => setStatus(e.target.value as PswComplianceStatus)}\n >\n {RESOLVE_STATUSES.map((s) => (\n <option key={s} value={s}>\n {humanize(s)}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Notes\">\n <TextArea value={details} onChange={(e) => setDetails(e.target.value)} />\n </Field>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompliancePage.js","names":[],"sources":["../../../src/proserviceworld/pages/CompliancePage.tsx"],"sourcesContent":["import type { FC, ReactNode } from 'react';\nimport { useDeferredValue, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n ShieldCheck,\n FileCheck,\n Scale,\n BadgeCheck,\n GraduationCap,\n Database,\n Lock,\n Clock,\n ListChecks,\n CheckCircle2,\n Search,\n} from 'lucide-react';\nimport {\n useComplianceChecks,\n useCreateComplianceCheck,\n useResolveComplianceCheck,\n useClients,\n useEngagements,\n useMatters,\n type PswComplianceStatus,\n type PswComplianceType,\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';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport { plural, useEnumLabel, useTr } from '../hooks/useTr';\n\nconst TYPES = [\n 'ENGAGEMENT_ACCEPTANCE',\n 'INDEPENDENCE',\n 'LICENSING',\n 'CONTINUING_EDUCATION',\n 'DATA_RETENTION',\n 'LEGAL_HOLD',\n] as const;\nconst RESOLVE_STATUSES: PswComplianceStatus[] = ['IN_REVIEW', 'PASSED', 'FAILED', 'WAIVED'];\nconst SUBJECT_TYPES = ['CLIENT', 'ENGAGEMENT', 'MATTER'] as const;\n\nconst TYPE_ICON: Record<PswComplianceType, ReactNode> = {\n ENGAGEMENT_ACCEPTANCE: <FileCheck className=\"h-3.5 w-3.5\" />,\n INDEPENDENCE: <Scale className=\"h-3.5 w-3.5\" />,\n LICENSING: <BadgeCheck className=\"h-3.5 w-3.5\" />,\n CONTINUING_EDUCATION: <GraduationCap className=\"h-3.5 w-3.5\" />,\n DATA_RETENTION: <Database className=\"h-3.5 w-3.5\" />,\n LEGAL_HOLD: <Lock className=\"h-3.5 w-3.5\" />,\n};\n\nexport const CompliancePage: FC = () => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\n const [statusFilter, setStatusFilter] = useState<PswComplianceStatus | ''>('');\n const [search, setSearch] = useState('');\n const deferredSearch = useDeferredValue(search);\n const [creating, setCreating] = useState(false);\n const [resolving, setResolving] = useState<{ id: string; title: string } | null>(null);\n const [banner, setBanner] = useState<string | null>(null);\n const { data, isLoading, error, refetch } = useComplianceChecks({\n status: statusFilter || undefined,\n search: deferredSearch.trim() || undefined,\n });\n const { emitFact } = useAnalytics();\n\n const checks = data?.items ?? [];\n const pendingCount = checks.filter((c) => c.status === 'PENDING').length;\n const inReviewCount = checks.filter((c) => c.status === 'IN_REVIEW').length;\n const resolvedCount = checks.filter(\n (c) => c.status === 'PASSED' || c.status === 'FAILED' || c.status === 'WAIVED'\n ).length;\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={tr('psw.compliance.title', 'Compliance')}\n subtitle={tr(\n 'psw.compliance.subtitle',\n 'The duties that travel with the work — acceptance, independence, licensing, CE, retention and legal hold — as gates, not afterthoughts.'\n )}\n icon={<ShieldCheck 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.compliance.new', 'New check')}\n </Button>\n }\n />\n\n {banner && (\n <Banner tone=\"success\" onClose={() => setBanner(null)}>\n {banner}\n </Banner>\n )}\n\n {checks.length > 0 && (\n <div className=\"grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <MetricCard\n label={tr('psw.compliance.metricChecks', 'Checks')}\n value={checks.length}\n icon={<ListChecks className=\"h-4 w-4\" />}\n />\n <MetricCard\n label={tr('psw.compliance.metricPending', 'Pending')}\n value={pendingCount}\n icon={<Clock className=\"h-4 w-4\" />}\n tone={pendingCount ? 'warning' : 'neutral'}\n />\n <MetricCard\n label={tr('psw.compliance.metricInReview', 'In review')}\n value={inReviewCount}\n icon={<ShieldCheck className=\"h-4 w-4\" />}\n tone=\"info\"\n />\n <MetricCard\n label={tr('psw.compliance.metricResolved', 'Resolved')}\n value={resolvedCount}\n icon={<CheckCircle2 className=\"h-4 w-4\" />}\n tone=\"success\"\n />\n </div>\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.compliance.searchPlaceholder', 'Search compliance checks…')}\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: 'compliance-check',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"ps-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswComplianceStatus | '')}\n className=\"sm:w-52\"\n >\n <option value=\"\">{tr('psw.common.allStatuses', 'All statuses')}</option>\n {enumOptions(['PENDING', 'IN_REVIEW', 'PASSED', 'FAILED', 'WAIVED'], enumLabel)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : checks.length === 0 ? (\n <Empty\n title={tr('psw.compliance.emptyTitle', 'No compliance checks')}\n description={tr(\n 'psw.compliance.emptyDescription',\n 'Raise a check to gate acceptance or track a professional obligation.'\n )}\n icon={<ShieldCheck 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.compliance.new', 'New check')}\n </Button>\n }\n />\n ) : (\n <SectionCard\n title={plural(\n tr,\n 'psw.compliance.count',\n checks.length,\n '{{count}} check',\n '{{count}} checks'\n )}\n >\n <TableWrap>\n <thead>\n <tr>\n <Th>{tr('psw.common.title', 'Title')}</Th>\n <Th>{tr('psw.common.type', 'Type')}</Th>\n <Th>{tr('psw.compliance.subject', 'Subject')}</Th>\n <Th>{tr('psw.common.due', 'Due')}</Th>\n <Th>{tr('psw.common.status', 'Status')}</Th>\n <Th className=\"text-end\">{tr('psw.common.actions', 'Actions')}</Th>\n </tr>\n </thead>\n <tbody>\n {checks.map((c) => (\n <tr key={c.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"font-medium text-text-primary\">{c.title}</span>\n </Td>\n <Td>\n <span className=\"inline-flex items-center gap-2 whitespace-nowrap\">\n <span className=\"flex h-6 w-6 items-center justify-center rounded-md bg-bg-sunken text-accent\">\n {TYPE_ICON[c.type]}\n </span>\n {enumLabel(c.type)}\n </span>\n </Td>\n <Td>{enumLabel(c.subjectType)}</Td>\n <Td className=\"whitespace-nowrap\">{fmtDate(c.dueDate)}</Td>\n <Td>\n <StatusPill status={c.status} />\n </Td>\n <Td className=\"text-end\">\n {c.status === 'PENDING' || c.status === 'IN_REVIEW' ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setResolving({ id: c.id, title: c.title })}\n >\n {tr('psw.common.resolve', 'Resolve')}\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {c.resolvedAt ? fmtDate(c.resolvedAt) : ''}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <ComplianceModal\n onClose={() => setCreating(false)}\n onDone={() => {\n void refetch();\n setBanner(tr('psw.compliance.created', 'Compliance check created.'));\n }}\n />\n )}\n {resolving && (\n <ResolveModal\n check={resolving}\n onClose={() => setResolving(null)}\n onDone={() => {\n void refetch();\n setBanner(tr('psw.compliance.resolved', 'Compliance check resolved.'));\n }}\n />\n )}\n </div>\n );\n};\n\nconst ComplianceModal: FC<{ onClose: () => void; onDone: () => void }> = ({ onClose, onDone }) => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\n const create = useCreateComplianceCheck();\n const [form, setForm] = useState({\n type: 'ENGAGEMENT_ACCEPTANCE',\n subjectType: 'ENGAGEMENT',\n subjectId: '',\n title: '',\n dueDate: '',\n details: '',\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 clients = useClients({ pagination: { limit: 100 } });\n const engagements = useEngagements({ pagination: { limit: 100 } });\n const matters = useMatters({ pagination: { limit: 100 } });\n const subjects =\n form.subjectType === 'CLIENT'\n ? (clients.data?.items ?? []).map((c) => ({ id: c.id, label: c.name }))\n : form.subjectType === 'ENGAGEMENT'\n ? (engagements.data?.items ?? []).map((e) => ({ id: e.id, label: e.name }))\n : (matters.data?.items ?? []).map((m) => ({ id: m.id, label: m.title }));\n\n const submit = () => {\n setErr(null);\n if (!form.title.trim()) return setErr(tr('psw.compliance.titleRequired', 'Title is required.'));\n if (!form.subjectId) return setErr(tr('psw.compliance.selectSubject', 'Select a subject.'));\n create.mutate(\n {\n type: form.type,\n subjectType: form.subjectType,\n subjectId: form.subjectId,\n title: form.title.trim(),\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n details: form.details.trim() || null,\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 return (\n <Modal\n open\n onClose={onClose}\n title={tr('psw.compliance.newTitle', 'New compliance check')}\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={create.isPending}>\n {tr('psw.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submit} disabled={create.isPending}>\n {create.isPending\n ? tr('psw.common.creating', 'Creating…')\n : tr('psw.compliance.create', 'Create check')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.common.title', 'Title')} required>\n <TextInput\n value={form.title}\n onChange={set('title')}\n placeholder={tr(\n 'psw.compliance.titlePlaceholder',\n 'Independence confirmation — FY26 audit'\n )}\n />\n </Field>\n <Field label={tr('psw.common.type', 'Type')}>\n <NativeSelect value={form.type} onChange={set('type')}>\n {enumOptions(TYPES, enumLabel)}\n </NativeSelect>\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label={tr('psw.compliance.subjectType', 'Subject type')}>\n <NativeSelect\n value={form.subjectType}\n onChange={(e) =>\n setForm((f) => ({ ...f, subjectType: e.target.value, subjectId: '' }))\n }\n >\n {enumOptions(SUBJECT_TYPES, enumLabel)}\n </NativeSelect>\n </Field>\n <Field label={tr('psw.compliance.subject', 'Subject')} required>\n <NativeSelect value={form.subjectId} onChange={set('subjectId')}>\n <option value=\"\">{tr('psw.common.select', 'Select…')}</option>\n {subjects.map((s) => (\n <option key={s.id} value={s.id}>\n {s.label}\n </option>\n ))}\n </NativeSelect>\n </Field>\n </div>\n <Field label={tr('psw.common.dueDate', 'Due date')}>\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n <Field label={tr('psw.compliance.details', 'Details')}>\n <TextArea value={form.details} onChange={set('details')} />\n </Field>\n </div>\n </Modal>\n );\n};\n\nconst ResolveModal: FC<{\n check: { id: string; title: string };\n onClose: () => void;\n onDone: () => void;\n}> = ({ check, onClose, onDone }) => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\n const resolve = useResolveComplianceCheck();\n const [status, setStatus] = useState<PswComplianceStatus>('PASSED');\n const [details, setDetails] = useState('');\n const [err, setErr] = useState<string | null>(null);\n const submit = () =>\n resolve.mutate(\n { id: check.id, status, details: details.trim() || undefined },\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 return (\n <Modal\n open\n onClose={onClose}\n title={tr('psw.compliance.resolveTitle', 'Resolve: {{title}}', { title: check.title })}\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={resolve.isPending}>\n {tr('psw.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submit} disabled={resolve.isPending}>\n {resolve.isPending\n ? tr('psw.common.saving', 'Saving…')\n : tr('psw.common.resolve', 'Resolve')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.common.outcome', 'Outcome')}>\n <NativeSelect\n value={status}\n onChange={(e) => setStatus(e.target.value as PswComplianceStatus)}\n >\n {RESOLVE_STATUSES.map((s) => (\n <option key={s} value={s}>\n {enumLabel(s)}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label={tr('psw.common.notes', 'Notes')}>\n <TextArea value={details} onChange={(e) => setDetails(e.target.value)} />\n </Field>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ConflictsPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/ConflictsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAuChC,eAAO,MAAM,aAAa,EAAE,EAuI3B,CAAC"}
1
+ {"version":3,"file":"ConflictsPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/ConflictsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAuChC,eAAO,MAAM,aAAa,EAAE,EAsJ3B,CAAC"}
@@ -1,243 +1,244 @@
1
1
  import { useClients as e, useConflictChecks as t, useCreateConflictCheck as n, useResolveConflictCheck as r } from "../hooks/useProServiceWorldApi.js";
2
- import { Banner as i, Empty as a, ErrorState as o, Field as s, LoadingBlock as c, Modal as l, NativeSelect as u, PageHeader as d, SectionCard as f, StatusPill as p, TableWrap as m, Td as h, TextArea as g, TextInput as _, Th as v, fmtDate as y, humanize as b } from "../components/ui.js";
3
- import { useAnalytics as x } from "../hooks/useAnalytics.js";
4
- import { useDeferredValue as S, useMemo as C, useState as w } from "react";
5
- import { GitBranch as T, Plus as E, Search as D } from "lucide-react";
6
- import { Fragment as O, jsx as k, jsxs as A } from "react/jsx-runtime";
7
- import { Button as j } from "@burdenoff/fe-libs/ui";
2
+ import { plural as i, useEnumLabel as a, useTr as o } from "../hooks/useTr.js";
3
+ import { Banner as s, Empty as c, ErrorState as l, Field as u, LoadingBlock as d, Modal as f, NativeSelect as p, PageHeader as m, SectionCard as h, StatusPill as g, TableWrap as _, Td as v, TextArea as y, TextInput as b, Th as x, fmtDate as S } from "../components/ui.js";
4
+ import { useAnalytics as C } from "../hooks/useAnalytics.js";
5
+ import { useDeferredValue as w, useMemo as T, useState as E } from "react";
6
+ import { GitBranch as D, Plus as O, Search as k } from "lucide-react";
7
+ import { Fragment as A, jsx as j, jsxs as M } from "react/jsx-runtime";
8
+ import { Button as N } from "@burdenoff/fe-libs/ui";
8
9
  //#region src/proserviceworld/pages/ConflictsPage.tsx
9
- var M = [
10
+ var P = [
10
11
  "CLEAR",
11
12
  "POTENTIAL_CONFLICT",
12
13
  "CONFLICT",
13
14
  "WAIVED"
14
- ], N = () => {
15
- let [n, r] = w(!1), [s, l] = w(null), [u, g] = w(null), [b, O] = w(""), { data: M, isLoading: N, error: I, refetch: L } = t({ search: S(b).trim() || void 0 }), { emitFact: R } = x(), z = M?.items ?? [], B = e({ pagination: { limit: 100 } }), V = C(() => new Map((B.data?.items ?? []).map((e) => [e.id, e.name])), [B.data]);
16
- return /* @__PURE__ */ A("div", {
15
+ ], F = () => {
16
+ let n = o(), [r, a] = E(!1), [u, f] = E(null), [p, y] = E(null), [A, P] = E(""), { data: F, isLoading: R, error: z, refetch: B } = t({ search: w(A).trim() || void 0 }), { emitFact: V } = C(), H = F?.items ?? [], U = e({ pagination: { limit: 100 } }), W = T(() => new Map((U.data?.items ?? []).map((e) => [e.id, e.name])), [U.data]);
17
+ return /* @__PURE__ */ M("div", {
17
18
  className: "space-y-6",
18
19
  children: [
19
- /* @__PURE__ */ k(d, {
20
- title: "Conflict checks",
21
- subtitle: "Run before accepting a client or opening a matter — searched against existing clients, matters and counterparties, with a documented result and waiver.",
22
- icon: /* @__PURE__ */ k(T, { className: "h-6 w-6" }),
23
- actions: /* @__PURE__ */ A(j, {
24
- onClick: () => r(!0),
25
- children: [/* @__PURE__ */ k(E, { className: "mr-1.5 h-4 w-4" }), "Run check"]
20
+ /* @__PURE__ */ j(m, {
21
+ title: n("psw.conflicts.title", "Conflict checks"),
22
+ subtitle: n("psw.conflicts.subtitle", "Run before accepting a client or opening a matter — searched against existing clients, matters and counterparties, with a documented result and waiver."),
23
+ icon: /* @__PURE__ */ j(D, { className: "h-6 w-6" }),
24
+ actions: /* @__PURE__ */ M(N, {
25
+ onClick: () => a(!0),
26
+ children: [/* @__PURE__ */ j(O, { className: "me-1.5 h-4 w-4" }), n("psw.conflicts.run", "Run check")]
26
27
  })
27
28
  }),
28
- u && /* @__PURE__ */ k(i, {
29
+ p && /* @__PURE__ */ j(s, {
29
30
  tone: "success",
30
- onClose: () => g(null),
31
- children: u
31
+ onClose: () => y(null),
32
+ children: p
32
33
  }),
33
- /* @__PURE__ */ A("div", {
34
+ /* @__PURE__ */ M("div", {
34
35
  className: "relative",
35
- 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(_, {
36
- placeholder: "Search conflict checks…",
37
- value: b,
38
- onChange: (e) => O(e.target.value),
36
+ children: [/* @__PURE__ */ j(k, { className: "pointer-events-none absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ j(b, {
37
+ placeholder: n("psw.conflicts.searchPlaceholder", "Search conflict checks…"),
38
+ value: A,
39
+ onChange: (e) => P(e.target.value),
39
40
  onKeyDown: (e) => {
40
- e.key === "Enter" && b.trim() && R("psw.search.performed", {
41
+ e.key === "Enter" && A.trim() && V("psw.search.performed", {
41
42
  entityType: "conflict-check",
42
- queryLength: b.trim().length
43
+ queryLength: A.trim().length
43
44
  });
44
45
  },
45
- className: "pl-9"
46
+ className: "ps-9"
46
47
  })]
47
48
  }),
48
- N ? /* @__PURE__ */ k(c, {}) : I ? /* @__PURE__ */ k(o, {
49
- error: I,
50
- onRetry: () => void L()
51
- }) : z.length === 0 ? /* @__PURE__ */ k(a, {
52
- title: "No conflict checks",
53
- description: "Run a conflict check before taking on new work.",
54
- icon: /* @__PURE__ */ k(T, { className: "h-8 w-8" }),
55
- action: /* @__PURE__ */ A(j, {
56
- onClick: () => r(!0),
57
- children: [/* @__PURE__ */ k(E, { className: "mr-1.5 h-4 w-4" }), "Run check"]
49
+ R ? /* @__PURE__ */ j(d, {}) : z ? /* @__PURE__ */ j(l, {
50
+ error: z,
51
+ onRetry: () => void B()
52
+ }) : H.length === 0 ? /* @__PURE__ */ j(c, {
53
+ title: n("psw.conflicts.emptyTitle", "No conflict checks"),
54
+ description: n("psw.conflicts.emptyDescription", "Run a conflict check before taking on new work."),
55
+ icon: /* @__PURE__ */ j(D, { className: "h-8 w-8" }),
56
+ action: /* @__PURE__ */ M(N, {
57
+ onClick: () => a(!0),
58
+ children: [/* @__PURE__ */ j(O, { className: "me-1.5 h-4 w-4" }), n("psw.conflicts.run", "Run check")]
58
59
  })
59
- }) : /* @__PURE__ */ k(f, {
60
- title: `${z.length} check${z.length === 1 ? "" : "s"}`,
61
- children: /* @__PURE__ */ A(m, { children: [/* @__PURE__ */ k("thead", { children: /* @__PURE__ */ A("tr", { children: [
62
- /* @__PURE__ */ k(v, { children: "Client" }),
63
- /* @__PURE__ */ k(v, { children: "Parties searched" }),
64
- /* @__PURE__ */ k(v, { children: "Run" }),
65
- /* @__PURE__ */ k(v, { children: "Status" }),
66
- /* @__PURE__ */ k(v, {
67
- className: "text-right",
68
- children: "Actions"
60
+ }) : /* @__PURE__ */ j(h, {
61
+ title: i(n, "psw.conflicts.count", H.length, "{{count}} check", "{{count}} checks"),
62
+ children: /* @__PURE__ */ M(_, { children: [/* @__PURE__ */ j("thead", { children: /* @__PURE__ */ M("tr", { children: [
63
+ /* @__PURE__ */ j(x, { children: n("psw.common.client", "Client") }),
64
+ /* @__PURE__ */ j(x, { children: n("psw.conflicts.partiesSearched", "Parties searched") }),
65
+ /* @__PURE__ */ j(x, { children: n("psw.conflicts.runAt", "Run") }),
66
+ /* @__PURE__ */ j(x, { children: n("psw.common.status", "Status") }),
67
+ /* @__PURE__ */ j(x, {
68
+ className: "text-end",
69
+ children: n("psw.common.actions", "Actions")
69
70
  })
70
- ] }) }), /* @__PURE__ */ k("tbody", { children: z.map((e) => /* @__PURE__ */ A("tr", {
71
+ ] }) }), /* @__PURE__ */ j("tbody", { children: H.map((e) => /* @__PURE__ */ M("tr", {
71
72
  className: "hover:bg-bg-sunken/50",
72
73
  children: [
73
- /* @__PURE__ */ k(h, { children: /* @__PURE__ */ k("span", {
74
+ /* @__PURE__ */ j(v, { children: /* @__PURE__ */ j("span", {
74
75
  className: "font-medium text-text-primary",
75
- children: V.get(e.clientId) ?? "—"
76
+ children: W.get(e.clientId) ?? "—"
76
77
  }) }),
77
- /* @__PURE__ */ k(h, {
78
+ /* @__PURE__ */ j(v, {
78
79
  className: "max-w-xs truncate",
79
80
  children: e.searchedParties.join(", ") || "—"
80
81
  }),
81
- /* @__PURE__ */ k(h, { children: y(e.createdAt) }),
82
- /* @__PURE__ */ k(h, { children: /* @__PURE__ */ k(p, { status: e.status }) }),
83
- /* @__PURE__ */ k(h, {
84
- className: "text-right",
85
- children: e.status === "PENDING" || e.status === "POTENTIAL_CONFLICT" ? /* @__PURE__ */ k(j, {
82
+ /* @__PURE__ */ j(v, { children: S(e.createdAt) }),
83
+ /* @__PURE__ */ j(v, { children: /* @__PURE__ */ j(g, { status: e.status }) }),
84
+ /* @__PURE__ */ j(v, {
85
+ className: "text-end",
86
+ children: e.status === "PENDING" || e.status === "POTENTIAL_CONFLICT" ? /* @__PURE__ */ j(N, {
86
87
  variant: "ghost",
87
88
  size: "sm",
88
- onClick: () => l({ id: e.id }),
89
- children: "Resolve"
90
- }) : /* @__PURE__ */ k("span", {
89
+ onClick: () => f({ id: e.id }),
90
+ children: n("psw.common.resolve", "Resolve")
91
+ }) : /* @__PURE__ */ j("span", {
91
92
  className: "text-xs text-text-tertiary",
92
- children: e.resolvedAt ? y(e.resolvedAt) : ""
93
+ children: e.resolvedAt ? S(e.resolvedAt) : ""
93
94
  })
94
95
  })
95
96
  ]
96
97
  }, e.id)) })] })
97
98
  }),
98
- n && /* @__PURE__ */ k(P, {
99
- onClose: () => r(!1),
99
+ r && /* @__PURE__ */ j(I, {
100
+ onClose: () => a(!1),
100
101
  onDone: () => {
101
- L(), g("Conflict check recorded.");
102
+ B(), y(n("psw.conflicts.recorded", "Conflict check recorded."));
102
103
  }
103
104
  }),
104
- s && /* @__PURE__ */ k(F, {
105
- id: s.id,
106
- onClose: () => l(null),
105
+ u && /* @__PURE__ */ j(L, {
106
+ id: u.id,
107
+ onClose: () => f(null),
107
108
  onDone: () => {
108
- L(), g("Conflict check resolved.");
109
+ B(), y(n("psw.conflicts.resolved", "Conflict check resolved."));
109
110
  }
110
111
  })
111
112
  ]
112
113
  });
113
- }, P = ({ onClose: t, onDone: r }) => {
114
- let a = n(), o = e({ pagination: { limit: 100 } }), [c, d] = w(""), [f, p] = w(""), [m, h] = w(""), [v, y] = w(null);
115
- return /* @__PURE__ */ k(l, {
114
+ }, I = ({ onClose: t, onDone: r }) => {
115
+ let i = o(), a = n(), c = e({ pagination: { limit: 100 } }), [l, d] = E(""), [m, h] = E(""), [g, _] = E(""), [v, x] = E(null);
116
+ return /* @__PURE__ */ j(f, {
116
117
  open: !0,
117
118
  onClose: t,
118
- title: "Run conflict check",
119
- footer: /* @__PURE__ */ A(O, { children: [/* @__PURE__ */ k(j, {
119
+ title: i("psw.conflicts.runTitle", "Run conflict check"),
120
+ footer: /* @__PURE__ */ M(A, { children: [/* @__PURE__ */ j(N, {
120
121
  variant: "outline",
121
122
  onClick: t,
122
123
  disabled: a.isPending,
123
- children: "Cancel"
124
- }), /* @__PURE__ */ k(j, {
124
+ children: i("psw.common.cancel", "Cancel")
125
+ }), /* @__PURE__ */ j(N, {
125
126
  onClick: () => {
126
- if (y(null), !c) return y("Select a client.");
127
- let e = f.split(",").map((e) => e.trim()).filter(Boolean);
128
- if (e.length === 0) return y("Add at least one party.");
127
+ if (x(null), !l) return x(i("psw.conflicts.selectClient", "Select a client."));
128
+ let e = m.split(",").map((e) => e.trim()).filter(Boolean);
129
+ if (e.length === 0) return x(i("psw.conflicts.partyRequired", "Add at least one party."));
129
130
  a.mutate({
130
- clientId: c,
131
+ clientId: l,
131
132
  searchedParties: e,
132
- findings: m.trim() || null
133
+ findings: g.trim() || null
133
134
  }, {
134
135
  onSuccess: () => {
135
136
  r(), t();
136
137
  },
137
- onError: (e) => y(e instanceof Error ? e.message : "Failed.")
138
+ onError: (e) => x(e instanceof Error ? e.message : i("psw.common.failed", "Failed."))
138
139
  });
139
140
  },
140
141
  disabled: a.isPending,
141
- children: a.isPending ? "Running…" : "Record check"
142
+ children: a.isPending ? i("psw.conflicts.running", "Running…") : i("psw.conflicts.record", "Record check")
142
143
  })] }),
143
- children: /* @__PURE__ */ A("div", {
144
+ children: /* @__PURE__ */ M("div", {
144
145
  className: "space-y-3",
145
146
  children: [
146
- v && /* @__PURE__ */ k(i, {
147
+ v && /* @__PURE__ */ j(s, {
147
148
  tone: "danger",
148
149
  children: v
149
150
  }),
150
- /* @__PURE__ */ k(s, {
151
- label: "Client",
151
+ /* @__PURE__ */ j(u, {
152
+ label: i("psw.common.client", "Client"),
152
153
  required: !0,
153
- children: /* @__PURE__ */ A(u, {
154
- value: c,
154
+ children: /* @__PURE__ */ M(p, {
155
+ value: l,
155
156
  onChange: (e) => d(e.target.value),
156
- children: [/* @__PURE__ */ k("option", {
157
+ children: [/* @__PURE__ */ j("option", {
157
158
  value: "",
158
- children: "Select…"
159
- }), o.data?.items.map((e) => /* @__PURE__ */ k("option", {
159
+ children: i("psw.common.select", "Select…")
160
+ }), c.data?.items.map((e) => /* @__PURE__ */ j("option", {
160
161
  value: e.id,
161
162
  children: e.name
162
163
  }, e.id))]
163
164
  })
164
165
  }),
165
- /* @__PURE__ */ k(s, {
166
- label: "Parties searched",
166
+ /* @__PURE__ */ j(u, {
167
+ label: i("psw.conflicts.partiesSearched", "Parties searched"),
167
168
  required: !0,
168
- hint: "Comma-separated.",
169
- children: /* @__PURE__ */ k(_, {
170
- value: f,
171
- onChange: (e) => p(e.target.value),
169
+ hint: i("psw.conflicts.commaSeparated", "Comma-separated."),
170
+ children: /* @__PURE__ */ j(b, {
171
+ value: m,
172
+ onChange: (e) => h(e.target.value),
172
173
  placeholder: "Beta Corp, John Roe"
173
174
  })
174
175
  }),
175
- /* @__PURE__ */ k(s, {
176
- label: "Findings",
177
- children: /* @__PURE__ */ k(g, {
178
- value: m,
179
- onChange: (e) => h(e.target.value)
176
+ /* @__PURE__ */ j(u, {
177
+ label: i("psw.conflicts.findings", "Findings"),
178
+ children: /* @__PURE__ */ j(y, {
179
+ value: g,
180
+ onChange: (e) => _(e.target.value)
180
181
  })
181
182
  })
182
183
  ]
183
184
  })
184
185
  });
185
- }, F = ({ id: e, onClose: t, onDone: n }) => {
186
- let a = r(), [o, c] = w("CLEAR"), [d, f] = w(""), [p, m] = w(""), [h, _] = w(null);
187
- return /* @__PURE__ */ k(l, {
186
+ }, L = ({ id: e, onClose: t, onDone: n }) => {
187
+ let i = o(), c = a(), l = r(), [d, m] = E("CLEAR"), [h, g] = E(""), [_, v] = E(""), [b, x] = E(null);
188
+ return /* @__PURE__ */ j(f, {
188
189
  open: !0,
189
190
  onClose: t,
190
- title: "Resolve conflict check",
191
- footer: /* @__PURE__ */ A(O, { children: [/* @__PURE__ */ k(j, {
191
+ title: i("psw.conflicts.resolveTitle", "Resolve conflict check"),
192
+ footer: /* @__PURE__ */ M(A, { children: [/* @__PURE__ */ j(N, {
192
193
  variant: "outline",
193
194
  onClick: t,
194
- disabled: a.isPending,
195
- children: "Cancel"
196
- }), /* @__PURE__ */ k(j, {
197
- onClick: () => a.mutate({
195
+ disabled: l.isPending,
196
+ children: i("psw.common.cancel", "Cancel")
197
+ }), /* @__PURE__ */ j(N, {
198
+ onClick: () => l.mutate({
198
199
  id: e,
199
- status: o,
200
- findings: d.trim() || void 0,
201
- waiverReason: o === "WAIVED" && p.trim() || void 0
200
+ status: d,
201
+ findings: h.trim() || void 0,
202
+ waiverReason: d === "WAIVED" && _.trim() || void 0
202
203
  }, {
203
204
  onSuccess: () => {
204
205
  n(), t();
205
206
  },
206
- onError: (e) => _(e instanceof Error ? e.message : "Failed.")
207
+ onError: (e) => x(e instanceof Error ? e.message : i("psw.common.failed", "Failed."))
207
208
  }),
208
- disabled: a.isPending,
209
- children: a.isPending ? "Saving…" : "Resolve"
209
+ disabled: l.isPending,
210
+ children: l.isPending ? i("psw.common.saving", "Saving…") : i("psw.common.resolve", "Resolve")
210
211
  })] }),
211
- children: /* @__PURE__ */ A("div", {
212
+ children: /* @__PURE__ */ M("div", {
212
213
  className: "space-y-3",
213
214
  children: [
214
- h && /* @__PURE__ */ k(i, {
215
+ b && /* @__PURE__ */ j(s, {
215
216
  tone: "danger",
216
- children: h
217
+ children: b
217
218
  }),
218
- /* @__PURE__ */ k(s, {
219
- label: "Outcome",
220
- children: /* @__PURE__ */ k(u, {
221
- value: o,
222
- onChange: (e) => c(e.target.value),
223
- children: M.map((e) => /* @__PURE__ */ k("option", {
219
+ /* @__PURE__ */ j(u, {
220
+ label: i("psw.common.outcome", "Outcome"),
221
+ children: /* @__PURE__ */ j(p, {
222
+ value: d,
223
+ onChange: (e) => m(e.target.value),
224
+ children: P.map((e) => /* @__PURE__ */ j("option", {
224
225
  value: e,
225
- children: b(e)
226
+ children: c(e)
226
227
  }, e))
227
228
  })
228
229
  }),
229
- /* @__PURE__ */ k(s, {
230
- label: "Findings",
231
- children: /* @__PURE__ */ k(g, {
232
- value: d,
233
- onChange: (e) => f(e.target.value)
230
+ /* @__PURE__ */ j(u, {
231
+ label: i("psw.conflicts.findings", "Findings"),
232
+ children: /* @__PURE__ */ j(y, {
233
+ value: h,
234
+ onChange: (e) => g(e.target.value)
234
235
  })
235
236
  }),
236
- o === "WAIVED" && /* @__PURE__ */ k(s, {
237
- label: "Waiver reason",
238
- children: /* @__PURE__ */ k(g, {
239
- value: p,
240
- onChange: (e) => m(e.target.value)
237
+ d === "WAIVED" && /* @__PURE__ */ j(u, {
238
+ label: i("psw.conflicts.waiverReason", "Waiver reason"),
239
+ children: /* @__PURE__ */ j(y, {
240
+ value: _,
241
+ onChange: (e) => v(e.target.value)
241
242
  })
242
243
  })
243
244
  ]
@@ -245,6 +246,6 @@ var M = [
245
246
  });
246
247
  };
247
248
  //#endregion
248
- export { N as ConflictsPage };
249
+ export { F as ConflictsPage };
249
250
 
250
251
  //# sourceMappingURL=ConflictsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConflictsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ConflictsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useDeferredValue, useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, GitBranch, Search } from 'lucide-react';\nimport {\n useConflictChecks,\n useCreateConflictCheck,\n useResolveConflictCheck,\n useClients,\n type PswConflictCheckStatus,\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 humanize,\n fmtDate,\n} from '../components/ui';\nimport { useAnalytics } from '../hooks/useAnalytics';\n\nconst RESOLVE_STATUSES: PswConflictCheckStatus[] = [\n 'CLEAR',\n 'POTENTIAL_CONFLICT',\n 'CONFLICT',\n 'WAIVED',\n];\n\nexport const ConflictsPage: FC = () => {\n const [creating, setCreating] = useState(false);\n const [resolving, setResolving] = useState<{ id: string } | null>(null);\n const [banner, setBanner] = useState<string | null>(null);\n const [search, setSearch] = useState('');\n const deferredSearch = useDeferredValue(search);\n const { data, isLoading, error, refetch } = useConflictChecks({\n search: deferredSearch.trim() || undefined,\n });\n const { emitFact } = useAnalytics();\n const checks = data?.items ?? [];\n const clients = useClients({ pagination: { limit: 100 } });\n const clientName = useMemo(\n () => new Map((clients.data?.items ?? []).map((c) => [c.id, c.name])),\n [clients.data]\n );\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Conflict checks\"\n subtitle=\"Run before accepting a client or opening a matter — searched against existing clients, matters and counterparties, with a documented result and waiver.\"\n icon={<GitBranch className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n Run check\n </Button>\n }\n />\n\n {banner && (\n <Banner tone=\"success\" onClose={() => setBanner(null)}>\n {banner}\n </Banner>\n )}\n\n <div className=\"relative\">\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 conflict checks…\"\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: 'conflict-check',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : checks.length === 0 ? (\n <Empty\n title=\"No conflict checks\"\n description=\"Run a conflict check before taking on new work.\"\n icon={<GitBranch className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n Run check\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${checks.length} check${checks.length === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Client</Th>\n <Th>Parties searched</Th>\n <Th>Run</Th>\n <Th>Status</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {checks.map((c) => (\n <tr key={c.id} className=\"hover:bg-bg-sunken/50\">\n <Td>\n <span className=\"font-medium text-text-primary\">\n {clientName.get(c.clientId) ?? '—'}\n </span>\n </Td>\n <Td className=\"max-w-xs truncate\">{c.searchedParties.join(', ') || '—'}</Td>\n <Td>{fmtDate(c.createdAt)}</Td>\n <Td>\n <StatusPill status={c.status} />\n </Td>\n <Td className=\"text-right\">\n {c.status === 'PENDING' || c.status === 'POTENTIAL_CONFLICT' ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setResolving({ id: c.id })}>\n Resolve\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {c.resolvedAt ? fmtDate(c.resolvedAt) : ''}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <ConflictModal\n onClose={() => setCreating(false)}\n onDone={() => {\n void refetch();\n setBanner('Conflict check recorded.');\n }}\n />\n )}\n {resolving && (\n <ResolveModal\n id={resolving.id}\n onClose={() => setResolving(null)}\n onDone={() => {\n void refetch();\n setBanner('Conflict check resolved.');\n }}\n />\n )}\n </div>\n );\n};\n\nconst ConflictModal: FC<{ onClose: () => void; onDone: () => void }> = ({ onClose, onDone }) => {\n const create = useCreateConflictCheck();\n const clients = useClients({ pagination: { limit: 100 } });\n const [clientId, setClientId] = useState('');\n const [parties, setParties] = useState('');\n const [findings, setFindings] = useState('');\n const [err, setErr] = useState<string | null>(null);\n const submit = () => {\n setErr(null);\n if (!clientId) return setErr('Select a client.');\n const searchedParties = parties\n .split(',')\n .map((p) => p.trim())\n .filter(Boolean);\n if (searchedParties.length === 0) return setErr('Add at least one party.');\n create.mutate(\n { clientId, searchedParties, findings: findings.trim() || null },\n {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n return (\n <Modal\n open\n onClose={onClose}\n title=\"Run conflict check\"\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 ? 'Running…' : 'Record check'}\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={clientId} onChange={(e) => setClientId(e.target.value)}>\n <option value=\"\">Select…</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=\"Parties searched\" required hint=\"Comma-separated.\">\n <TextInput\n value={parties}\n onChange={(e) => setParties(e.target.value)}\n placeholder=\"Beta Corp, John Roe\"\n />\n </Field>\n <Field label=\"Findings\">\n <TextArea value={findings} onChange={(e) => setFindings(e.target.value)} />\n </Field>\n </div>\n </Modal>\n );\n};\n\nconst ResolveModal: FC<{ id: string; onClose: () => void; onDone: () => void }> = ({\n id,\n onClose,\n onDone,\n}) => {\n const resolve = useResolveConflictCheck();\n const [status, setStatus] = useState<PswConflictCheckStatus>('CLEAR');\n const [findings, setFindings] = useState('');\n const [waiverReason, setWaiverReason] = useState('');\n const [err, setErr] = useState<string | null>(null);\n const submit = () =>\n resolve.mutate(\n {\n id,\n status,\n findings: findings.trim() || undefined,\n waiverReason: status === 'WAIVED' ? waiverReason.trim() || undefined : undefined,\n },\n {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n return (\n <Modal\n open\n onClose={onClose}\n title=\"Resolve conflict check\"\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={resolve.isPending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={resolve.isPending}>\n {resolve.isPending ? 'Saving…' : 'Resolve'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Outcome\">\n <NativeSelect\n value={status}\n onChange={(e) => setStatus(e.target.value as PswConflictCheckStatus)}\n >\n {RESOLVE_STATUSES.map((s) => (\n <option key={s} value={s}>\n {humanize(s)}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Findings\">\n <TextArea value={findings} onChange={(e) => setFindings(e.target.value)} />\n </Field>\n {status === 'WAIVED' && (\n <Field label=\"Waiver reason\">\n <TextArea value={waiverReason} onChange={(e) => setWaiverReason(e.target.value)} />\n </Field>\n )}\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ConflictsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ConflictsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useDeferredValue, useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, GitBranch, Search } from 'lucide-react';\nimport {\n useConflictChecks,\n useCreateConflictCheck,\n useResolveConflictCheck,\n useClients,\n type PswConflictCheckStatus,\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 fmtDate,\n} from '../components/ui';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport { plural, useEnumLabel, useTr } from '../hooks/useTr';\n\nconst RESOLVE_STATUSES: PswConflictCheckStatus[] = [\n 'CLEAR',\n 'POTENTIAL_CONFLICT',\n 'CONFLICT',\n 'WAIVED',\n];\n\nexport const ConflictsPage: FC = () => {\n const tr = useTr();\n const [creating, setCreating] = useState(false);\n const [resolving, setResolving] = useState<{ id: string } | null>(null);\n const [banner, setBanner] = useState<string | null>(null);\n const [search, setSearch] = useState('');\n const deferredSearch = useDeferredValue(search);\n const { data, isLoading, error, refetch } = useConflictChecks({\n search: deferredSearch.trim() || undefined,\n });\n const { emitFact } = useAnalytics();\n const checks = data?.items ?? [];\n const clients = useClients({ pagination: { limit: 100 } });\n const clientName = useMemo(\n () => new Map((clients.data?.items ?? []).map((c) => [c.id, c.name])),\n [clients.data]\n );\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={tr('psw.conflicts.title', 'Conflict checks')}\n subtitle={tr(\n 'psw.conflicts.subtitle',\n 'Run before accepting a client or opening a matter — searched against existing clients, matters and counterparties, with a documented result and waiver.'\n )}\n icon={<GitBranch 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.conflicts.run', 'Run check')}\n </Button>\n }\n />\n\n {banner && (\n <Banner tone=\"success\" onClose={() => setBanner(null)}>\n {banner}\n </Banner>\n )}\n\n <div className=\"relative\">\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.conflicts.searchPlaceholder', 'Search conflict checks…')}\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: 'conflict-check',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"ps-9\"\n />\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : checks.length === 0 ? (\n <Empty\n title={tr('psw.conflicts.emptyTitle', 'No conflict checks')}\n description={tr(\n 'psw.conflicts.emptyDescription',\n 'Run a conflict check before taking on new work.'\n )}\n icon={<GitBranch 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.conflicts.run', 'Run check')}\n </Button>\n }\n />\n ) : (\n <SectionCard\n title={plural(\n tr,\n 'psw.conflicts.count',\n checks.length,\n '{{count}} check',\n '{{count}} checks'\n )}\n >\n <TableWrap>\n <thead>\n <tr>\n <Th>{tr('psw.common.client', 'Client')}</Th>\n <Th>{tr('psw.conflicts.partiesSearched', 'Parties searched')}</Th>\n <Th>{tr('psw.conflicts.runAt', 'Run')}</Th>\n <Th>{tr('psw.common.status', 'Status')}</Th>\n <Th className=\"text-end\">{tr('psw.common.actions', 'Actions')}</Th>\n </tr>\n </thead>\n <tbody>\n {checks.map((c) => (\n <tr key={c.id} className=\"hover:bg-bg-sunken/50\">\n <Td>\n <span className=\"font-medium text-text-primary\">\n {clientName.get(c.clientId) ?? '—'}\n </span>\n </Td>\n <Td className=\"max-w-xs truncate\">{c.searchedParties.join(', ') || '—'}</Td>\n <Td>{fmtDate(c.createdAt)}</Td>\n <Td>\n <StatusPill status={c.status} />\n </Td>\n <Td className=\"text-end\">\n {c.status === 'PENDING' || c.status === 'POTENTIAL_CONFLICT' ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setResolving({ id: c.id })}>\n {tr('psw.common.resolve', 'Resolve')}\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {c.resolvedAt ? fmtDate(c.resolvedAt) : ''}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <ConflictModal\n onClose={() => setCreating(false)}\n onDone={() => {\n void refetch();\n setBanner(tr('psw.conflicts.recorded', 'Conflict check recorded.'));\n }}\n />\n )}\n {resolving && (\n <ResolveModal\n id={resolving.id}\n onClose={() => setResolving(null)}\n onDone={() => {\n void refetch();\n setBanner(tr('psw.conflicts.resolved', 'Conflict check resolved.'));\n }}\n />\n )}\n </div>\n );\n};\n\nconst ConflictModal: FC<{ onClose: () => void; onDone: () => void }> = ({ onClose, onDone }) => {\n const tr = useTr();\n const create = useCreateConflictCheck();\n const clients = useClients({ pagination: { limit: 100 } });\n const [clientId, setClientId] = useState('');\n const [parties, setParties] = useState('');\n const [findings, setFindings] = useState('');\n const [err, setErr] = useState<string | null>(null);\n const submit = () => {\n setErr(null);\n if (!clientId) return setErr(tr('psw.conflicts.selectClient', 'Select a client.'));\n const searchedParties = parties\n .split(',')\n .map((p) => p.trim())\n .filter(Boolean);\n if (searchedParties.length === 0)\n return setErr(tr('psw.conflicts.partyRequired', 'Add at least one party.'));\n create.mutate(\n { clientId, searchedParties, findings: findings.trim() || null },\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 return (\n <Modal\n open\n onClose={onClose}\n title={tr('psw.conflicts.runTitle', 'Run conflict check')}\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={create.isPending}>\n {tr('psw.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submit} disabled={create.isPending}>\n {create.isPending\n ? tr('psw.conflicts.running', 'Running…')\n : tr('psw.conflicts.record', 'Record check')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.common.client', 'Client')} required>\n <NativeSelect value={clientId} onChange={(e) => setClientId(e.target.value)}>\n <option value=\"\">{tr('psw.common.select', 'Select…')}</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\n label={tr('psw.conflicts.partiesSearched', 'Parties searched')}\n required\n hint={tr('psw.conflicts.commaSeparated', 'Comma-separated.')}\n >\n <TextInput\n value={parties}\n onChange={(e) => setParties(e.target.value)}\n placeholder=\"Beta Corp, John Roe\"\n />\n </Field>\n <Field label={tr('psw.conflicts.findings', 'Findings')}>\n <TextArea value={findings} onChange={(e) => setFindings(e.target.value)} />\n </Field>\n </div>\n </Modal>\n );\n};\n\nconst ResolveModal: FC<{ id: string; onClose: () => void; onDone: () => void }> = ({\n id,\n onClose,\n onDone,\n}) => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\n const resolve = useResolveConflictCheck();\n const [status, setStatus] = useState<PswConflictCheckStatus>('CLEAR');\n const [findings, setFindings] = useState('');\n const [waiverReason, setWaiverReason] = useState('');\n const [err, setErr] = useState<string | null>(null);\n const submit = () =>\n resolve.mutate(\n {\n id,\n status,\n findings: findings.trim() || undefined,\n waiverReason: status === 'WAIVED' ? waiverReason.trim() || undefined : undefined,\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 return (\n <Modal\n open\n onClose={onClose}\n title={tr('psw.conflicts.resolveTitle', 'Resolve conflict check')}\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={resolve.isPending}>\n {tr('psw.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submit} disabled={resolve.isPending}>\n {resolve.isPending\n ? tr('psw.common.saving', 'Saving…')\n : tr('psw.common.resolve', 'Resolve')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.common.outcome', 'Outcome')}>\n <NativeSelect\n value={status}\n onChange={(e) => setStatus(e.target.value as PswConflictCheckStatus)}\n >\n {RESOLVE_STATUSES.map((s) => (\n <option key={s} value={s}>\n {enumLabel(s)}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label={tr('psw.conflicts.findings', 'Findings')}>\n <TextArea value={findings} onChange={(e) => setFindings(e.target.value)} />\n </Field>\n {status === 'WAIVED' && (\n <Field label={tr('psw.conflicts.waiverReason', 'Waiver reason')}>\n <TextArea value={waiverReason} onChange={(e) => setWaiverReason(e.target.value)} />\n </Field>\n )}\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentsPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/DocumentsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAmChC,eAAO,MAAM,aAAa,EAAE,EA6K3B,CAAC"}
1
+ {"version":3,"file":"DocumentsPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/DocumentsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAmChC,eAAO,MAAM,aAAa,EAAE,EAwM3B,CAAC"}