@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":"MattersPage.js","names":[],"sources":["../../../src/proserviceworld/pages/MattersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n FolderKanban,\n Lock,\n CheckCircle2,\n CircleDot,\n AlertTriangle,\n} from 'lucide-react';\nimport {\n useMatters,\n useCreateMatter,\n useUpdateMatter,\n useCloseMatter,\n useClients,\n usePracticeAreas,\n type PswMatterStatus,\n type PswMatter,\n} from '../hooks/useProServiceWorldApi';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport { useTr } from '../hooks/useTr';\nimport { impactFeedback } from '../utils/native';\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 { TagPicker } from '../components/TagPicker';\nimport { LoadMore } from '../components/LoadMore';\n\nconst STATUSES: PswMatterStatus[] = ['OPEN', 'ON_HOLD', 'CLOSED', 'ARCHIVED'];\nconst PRIORITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const;\n\n/** Amber padlock chip that flags privileged / confidential matters. */\nconst PrivilegeLock: FC = () => {\n const tr = useTr();\n return (\n <span\n className=\"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text\"\n title={tr('psw.matters.privilegedLabel', 'Privileged / confidential')}\n aria-label={tr('psw.matters.privilegedAria', 'Privileged')}\n >\n <Lock className=\"h-3 w-3\" />\n </span>\n );\n};\n\nconst PAGE_SIZE = 25;\n\nexport const MattersPage: FC = () => {\n const tr = useTr();\n const { emitIntent, emitFact } = useAnalytics();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswMatterStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const [pagination, setPagination] = useState({ limit: PAGE_SIZE, offset: 0 });\n const { data, isLoading, error, refetch } = useMatters({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n pagination,\n });\n const close = useCloseMatter();\n const update = useUpdateMatter();\n\n const items = useMemo(() => data?.items ?? [], [data]);\n const openCount = items.filter((m) => m.status === 'OPEN').length;\n const privilegedCount = items.filter((m) => m.isPrivileged).length;\n const highCount = items.filter((m) => m.priority === 'HIGH' || m.priority === 'CRITICAL').length;\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={tr('psw.matters.title', 'Matters')}\n subtitle={tr(\n 'psw.matters.subtitle',\n 'The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.'\n )}\n icon={<FolderKanban className=\"h-6 w-6\" />}\n actions={\n <Button\n onClick={() => {\n void impactFeedback('light');\n emitIntent('psw.matter.create_clicked');\n setCreating(true);\n }}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {tr('psw.matters.new', 'New matter')}\n </Button>\n }\n />\n\n {banner && (\n <Banner tone={banner.tone} onClose={() => setBanner(null)}>\n {banner.text}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder={tr('psw.matters.searchPlaceholder', 'Search matters…')}\n value={search}\n onChange={(e) => {\n setSearch(e.target.value);\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && search.trim()) {\n emitFact('psw.search.performed', {\n entityType: 'matter',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as PswMatterStatus | '');\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n className=\"sm:w-48\"\n >\n <option value=\"\">{tr('psw.matters.allStatuses', 'All statuses')}</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title={tr('psw.matters.emptyTitle', 'No matters yet')}\n description={tr(\n 'psw.matters.emptyDescription',\n 'Create your first matter to track deadlines, privileged documents, and status.'\n )}\n icon={<FolderKanban className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {tr('psw.matters.new', 'New matter')}\n </Button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <MetricCard\n label={tr('psw.matters.metricTotal', 'Matters')}\n value={data.totalCount}\n icon={<FolderKanban className=\"h-4 w-4\" />}\n />\n <MetricCard\n label={tr('psw.matters.metricOpen', 'Open')}\n value={openCount}\n icon={<CircleDot className=\"h-4 w-4\" />}\n tone=\"accent\"\n />\n <MetricCard\n label={tr('psw.matters.metricPrivileged', 'Privileged')}\n value={privilegedCount}\n icon={<Lock className=\"h-4 w-4\" />}\n tone=\"warning\"\n />\n <MetricCard\n label={tr('psw.matters.metricHighPriority', 'High priority')}\n value={highCount}\n icon={<AlertTriangle className=\"h-4 w-4\" />}\n tone={highCount ? 'danger' : 'neutral'}\n />\n </div>\n\n <SectionCard\n title={\n data.totalCount === 1\n ? tr('psw.matters.count', '{{count}} matter', { count: data.totalCount })\n : tr('psw.matters.countPlural', '{{count}} matters', { count: data.totalCount })\n }\n >\n <TableWrap>\n <thead>\n <tr>\n <Th>{tr('psw.matters.tableMatter', 'Matter')}</Th>\n <Th>{tr('psw.matters.tableClient', 'Client')}</Th>\n <Th>{tr('psw.matters.tablePriority', 'Priority')}</Th>\n <Th>{tr('psw.matters.tableStatus', 'Status')}</Th>\n <Th>{tr('psw.matters.tableDue', 'Due')}</Th>\n <Th>{tr('psw.matters.tableTags', 'Tags')}</Th>\n <Th className=\"text-right\">{tr('psw.common.actions', 'Actions')}</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((m) => (\n <tr key={m.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"flex items-center gap-2 font-medium text-text-primary\">\n {m.isPrivileged && <PrivilegeLock />}\n <span className=\"truncate\">{m.title}</span>\n </span>\n {m.reference ? (\n <div className=\"mt-0.5 pl-0 text-xs text-text-tertiary\">\n {tr('psw.matters.reference', 'Ref: {{reference}}', {\n reference: m.reference,\n })}\n </div>\n ) : null}\n </Td>\n <Td className=\"text-text-primary\">\n {m.client?.name ?? tr('psw.common.dash', '—')}\n </Td>\n <Td>\n <StatusPill status={m.priority} />\n </Td>\n <Td>\n <StatusPill status={m.status} />\n </Td>\n <Td>{fmtDate(m.dueDate)}</Td>\n <Td>\n <TagPicker\n entityType=\"PswMatter\"\n entityId={m.id}\n tags={m.tags ?? []}\n onChange={async (tags) => {\n await update.mutateAsync({ id: m.id, input: { tags } });\n void refetch();\n }}\n maxTags={5}\n />\n </Td>\n <Td className=\"text-right\">\n {m.status !== 'CLOSED' && m.status !== 'ARCHIVED' ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={close.isPending}\n onClick={() =>\n close.mutate(m.id, {\n onSuccess: () => {\n emitFact('psw.matter.closed', { matterId: m.id });\n setBanner({\n tone: 'success',\n text: tr('psw.matters.closed', '{{title}} closed.', {\n title: m.title,\n }),\n });\n },\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text:\n e instanceof Error\n ? e.message\n : tr('psw.matters.createFailed', 'Failed.'),\n }),\n })\n }\n >\n <CheckCircle2 className=\"mr-1 h-4 w-4\" />{' '}\n {tr('psw.matters.close', 'Close')}\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {m.closedAt\n ? tr('psw.matters.closedAt', 'Closed {{date}}', {\n date: fmtDate(m.closedAt),\n })\n : tr('psw.common.dash', '—')}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n <LoadMore\n hasMore={data?.pageInfo?.hasMore ?? false}\n loading={isLoading}\n loadedCount={items.length}\n totalCount={data?.totalCount ?? items.length}\n onLoadMore={() =>\n setPagination((p) => ({ limit: PAGE_SIZE, offset: p.offset + PAGE_SIZE }))\n }\n />\n </SectionCard>\n </>\n )}\n\n {creating && (\n <MatterModal\n onClose={() => setCreating(false)}\n onSaved={(title) =>\n setBanner({\n tone: 'success',\n text: tr('psw.matters.opened', '{{title}} opened.', { title }),\n })\n }\n />\n )}\n </div>\n );\n};\n\nconst MatterModal: FC<{ onClose: () => void; onSaved: (title: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const tr = useTr();\n const create = useCreateMatter();\n const { emitFact } = useAnalytics();\n const clients = useClients({ pagination: { limit: 100 } });\n const practiceAreas = usePracticeAreas();\n const [form, setForm] = useState({\n clientId: '',\n practiceAreaId: '',\n title: '',\n reference: '',\n description: '',\n priority: 'MEDIUM',\n dueDate: '',\n isPrivileged: false,\n });\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof typeof form) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n\n const submit = () => {\n setErr(null);\n if (!form.clientId) return setErr(tr('psw.matters.selectClient', 'Select a client.'));\n if (!form.title.trim())\n return setErr(tr('psw.matters.titleRequired', 'Matter title is required.'));\n create.mutate(\n {\n clientId: form.clientId,\n practiceAreaId: form.practiceAreaId || null,\n title: form.title.trim(),\n reference: form.reference.trim() || null,\n description: form.description.trim() || null,\n priority: form.priority,\n isPrivileged: form.isPrivileged,\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n },\n {\n onSuccess: (created) => {\n const matter = (created as { pswCreateMatter: PswMatter }).pswCreateMatter;\n emitFact('psw.matter.created', {\n matterId: matter.id,\n clientId: form.clientId,\n });\n onSaved(form.title.trim());\n onClose();\n },\n onError: (e) =>\n setErr(e instanceof Error ? e.message : tr('psw.matters.createFailed', 'Failed.')),\n }\n );\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title={tr('psw.matters.newTitle', 'New matter')}\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.opening', 'Opening…')\n : tr('psw.common.create', 'Open matter')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.matters.client', 'Client')} required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\n <option value=\"\">\n {tr('psw.engagements.selectClientPlaceholder', 'Select a client…')}\n </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={tr('psw.matters.titleLabel', 'Title')} required>\n <TextInput\n value={form.title}\n onChange={set('title')}\n placeholder={tr(\n 'psw.matters.titlePlaceholder',\n 'Regulatory investigation — SEC inquiry'\n )}\n />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label={tr('psw.matters.referenceLabel', 'Reference')}>\n <TextInput\n value={form.reference}\n onChange={set('reference')}\n placeholder={tr('psw.matters.referencePlaceholder', 'MAT-2026-014')}\n />\n </Field>\n <Field label={tr('psw.matters.priority', 'Priority')}>\n <NativeSelect value={form.priority} onChange={set('priority')}>\n {enumOptions(PRIORITIES)}\n </NativeSelect>\n </Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label={tr('psw.matters.practiceArea', 'Practice area')}>\n <NativeSelect value={form.practiceAreaId} onChange={set('practiceAreaId')}>\n <option value=\"\">{tr('psw.engagements.unassigned', 'Unassigned')}</option>\n {practiceAreas.data?.items.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label={tr('psw.matters.dueDate', 'Due date')}>\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n </div>\n <Field label={tr('psw.matters.description', 'Description')}>\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n <label className=\"flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-canvas px-3 py-2.5 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.isPrivileged}\n onChange={(e) => setForm((f) => ({ ...f, isPrivileged: e.target.checked }))}\n />\n <span className=\"flex items-center gap-1.5\">\n <Lock className=\"h-3.5 w-3.5 text-status-warning-text\" />\n {tr('psw.matters.privilegedLabel', 'Privileged / confidential matter')}\n </span>\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"MattersPage.js","names":[],"sources":["../../../src/proserviceworld/pages/MattersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n FolderKanban,\n Lock,\n CheckCircle2,\n CircleDot,\n AlertTriangle,\n} from 'lucide-react';\nimport {\n useMatters,\n useCreateMatter,\n useUpdateMatter,\n useCloseMatter,\n useClients,\n usePracticeAreas,\n type PswMatterStatus,\n type PswMatter,\n} from '../hooks/useProServiceWorldApi';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport { useEnumLabel, useTr } from '../hooks/useTr';\nimport { impactFeedback } from '../utils/native';\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 { TagPicker } from '../components/TagPicker';\nimport { LoadMore } from '../components/LoadMore';\n\nconst STATUSES: PswMatterStatus[] = ['OPEN', 'ON_HOLD', 'CLOSED', 'ARCHIVED'];\nconst PRIORITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const;\n\n/** Amber padlock chip that flags privileged / confidential matters. */\nconst PrivilegeLock: FC = () => {\n const tr = useTr();\n return (\n <span\n className=\"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text\"\n title={tr('psw.matters.privilegedTitle', 'Privileged / confidential')}\n aria-label={tr('psw.matters.privilegedAria', 'Privileged')}\n >\n <Lock className=\"h-3 w-3\" />\n </span>\n );\n};\n\nconst PAGE_SIZE = 25;\n\nexport const MattersPage: FC = () => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\n const { emitIntent, emitFact } = useAnalytics();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswMatterStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const [pagination, setPagination] = useState({ limit: PAGE_SIZE, offset: 0 });\n const { data, isLoading, error, refetch } = useMatters({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n pagination,\n });\n const close = useCloseMatter();\n const update = useUpdateMatter();\n\n const items = useMemo(() => data?.items ?? [], [data]);\n const openCount = items.filter((m) => m.status === 'OPEN').length;\n const privilegedCount = items.filter((m) => m.isPrivileged).length;\n const highCount = items.filter((m) => m.priority === 'HIGH' || m.priority === 'CRITICAL').length;\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={tr('psw.matters.title', 'Matters')}\n subtitle={tr(\n 'psw.matters.subtitle',\n 'The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.'\n )}\n icon={<FolderKanban className=\"h-6 w-6\" />}\n actions={\n <Button\n onClick={() => {\n void impactFeedback('light');\n emitIntent('psw.matter.create_clicked');\n setCreating(true);\n }}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {tr('psw.matters.new', 'New matter')}\n </Button>\n }\n />\n\n {banner && (\n <Banner tone={banner.tone} onClose={() => setBanner(null)}>\n {banner.text}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder={tr('psw.matters.searchPlaceholder', 'Search matters…')}\n value={search}\n onChange={(e) => {\n setSearch(e.target.value);\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && search.trim()) {\n emitFact('psw.search.performed', {\n entityType: 'matter',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as PswMatterStatus | '');\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n className=\"sm:w-48\"\n >\n <option value=\"\">{tr('psw.matters.allStatuses', 'All statuses')}</option>\n {enumOptions(STATUSES, 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.matters.emptyTitle', 'No matters yet')}\n description={tr(\n 'psw.matters.emptyDescription',\n 'Create your first matter to track deadlines, privileged documents, and status.'\n )}\n icon={<FolderKanban className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {tr('psw.matters.new', 'New matter')}\n </Button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <MetricCard\n label={tr('psw.matters.metricTotal', 'Matters')}\n value={data.totalCount}\n icon={<FolderKanban className=\"h-4 w-4\" />}\n />\n <MetricCard\n label={tr('psw.matters.metricOpen', 'Open')}\n value={openCount}\n icon={<CircleDot className=\"h-4 w-4\" />}\n tone=\"accent\"\n />\n <MetricCard\n label={tr('psw.matters.metricPrivileged', 'Privileged')}\n value={privilegedCount}\n icon={<Lock className=\"h-4 w-4\" />}\n tone=\"warning\"\n />\n <MetricCard\n label={tr('psw.matters.metricHighPriority', 'High priority')}\n value={highCount}\n icon={<AlertTriangle className=\"h-4 w-4\" />}\n tone={highCount ? 'danger' : 'neutral'}\n />\n </div>\n\n <SectionCard\n title={\n data.totalCount === 1\n ? tr('psw.matters.count', '{{count}} matter', { count: data.totalCount })\n : tr('psw.matters.countPlural', '{{count}} matters', { count: data.totalCount })\n }\n >\n <TableWrap>\n <thead>\n <tr>\n <Th>{tr('psw.matters.tableMatter', 'Matter')}</Th>\n <Th>{tr('psw.matters.tableClient', 'Client')}</Th>\n <Th>{tr('psw.matters.tablePriority', 'Priority')}</Th>\n <Th>{tr('psw.matters.tableStatus', 'Status')}</Th>\n <Th>{tr('psw.matters.tableDue', 'Due')}</Th>\n <Th>{tr('psw.matters.tableTags', 'Tags')}</Th>\n <Th className=\"text-right\">{tr('psw.common.actions', 'Actions')}</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((m) => (\n <tr key={m.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"flex items-center gap-2 font-medium text-text-primary\">\n {m.isPrivileged && <PrivilegeLock />}\n <span className=\"truncate\">{m.title}</span>\n </span>\n {m.reference ? (\n <div className=\"mt-0.5 pl-0 text-xs text-text-tertiary\">\n {tr('psw.matters.reference', 'Ref: {{reference}}', {\n reference: m.reference,\n })}\n </div>\n ) : null}\n </Td>\n <Td className=\"text-text-primary\">\n {m.client?.name ?? tr('psw.common.dash', '—')}\n </Td>\n <Td>\n <StatusPill status={m.priority} />\n </Td>\n <Td>\n <StatusPill status={m.status} />\n </Td>\n <Td>{fmtDate(m.dueDate)}</Td>\n <Td>\n <TagPicker\n entityType=\"PswMatter\"\n entityId={m.id}\n tags={m.tags ?? []}\n onChange={async (tags) => {\n await update.mutateAsync({ id: m.id, input: { tags } });\n void refetch();\n }}\n maxTags={5}\n />\n </Td>\n <Td className=\"text-right\">\n {m.status !== 'CLOSED' && m.status !== 'ARCHIVED' ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={close.isPending}\n onClick={() =>\n close.mutate(m.id, {\n onSuccess: () => {\n emitFact('psw.matter.closed', { matterId: m.id });\n setBanner({\n tone: 'success',\n text: tr('psw.matters.closed', '{{title}} closed.', {\n title: m.title,\n }),\n });\n },\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text:\n e instanceof Error\n ? e.message\n : tr('psw.matters.createFailed', 'Failed.'),\n }),\n })\n }\n >\n <CheckCircle2 className=\"mr-1 h-4 w-4\" />{' '}\n {tr('psw.matters.close', 'Close')}\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {m.closedAt\n ? tr('psw.matters.closedAt', 'Closed {{date}}', {\n date: fmtDate(m.closedAt),\n })\n : tr('psw.common.dash', '—')}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n <LoadMore\n hasMore={data?.pageInfo?.hasMore ?? false}\n loading={isLoading}\n loadedCount={items.length}\n totalCount={data?.totalCount ?? items.length}\n onLoadMore={() =>\n setPagination((p) => ({ limit: PAGE_SIZE, offset: p.offset + PAGE_SIZE }))\n }\n />\n </SectionCard>\n </>\n )}\n\n {creating && (\n <MatterModal\n onClose={() => setCreating(false)}\n onSaved={(title) =>\n setBanner({\n tone: 'success',\n text: tr('psw.matters.opened', '{{title}} opened.', { title }),\n })\n }\n />\n )}\n </div>\n );\n};\n\nconst MatterModal: FC<{ onClose: () => void; onSaved: (title: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\n const create = useCreateMatter();\n const { emitFact } = useAnalytics();\n const clients = useClients({ pagination: { limit: 100 } });\n const practiceAreas = usePracticeAreas();\n const [form, setForm] = useState({\n clientId: '',\n practiceAreaId: '',\n title: '',\n reference: '',\n description: '',\n priority: 'MEDIUM',\n dueDate: '',\n isPrivileged: false,\n });\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof typeof form) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n\n const submit = () => {\n setErr(null);\n if (!form.clientId) return setErr(tr('psw.matters.selectClient', 'Select a client.'));\n if (!form.title.trim())\n return setErr(tr('psw.matters.titleRequired', 'Matter title is required.'));\n create.mutate(\n {\n clientId: form.clientId,\n practiceAreaId: form.practiceAreaId || null,\n title: form.title.trim(),\n reference: form.reference.trim() || null,\n description: form.description.trim() || null,\n priority: form.priority,\n isPrivileged: form.isPrivileged,\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n },\n {\n onSuccess: (created) => {\n const matter = (created as { pswCreateMatter: PswMatter }).pswCreateMatter;\n emitFact('psw.matter.created', {\n matterId: matter.id,\n clientId: form.clientId,\n });\n onSaved(form.title.trim());\n onClose();\n },\n onError: (e) =>\n setErr(e instanceof Error ? e.message : tr('psw.matters.createFailed', 'Failed.')),\n }\n );\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title={tr('psw.matters.newTitle', 'New matter')}\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.opening', 'Opening…')\n : tr('psw.matters.open', 'Open matter')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.matters.client', 'Client')} required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\n <option value=\"\">\n {tr('psw.engagements.selectClientPlaceholder', 'Select a client…')}\n </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={tr('psw.matters.titleLabel', 'Title')} required>\n <TextInput\n value={form.title}\n onChange={set('title')}\n placeholder={tr(\n 'psw.matters.titlePlaceholder',\n 'Regulatory investigation — SEC inquiry'\n )}\n />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label={tr('psw.matters.referenceLabel', 'Reference')}>\n <TextInput\n value={form.reference}\n onChange={set('reference')}\n placeholder={tr('psw.matters.referencePlaceholder', 'MAT-2026-014')}\n />\n </Field>\n <Field label={tr('psw.matters.priority', 'Priority')}>\n <NativeSelect value={form.priority} onChange={set('priority')}>\n {enumOptions(PRIORITIES, enumLabel)}\n </NativeSelect>\n </Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label={tr('psw.matters.practiceArea', 'Practice area')}>\n <NativeSelect value={form.practiceAreaId} onChange={set('practiceAreaId')}>\n <option value=\"\">{tr('psw.engagements.unassigned', 'Unassigned')}</option>\n {practiceAreas.data?.items.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label={tr('psw.matters.dueDate', 'Due date')}>\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n </div>\n <Field label={tr('psw.matters.description', 'Description')}>\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n <label className=\"flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-canvas px-3 py-2.5 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.isPrivileged}\n onChange={(e) => setForm((f) => ({ ...f, isPrivileged: e.target.checked }))}\n />\n <span className=\"flex items-center gap-1.5\">\n <Lock className=\"h-3.5 w-3.5 text-status-warning-text\" />\n {tr('psw.matters.privilegedLabel', 'Privileged / confidential matter')}\n </span>\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PracticeAreasPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/PracticeAreasPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAwBhC,eAAO,MAAM,iBAAiB,EAAE,EA4F/B,CAAC"}
1
+ {"version":3,"file":"PracticeAreasPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/PracticeAreasPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAyBhC,eAAO,MAAM,iBAAiB,EAAE,EAwG/B,CAAC"}
@@ -1,176 +1,177 @@
1
1
  import { useCreatePracticeArea as e, usePracticeAreas as t, useUpdatePracticeArea as n } from "../hooks/useProServiceWorldApi.js";
2
- import { Banner as r, Empty as i, ErrorState as a, Field as o, LoadingBlock as s, Modal as c, PageHeader as l, SectionCard as u, StatusPill as d, TextArea as f, TextInput as p } from "../components/ui.js";
3
- import { useState as m } from "react";
4
- import { LayoutGrid as h, Pencil as g, Plus as _ } from "lucide-react";
5
- import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
6
- import { Button as x } from "@burdenoff/fe-libs/ui";
2
+ import { useTr as r } from "../hooks/useTr.js";
3
+ import { Banner as i, Empty as a, ErrorState as o, Field as s, LoadingBlock as c, Modal as l, PageHeader as u, SectionCard as d, StatusPill as f, TextArea as p, TextInput as m } from "../components/ui.js";
4
+ import { useState as h } from "react";
5
+ import { LayoutGrid as g, Pencil as _, Plus as v } from "lucide-react";
6
+ import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
7
+ import { Button as S } from "@burdenoff/fe-libs/ui";
7
8
  //#region src/proserviceworld/pages/PracticeAreasPage.tsx
8
- var S = () => {
9
- let { data: e, isLoading: n, error: o, refetch: c } = t(), f = e?.items ?? [], [p, v] = m(!1), [S, w] = m(null), [T, E] = m(null);
10
- return /* @__PURE__ */ b("div", {
9
+ var C = () => {
10
+ let e = r(), { data: n, isLoading: s, error: l, refetch: p } = t(), m = n?.items ?? [], [y, C] = h(!1), [T, E] = h(null), [D, O] = h(null);
11
+ return /* @__PURE__ */ x("div", {
11
12
  className: "space-y-6",
12
13
  children: [
13
- /* @__PURE__ */ y(l, {
14
- title: "Practice areas",
15
- subtitle: "The domains of service your firm offers — Tax, Audit, Litigation, Advisory — that engagements and matters classify against.",
16
- icon: /* @__PURE__ */ y(h, { className: "h-6 w-6" }),
17
- actions: /* @__PURE__ */ b(x, {
18
- onClick: () => v(!0),
19
- children: [/* @__PURE__ */ y(_, { className: "mr-1.5 h-4 w-4" }), "New area"]
14
+ /* @__PURE__ */ b(u, {
15
+ title: e("psw.practiceAreas.title", "Practice areas"),
16
+ subtitle: e("psw.practiceAreas.subtitle", "The domains of service your firm offers — Tax, Audit, Litigation, Advisory — that engagements and matters classify against."),
17
+ icon: /* @__PURE__ */ b(g, { className: "h-6 w-6" }),
18
+ actions: /* @__PURE__ */ x(S, {
19
+ onClick: () => C(!0),
20
+ children: [/* @__PURE__ */ b(v, { className: "me-1.5 h-4 w-4" }), e("psw.practiceAreas.new", "New area")]
20
21
  })
21
22
  }),
22
- T && /* @__PURE__ */ y(r, {
23
+ D && /* @__PURE__ */ b(i, {
23
24
  tone: "success",
24
- onClose: () => E(null),
25
- children: T
25
+ onClose: () => O(null),
26
+ children: D
26
27
  }),
27
- n ? /* @__PURE__ */ y(s, {}) : o ? /* @__PURE__ */ y(a, {
28
- error: o,
29
- onRetry: () => void c()
30
- }) : f.length === 0 ? /* @__PURE__ */ y(i, {
31
- title: "No practice areas",
32
- description: "Define the service domains your firm offers.",
33
- icon: /* @__PURE__ */ y(h, { className: "h-8 w-8" }),
34
- action: /* @__PURE__ */ b(x, {
35
- onClick: () => v(!0),
36
- children: [/* @__PURE__ */ y(_, { className: "mr-1.5 h-4 w-4" }), "New area"]
28
+ s ? /* @__PURE__ */ b(c, {}) : l ? /* @__PURE__ */ b(o, {
29
+ error: l,
30
+ onRetry: () => void p()
31
+ }) : m.length === 0 ? /* @__PURE__ */ b(a, {
32
+ title: e("psw.practiceAreas.emptyTitle", "No practice areas"),
33
+ description: e("psw.practiceAreas.emptyDescription", "Define the service domains your firm offers."),
34
+ icon: /* @__PURE__ */ b(g, { className: "h-8 w-8" }),
35
+ action: /* @__PURE__ */ x(S, {
36
+ onClick: () => C(!0),
37
+ children: [/* @__PURE__ */ b(v, { className: "me-1.5 h-4 w-4" }), e("psw.practiceAreas.new", "New area")]
37
38
  })
38
- }) : /* @__PURE__ */ y("div", {
39
+ }) : /* @__PURE__ */ b("div", {
39
40
  className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3",
40
- children: f.map((e) => /* @__PURE__ */ b(u, { children: [/* @__PURE__ */ b("div", {
41
+ children: m.map((t) => /* @__PURE__ */ x(d, { children: [/* @__PURE__ */ x("div", {
41
42
  className: "flex items-start justify-between",
42
- children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ b("div", {
43
+ children: [/* @__PURE__ */ x("div", { children: [/* @__PURE__ */ x("div", {
43
44
  className: "flex items-center gap-2",
44
- children: [/* @__PURE__ */ y("h3", {
45
+ children: [/* @__PURE__ */ b("h3", {
45
46
  className: "text-sm font-semibold text-text-primary",
46
- children: e.name
47
- }), e.code ? /* @__PURE__ */ y("span", {
47
+ children: t.name
48
+ }), t.code ? /* @__PURE__ */ b("span", {
48
49
  className: "rounded bg-bg-sunken px-1.5 py-0.5 text-xs text-text-tertiary",
49
- children: e.code
50
+ children: t.code
50
51
  }) : null]
51
- }), /* @__PURE__ */ y(d, {
52
- status: e.isActive ? "ACTIVE" : "INACTIVE",
52
+ }), /* @__PURE__ */ b(f, {
53
+ status: t.isActive ? "ACTIVE" : "INACTIVE",
53
54
  className: "mt-1.5"
54
- })] }), /* @__PURE__ */ y(x, {
55
+ })] }), /* @__PURE__ */ b(S, {
55
56
  variant: "ghost",
56
57
  size: "sm",
57
- "aria-label": "Edit",
58
- onClick: () => w(e),
59
- children: /* @__PURE__ */ y(g, { className: "h-4 w-4" })
58
+ "aria-label": e("psw.common.edit", "Edit"),
59
+ onClick: () => E(t),
60
+ children: /* @__PURE__ */ b(_, { className: "h-4 w-4" })
60
61
  })]
61
- }), e.description ? /* @__PURE__ */ y("p", {
62
+ }), t.description ? /* @__PURE__ */ b("p", {
62
63
  className: "mt-2 text-sm text-text-secondary",
63
- children: e.description
64
- }) : null] }, e.id))
64
+ children: t.description
65
+ }) : null] }, t.id))
65
66
  }),
66
- p && /* @__PURE__ */ y(C, {
67
- onClose: () => v(!1),
67
+ y && /* @__PURE__ */ b(w, {
68
+ onClose: () => C(!1),
68
69
  onDone: () => {
69
- c(), E("Practice area created.");
70
+ p(), O(e("psw.practiceAreas.created", "Practice area created."));
70
71
  }
71
72
  }),
72
- S && /* @__PURE__ */ y(C, {
73
- area: S,
74
- onClose: () => w(null),
73
+ T && /* @__PURE__ */ b(w, {
74
+ area: T,
75
+ onClose: () => E(null),
75
76
  onDone: () => {
76
- c(), E("Practice area updated.");
77
+ p(), O(e("psw.practiceAreas.updated", "Practice area updated."));
77
78
  }
78
79
  })
79
80
  ]
80
81
  });
81
- }, C = ({ area: t, onClose: i, onDone: a }) => {
82
- let s = e(), l = n(), [u, d] = m({
82
+ }, w = ({ area: t, onClose: a, onDone: o }) => {
83
+ let c = r(), u = e(), d = n(), [f, g] = h({
83
84
  name: t?.name ?? "",
84
85
  code: t?.code ?? "",
85
86
  description: t?.description ?? "",
86
87
  isActive: t?.isActive ?? !0
87
- }), [h, g] = m(null), _ = s.isPending || l.isPending, S = (e) => (t) => d((n) => ({
88
+ }), [_, v] = h(null), C = u.isPending || d.isPending, w = (e) => (t) => g((n) => ({
88
89
  ...n,
89
90
  [e]: t.target.value
90
91
  }));
91
- return /* @__PURE__ */ y(c, {
92
+ return /* @__PURE__ */ b(l, {
92
93
  open: !0,
93
- onClose: i,
94
- title: t ? "Edit practice area" : "New practice area",
95
- footer: /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ y(x, {
94
+ onClose: a,
95
+ title: t ? c("psw.practiceAreas.editTitle", "Edit practice area") : c("psw.practiceAreas.newTitle", "New practice area"),
96
+ footer: /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(S, {
96
97
  variant: "outline",
97
- onClick: i,
98
- disabled: _,
99
- children: "Cancel"
100
- }), /* @__PURE__ */ y(x, {
98
+ onClick: a,
99
+ disabled: C,
100
+ children: c("psw.common.cancel", "Cancel")
101
+ }), /* @__PURE__ */ b(S, {
101
102
  onClick: () => {
102
- if (g(null), !u.name.trim()) return g("Name is required.");
103
+ if (v(null), !f.name.trim()) return v(c("psw.practiceAreas.nameRequired", "Name is required."));
103
104
  let e = {
104
- name: u.name.trim(),
105
- code: u.code.trim() || null,
106
- description: u.description.trim() || null,
107
- isActive: u.isActive
108
- }, n = (e) => g(e instanceof Error ? e.message : "Failed.");
109
- t ? l.mutate({
105
+ name: f.name.trim(),
106
+ code: f.code.trim() || null,
107
+ description: f.description.trim() || null,
108
+ isActive: f.isActive
109
+ }, n = (e) => v(e instanceof Error ? e.message : c("psw.common.failed", "Failed."));
110
+ t ? d.mutate({
110
111
  id: t.id,
111
112
  input: e
112
113
  }, {
113
114
  onSuccess: () => {
114
- a(), i();
115
+ o(), a();
115
116
  },
116
117
  onError: n
117
- }) : s.mutate(e, {
118
+ }) : u.mutate(e, {
118
119
  onSuccess: () => {
119
- a(), i();
120
+ o(), a();
120
121
  },
121
122
  onError: n
122
123
  });
123
124
  },
124
- disabled: _,
125
- children: _ ? "Saving…" : t ? "Save" : "Create"
125
+ disabled: C,
126
+ children: C ? c("psw.common.saving", "Saving…") : t ? c("psw.common.save", "Save") : c("psw.common.create", "Create")
126
127
  })] }),
127
- children: /* @__PURE__ */ b("div", {
128
+ children: /* @__PURE__ */ x("div", {
128
129
  className: "space-y-3",
129
130
  children: [
130
- h && /* @__PURE__ */ y(r, {
131
+ _ && /* @__PURE__ */ b(i, {
131
132
  tone: "danger",
132
- children: h
133
+ children: _
133
134
  }),
134
- /* @__PURE__ */ y(o, {
135
- label: "Name",
135
+ /* @__PURE__ */ b(s, {
136
+ label: c("psw.common.name", "Name"),
136
137
  required: !0,
137
- children: /* @__PURE__ */ y(p, {
138
- value: u.name,
139
- onChange: S("name"),
140
- placeholder: "Tax Advisory"
138
+ children: /* @__PURE__ */ b(m, {
139
+ value: f.name,
140
+ onChange: w("name"),
141
+ placeholder: c("psw.practiceAreas.namePlaceholder", "Tax Advisory")
141
142
  })
142
143
  }),
143
- /* @__PURE__ */ y(o, {
144
- label: "Code",
145
- children: /* @__PURE__ */ y(p, {
146
- value: u.code,
147
- onChange: S("code"),
144
+ /* @__PURE__ */ b(s, {
145
+ label: c("psw.practiceAreas.code", "Code"),
146
+ children: /* @__PURE__ */ b(m, {
147
+ value: f.code,
148
+ onChange: w("code"),
148
149
  placeholder: "TAX"
149
150
  })
150
151
  }),
151
- /* @__PURE__ */ y(o, {
152
- label: "Description",
153
- children: /* @__PURE__ */ y(f, {
154
- value: u.description,
155
- onChange: S("description")
152
+ /* @__PURE__ */ b(s, {
153
+ label: c("psw.common.description", "Description"),
154
+ children: /* @__PURE__ */ b(p, {
155
+ value: f.description,
156
+ onChange: w("description")
156
157
  })
157
158
  }),
158
- /* @__PURE__ */ b("label", {
159
+ /* @__PURE__ */ x("label", {
159
160
  className: "flex items-center gap-2 text-sm text-text-secondary",
160
- children: [/* @__PURE__ */ y("input", {
161
+ children: [/* @__PURE__ */ b("input", {
161
162
  type: "checkbox",
162
- checked: u.isActive,
163
- onChange: (e) => d((t) => ({
163
+ checked: f.isActive,
164
+ onChange: (e) => g((t) => ({
164
165
  ...t,
165
166
  isActive: e.target.checked
166
167
  }))
167
- }), "Active"]
168
+ }), c("psw.practiceAreas.active", "Active")]
168
169
  })
169
170
  ]
170
171
  })
171
172
  });
172
173
  };
173
174
  //#endregion
174
- export { S as PracticeAreasPage };
175
+ export { C as PracticeAreasPage };
175
176
 
176
177
  //# sourceMappingURL=PracticeAreasPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PracticeAreasPage.js","names":[],"sources":["../../../src/proserviceworld/pages/PracticeAreasPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, LayoutGrid, Pencil } from 'lucide-react';\nimport {\n usePracticeAreas,\n useCreatePracticeArea,\n useUpdatePracticeArea,\n type PswPracticeArea,\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 Banner,\n} from '../components/ui';\n\nexport const PracticeAreasPage: FC = () => {\n const { data, isLoading, error, refetch } = usePracticeAreas();\n const areas = data?.items ?? [];\n const [creating, setCreating] = useState(false);\n const [editing, setEditing] = useState<PswPracticeArea | null>(null);\n const [banner, setBanner] = useState<string | null>(null);\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Practice areas\"\n subtitle=\"The domains of service your firm offers — Tax, Audit, Litigation, Advisory — that engagements and matters classify against.\"\n icon={<LayoutGrid className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New area\n </Button>\n }\n />\n\n {banner && (\n <Banner tone=\"success\" onClose={() => setBanner(null)}>\n {banner}\n </Banner>\n )}\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : areas.length === 0 ? (\n <Empty\n title=\"No practice areas\"\n description=\"Define the service domains your firm offers.\"\n icon={<LayoutGrid className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New area\n </Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3\">\n {areas.map((p) => (\n <SectionCard key={p.id}>\n <div className=\"flex items-start justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"text-sm font-semibold text-text-primary\">{p.name}</h3>\n {p.code ? (\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-xs text-text-tertiary\">\n {p.code}\n </span>\n ) : null}\n </div>\n <StatusPill status={p.isActive ? 'ACTIVE' : 'INACTIVE'} className=\"mt-1.5\" />\n </div>\n <Button variant=\"ghost\" size=\"sm\" aria-label=\"Edit\" onClick={() => setEditing(p)}>\n <Pencil className=\"h-4 w-4\" />\n </Button>\n </div>\n {p.description ? (\n <p className=\"mt-2 text-sm text-text-secondary\">{p.description}</p>\n ) : null}\n </SectionCard>\n ))}\n </div>\n )}\n\n {creating && (\n <AreaModal\n onClose={() => setCreating(false)}\n onDone={() => {\n void refetch();\n setBanner('Practice area created.');\n }}\n />\n )}\n {editing && (\n <AreaModal\n area={editing}\n onClose={() => setEditing(null)}\n onDone={() => {\n void refetch();\n setBanner('Practice area updated.');\n }}\n />\n )}\n </div>\n );\n};\n\nconst AreaModal: FC<{ area?: PswPracticeArea; onClose: () => void; onDone: () => void }> = ({\n area,\n onClose,\n onDone,\n}) => {\n const create = useCreatePracticeArea();\n const update = useUpdatePracticeArea();\n const [form, setForm] = useState({\n name: area?.name ?? '',\n code: area?.code ?? '',\n description: area?.description ?? '',\n isActive: area?.isActive ?? true,\n });\n const [err, setErr] = useState<string | null>(null);\n const pending = create.isPending || update.isPending;\n const set = (k: 'name' | 'code' | 'description') => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n\n const submit = () => {\n setErr(null);\n if (!form.name.trim()) return setErr('Name is required.');\n const payload = {\n name: form.name.trim(),\n code: form.code.trim() || null,\n description: form.description.trim() || null,\n isActive: form.isActive,\n };\n const onError = (e: unknown) => setErr(e instanceof Error ? e.message : 'Failed.');\n if (area)\n update.mutate(\n { id: area.id, input: payload },\n {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError,\n }\n );\n else\n create.mutate(payload, {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError,\n });\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title={area ? 'Edit practice area' : 'New practice area'}\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={pending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={pending}>\n {pending ? 'Saving…' : area ? 'Save' : 'Create'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Name\" required>\n <TextInput value={form.name} onChange={set('name')} placeholder=\"Tax Advisory\" />\n </Field>\n <Field label=\"Code\">\n <TextInput value={form.code} onChange={set('code')} placeholder=\"TAX\" />\n </Field>\n <Field label=\"Description\">\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n <label className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.isActive}\n onChange={(e) => setForm((f) => ({ ...f, isActive: e.target.checked }))}\n />\n Active\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PracticeAreasPage.js","names":[],"sources":["../../../src/proserviceworld/pages/PracticeAreasPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, LayoutGrid, Pencil } from 'lucide-react';\nimport {\n usePracticeAreas,\n useCreatePracticeArea,\n useUpdatePracticeArea,\n type PswPracticeArea,\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 Banner,\n} from '../components/ui';\nimport { useTr } from '../hooks/useTr';\n\nexport const PracticeAreasPage: FC = () => {\n const tr = useTr();\n const { data, isLoading, error, refetch } = usePracticeAreas();\n const areas = data?.items ?? [];\n const [creating, setCreating] = useState(false);\n const [editing, setEditing] = useState<PswPracticeArea | null>(null);\n const [banner, setBanner] = useState<string | null>(null);\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={tr('psw.practiceAreas.title', 'Practice areas')}\n subtitle={tr(\n 'psw.practiceAreas.subtitle',\n 'The domains of service your firm offers — Tax, Audit, Litigation, Advisory — that engagements and matters classify against.'\n )}\n icon={<LayoutGrid 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.practiceAreas.new', 'New area')}\n </Button>\n }\n />\n\n {banner && (\n <Banner tone=\"success\" onClose={() => setBanner(null)}>\n {banner}\n </Banner>\n )}\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : areas.length === 0 ? (\n <Empty\n title={tr('psw.practiceAreas.emptyTitle', 'No practice areas')}\n description={tr(\n 'psw.practiceAreas.emptyDescription',\n 'Define the service domains your firm offers.'\n )}\n icon={<LayoutGrid 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.practiceAreas.new', 'New area')}\n </Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3\">\n {areas.map((p) => (\n <SectionCard key={p.id}>\n <div className=\"flex items-start justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"text-sm font-semibold text-text-primary\">{p.name}</h3>\n {p.code ? (\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-xs text-text-tertiary\">\n {p.code}\n </span>\n ) : null}\n </div>\n <StatusPill status={p.isActive ? 'ACTIVE' : 'INACTIVE'} className=\"mt-1.5\" />\n </div>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={tr('psw.common.edit', 'Edit')}\n onClick={() => setEditing(p)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n </div>\n {p.description ? (\n <p className=\"mt-2 text-sm text-text-secondary\">{p.description}</p>\n ) : null}\n </SectionCard>\n ))}\n </div>\n )}\n\n {creating && (\n <AreaModal\n onClose={() => setCreating(false)}\n onDone={() => {\n void refetch();\n setBanner(tr('psw.practiceAreas.created', 'Practice area created.'));\n }}\n />\n )}\n {editing && (\n <AreaModal\n area={editing}\n onClose={() => setEditing(null)}\n onDone={() => {\n void refetch();\n setBanner(tr('psw.practiceAreas.updated', 'Practice area updated.'));\n }}\n />\n )}\n </div>\n );\n};\n\nconst AreaModal: FC<{ area?: PswPracticeArea; onClose: () => void; onDone: () => void }> = ({\n area,\n onClose,\n onDone,\n}) => {\n const tr = useTr();\n const create = useCreatePracticeArea();\n const update = useUpdatePracticeArea();\n const [form, setForm] = useState({\n name: area?.name ?? '',\n code: area?.code ?? '',\n description: area?.description ?? '',\n isActive: area?.isActive ?? true,\n });\n const [err, setErr] = useState<string | null>(null);\n const pending = create.isPending || update.isPending;\n const set = (k: 'name' | 'code' | 'description') => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n\n const submit = () => {\n setErr(null);\n if (!form.name.trim()) return setErr(tr('psw.practiceAreas.nameRequired', 'Name is required.'));\n const payload = {\n name: form.name.trim(),\n code: form.code.trim() || null,\n description: form.description.trim() || null,\n isActive: form.isActive,\n };\n const onError = (e: unknown) =>\n setErr(e instanceof Error ? e.message : tr('psw.common.failed', 'Failed.'));\n if (area)\n update.mutate(\n { id: area.id, input: payload },\n {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError,\n }\n );\n else\n create.mutate(payload, {\n onSuccess: () => {\n onDone();\n onClose();\n },\n onError,\n });\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title={\n area\n ? tr('psw.practiceAreas.editTitle', 'Edit practice area')\n : tr('psw.practiceAreas.newTitle', 'New practice area')\n }\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={pending}>\n {tr('psw.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submit} disabled={pending}>\n {pending\n ? tr('psw.common.saving', 'Saving…')\n : area\n ? tr('psw.common.save', 'Save')\n : tr('psw.common.create', 'Create')}\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={set('name')}\n placeholder={tr('psw.practiceAreas.namePlaceholder', 'Tax Advisory')}\n />\n </Field>\n <Field label={tr('psw.practiceAreas.code', 'Code')}>\n <TextInput value={form.code} onChange={set('code')} placeholder=\"TAX\" />\n </Field>\n <Field label={tr('psw.common.description', 'Description')}>\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n <label className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.isActive}\n onChange={(e) => setForm((f) => ({ ...f, isActive: e.target.checked }))}\n />\n {tr('psw.practiceAreas.active', 'Active')}\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}