@burdenoff/microfe-proserviceworld 2026.709.1 → 2026.709.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/index.js +2 -1
  2. package/dist/node_modules/clsx/dist/clsx.js +1 -1
  3. package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
  4. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +130 -130
  5. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
  6. package/dist/proserviceworld/ProServiceWorldRoot.js +4 -2
  7. package/dist/proserviceworld/ProServiceWorldRoot.js.map +1 -1
  8. package/dist/proserviceworld/ProServiceWorldRoutes.d.ts.map +1 -1
  9. package/dist/proserviceworld/ProServiceWorldRoutes.js +95 -42
  10. package/dist/proserviceworld/ProServiceWorldRoutes.js.map +1 -1
  11. package/dist/proserviceworld/components/DiscussionThread.js.map +1 -1
  12. package/dist/proserviceworld/components/FeatureFlaggedPage.d.ts +8 -0
  13. package/dist/proserviceworld/components/FeatureFlaggedPage.d.ts.map +1 -0
  14. package/dist/proserviceworld/components/FeatureFlaggedPage.js +17 -0
  15. package/dist/proserviceworld/components/FeatureFlaggedPage.js.map +1 -0
  16. package/dist/proserviceworld/components/LoadMore.d.ts +12 -0
  17. package/dist/proserviceworld/components/LoadMore.d.ts.map +1 -0
  18. package/dist/proserviceworld/components/LoadMore.js +30 -0
  19. package/dist/proserviceworld/components/LoadMore.js.map +1 -0
  20. package/dist/proserviceworld/components/TagPicker.d.ts +11 -0
  21. package/dist/proserviceworld/components/TagPicker.d.ts.map +1 -0
  22. package/dist/proserviceworld/components/TagPicker.js +31 -0
  23. package/dist/proserviceworld/components/TagPicker.js.map +1 -0
  24. package/dist/proserviceworld/components/ui.js.map +1 -1
  25. package/dist/proserviceworld/hooks/useAnalytics.js.map +1 -1
  26. package/dist/proserviceworld/hooks/useEntityComments.js.map +1 -1
  27. package/dist/proserviceworld/hooks/useFiles.js.map +1 -1
  28. package/dist/proserviceworld/hooks/usePageViewAnalytics.d.ts +10 -0
  29. package/dist/proserviceworld/hooks/usePageViewAnalytics.d.ts.map +1 -0
  30. package/dist/proserviceworld/hooks/usePageViewAnalytics.js +24 -0
  31. package/dist/proserviceworld/hooks/usePageViewAnalytics.js.map +1 -0
  32. package/dist/proserviceworld/hooks/useProServiceWorldApi.js +47 -27
  33. package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
  34. package/dist/proserviceworld/i18n/index.d.ts +13 -0
  35. package/dist/proserviceworld/i18n/index.d.ts.map +1 -0
  36. package/dist/proserviceworld/i18n/index.js +171 -0
  37. package/dist/proserviceworld/i18n/index.js.map +1 -0
  38. package/dist/proserviceworld/index.d.ts +1 -0
  39. package/dist/proserviceworld/index.d.ts.map +1 -1
  40. package/dist/proserviceworld/index.js +5 -3
  41. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  42. package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
  43. package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -1
  44. package/dist/proserviceworld/pages/ClientsPage.js +173 -121
  45. package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
  46. package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
  47. package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -1
  48. package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
  49. package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
  50. package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
  51. package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -1
  52. package/dist/proserviceworld/pages/EngagementsPage.js +168 -120
  53. package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
  54. package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
  55. package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -1
  56. package/dist/proserviceworld/pages/MattersPage.js +183 -144
  57. package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
  58. package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -1
  59. package/dist/proserviceworld/pages/TimePage.js.map +1 -1
  60. package/dist/proserviceworld/providers/ProServiceWorldProvider.js.map +1 -1
  61. package/dist/proserviceworld/services/assistantApi.js.map +1 -1
  62. package/dist/proserviceworld/services/createSandboxAssistantTransport.js.map +1 -1
  63. package/dist/proserviceworld/utils/cn.js +1 -1
  64. package/dist/proserviceworld/utils/cn.js.map +1 -1
  65. package/dist/proserviceworld/utils/native.d.ts +23 -0
  66. package/dist/proserviceworld/utils/native.d.ts.map +1 -0
  67. package/dist/proserviceworld/utils/native.js +14 -0
  68. package/dist/proserviceworld/utils/native.js.map +1 -0
  69. package/dist/proserviceworld/utils/nav.js.map +1 -1
  70. package/dist/proserviceworld/utils/navigation.js.map +1 -1
  71. package/dist/proserviceworld/utils/pageContext.js +14 -16
  72. package/dist/proserviceworld/utils/pageContext.js.map +1 -1
  73. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"InvoicesPage.js","names":[],"sources":["../../../src/proserviceworld/pages/InvoicesPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Receipt, CheckCircle2, AlertCircle, Wallet } from 'lucide-react';\nimport {\n useInvoices,\n useCreateInvoice,\n useMarkInvoicePaid,\n useClients,\n useEngagements,\n type PswInvoiceStatus,\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 MetricCard,\n TableWrap,\n Th,\n Td,\n enumOptions,\n fmtDate,\n fmtMoney,\n} from '../components/ui';\nimport { cn } from '../utils/cn';\n\nconst STATUSES: PswInvoiceStatus[] = ['DRAFT', 'SENT', 'PAID', 'OVERDUE', 'CANCELLED'];\n\nexport const InvoicesPage: FC = () => {\n const [statusFilter, setStatusFilter] = useState<PswInvoiceStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const { data, isLoading, error, refetch } = useInvoices({ status: statusFilter || undefined });\n const markPaid = useMarkInvoicePaid();\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 const outstandingInvoices = (data?.items ?? []).filter(\n (i) => i.status === 'SENT' || i.status === 'OVERDUE'\n );\n const paidInvoices = (data?.items ?? []).filter((i) => i.status === 'PAID');\n const outstanding = outstandingInvoices.reduce((s, i) => s + i.total, 0);\n const collected = paidInvoices.reduce((s, i) => s + i.total, 0);\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Invoices\"\n subtitle=\"Assemble invoices from time, milestones and fixed-fee schedules — and track what's outstanding.\"\n icon={<Receipt className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New invoice\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=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <MetricCard\n label=\"Invoices\"\n value={data?.totalCount ?? 0}\n icon={<Receipt className=\"h-4 w-4\" />}\n />\n <MetricCard\n label=\"Outstanding\"\n value={fmtMoney(outstanding)}\n hint={`${outstandingInvoices.length} sent + overdue`}\n icon={<AlertCircle className=\"h-4 w-4\" />}\n tone=\"warning\"\n />\n <MetricCard\n label=\"Collected\"\n value={fmtMoney(collected)}\n hint={`${paidInvoices.length} paid`}\n icon={<Wallet className=\"h-4 w-4\" />}\n tone=\"success\"\n />\n </div>\n\n <div className=\"flex justify-end\">\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswInvoiceStatus | '')}\n className=\"sm:w-48\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title=\"No invoices yet\"\n description=\"Raise an invoice for a client to start tracking receivables.\"\n icon={<Receipt className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New invoice\n </Button>\n }\n />\n ) : (\n <SectionCard title=\"Invoices\">\n <TableWrap>\n <thead>\n <tr>\n <Th>Number</Th>\n <Th>Client</Th>\n <Th>Total</Th>\n <Th>Status</Th>\n <Th>Due</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((i) => (\n <tr key={i.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"font-medium text-text-primary\">{i.number}</span>\n </Td>\n <Td className=\"text-text-primary\">{clientName.get(i.clientId) ?? '—'}</Td>\n <Td className=\"whitespace-nowrap font-semibold text-text-primary\">\n {fmtMoney(i.total, i.currency)}\n </Td>\n <Td>\n <StatusPill status={i.status} />\n </Td>\n <Td\n className={cn(\n 'whitespace-nowrap',\n i.status === 'OVERDUE' && 'font-medium text-status-error-text'\n )}\n >\n {fmtDate(i.dueDate)}\n </Td>\n <Td className=\"text-right\">\n {i.status !== 'PAID' && i.status !== 'CANCELLED' && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={markPaid.isPending}\n onClick={() =>\n markPaid.mutate(i.id, {\n onSuccess: () =>\n setBanner({ tone: 'success', text: `${i.number} marked paid.` }),\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Failed.',\n }),\n })\n }\n >\n <CheckCircle2 className=\"mr-1 h-4 w-4\" />\n Mark paid\n </Button>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <InvoiceModal\n onClose={() => setCreating(false)}\n onSaved={(n) => setBanner({ tone: 'success', text: `${n} created.` })}\n />\n )}\n </div>\n );\n};\n\nconst InvoiceModal: FC<{ onClose: () => void; onSaved: (number: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const create = useCreateInvoice();\n const clients = useClients({ pagination: { limit: 100 } });\n const [form, setForm] = useState({\n clientId: '',\n engagementId: '',\n number: '',\n currency: 'USD',\n subtotal: '',\n taxAmount: '',\n issueDate: new Date().toISOString().slice(0, 10),\n dueDate: '',\n notes: '',\n });\n const [err, setErr] = useState<string | null>(null);\n const engagements = useEngagements({\n clientId: form.clientId || undefined,\n pagination: { limit: 100 },\n });\n const set = (k: keyof typeof form) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n const total = (Number(form.subtotal) || 0) + (Number(form.taxAmount) || 0);\n\n const submit = () => {\n setErr(null);\n if (!form.clientId) return setErr('Select a client.');\n if (!form.number.trim()) return setErr('Invoice number is required.');\n create.mutate(\n {\n clientId: form.clientId,\n engagementId: form.engagementId || null,\n number: form.number.trim(),\n currency: form.currency || 'USD',\n subtotal: Number(form.subtotal) || 0,\n taxAmount: Number(form.taxAmount) || 0,\n total,\n issueDate: form.issueDate ? new Date(form.issueDate).toISOString() : null,\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n notes: form.notes.trim() || null,\n },\n {\n onSuccess: () => {\n onSaved(form.number.trim());\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"New invoice\"\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 invoice'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Client\" required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\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=\"Number\" required>\n <TextInput value={form.number} onChange={set('number')} placeholder=\"INV-2026-014\" />\n </Field>\n </div>\n <Field label=\"Engagement (optional)\">\n <NativeSelect\n value={form.engagementId}\n onChange={set('engagementId')}\n disabled={!form.clientId}\n >\n <option value=\"\">None</option>\n {engagements.data?.items.map((e) => (\n <option key={e.id} value={e.id}>\n {e.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <div className=\"grid grid-cols-3 gap-3\">\n <Field label=\"Subtotal\">\n <TextInput type=\"number\" min=\"0\" value={form.subtotal} onChange={set('subtotal')} />\n </Field>\n <Field label=\"Tax\">\n <TextInput type=\"number\" min=\"0\" value={form.taxAmount} onChange={set('taxAmount')} />\n </Field>\n <Field label=\"Currency\">\n <TextInput value={form.currency} onChange={set('currency')} maxLength={3} />\n </Field>\n </div>\n <div className=\"rounded-lg bg-bg-sunken px-3 py-2 text-sm text-text-secondary\">\n Total:{' '}\n <span className=\"font-semibold text-text-primary\">{fmtMoney(total, form.currency)}</span>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Issue date\">\n <TextInput type=\"date\" value={form.issueDate} onChange={set('issueDate')} />\n </Field>\n <Field label=\"Due date\">\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n </div>\n <Field label=\"Notes\">\n <TextArea value={form.notes} onChange={set('notes')} />\n </Field>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"InvoicesPage.js","names":[],"sources":["../../../src/proserviceworld/pages/InvoicesPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Receipt, CheckCircle2, AlertCircle, Wallet } from 'lucide-react';\nimport {\n useInvoices,\n useCreateInvoice,\n useMarkInvoicePaid,\n useClients,\n useEngagements,\n type PswInvoiceStatus,\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 MetricCard,\n TableWrap,\n Th,\n Td,\n enumOptions,\n fmtDate,\n fmtMoney,\n} from '../components/ui';\nimport { cn } from '../utils/cn';\n\nconst STATUSES: PswInvoiceStatus[] = ['DRAFT', 'SENT', 'PAID', 'OVERDUE', 'CANCELLED'];\n\nexport const InvoicesPage: FC = () => {\n const [statusFilter, setStatusFilter] = useState<PswInvoiceStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const { data, isLoading, error, refetch } = useInvoices({ status: statusFilter || undefined });\n const markPaid = useMarkInvoicePaid();\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 const outstandingInvoices = (data?.items ?? []).filter(\n (i) => i.status === 'SENT' || i.status === 'OVERDUE'\n );\n const paidInvoices = (data?.items ?? []).filter((i) => i.status === 'PAID');\n const outstanding = outstandingInvoices.reduce((s, i) => s + i.total, 0);\n const collected = paidInvoices.reduce((s, i) => s + i.total, 0);\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Invoices\"\n subtitle=\"Assemble invoices from time, milestones and fixed-fee schedules — and track what's outstanding.\"\n icon={<Receipt className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New invoice\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=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <MetricCard\n label=\"Invoices\"\n value={data?.totalCount ?? 0}\n icon={<Receipt className=\"h-4 w-4\" />}\n />\n <MetricCard\n label=\"Outstanding\"\n value={fmtMoney(outstanding)}\n hint={`${outstandingInvoices.length} sent + overdue`}\n icon={<AlertCircle className=\"h-4 w-4\" />}\n tone=\"warning\"\n />\n <MetricCard\n label=\"Collected\"\n value={fmtMoney(collected)}\n hint={`${paidInvoices.length} paid`}\n icon={<Wallet className=\"h-4 w-4\" />}\n tone=\"success\"\n />\n </div>\n\n <div className=\"flex justify-end\">\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswInvoiceStatus | '')}\n className=\"sm:w-48\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title=\"No invoices yet\"\n description=\"Raise an invoice for a client to start tracking receivables.\"\n icon={<Receipt className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New invoice\n </Button>\n }\n />\n ) : (\n <SectionCard title=\"Invoices\">\n <TableWrap>\n <thead>\n <tr>\n <Th>Number</Th>\n <Th>Client</Th>\n <Th>Total</Th>\n <Th>Status</Th>\n <Th>Due</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((i) => (\n <tr key={i.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"font-medium text-text-primary\">{i.number}</span>\n </Td>\n <Td className=\"text-text-primary\">{clientName.get(i.clientId) ?? '—'}</Td>\n <Td className=\"whitespace-nowrap font-semibold text-text-primary\">\n {fmtMoney(i.total, i.currency)}\n </Td>\n <Td>\n <StatusPill status={i.status} />\n </Td>\n <Td\n className={cn(\n 'whitespace-nowrap',\n i.status === 'OVERDUE' && 'font-medium text-status-error-text'\n )}\n >\n {fmtDate(i.dueDate)}\n </Td>\n <Td className=\"text-right\">\n {i.status !== 'PAID' && i.status !== 'CANCELLED' && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={markPaid.isPending}\n onClick={() =>\n markPaid.mutate(i.id, {\n onSuccess: () =>\n setBanner({ tone: 'success', text: `${i.number} marked paid.` }),\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Failed.',\n }),\n })\n }\n >\n <CheckCircle2 className=\"mr-1 h-4 w-4\" />\n Mark paid\n </Button>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <InvoiceModal\n onClose={() => setCreating(false)}\n onSaved={(n) => setBanner({ tone: 'success', text: `${n} created.` })}\n />\n )}\n </div>\n );\n};\n\nconst InvoiceModal: FC<{ onClose: () => void; onSaved: (number: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const create = useCreateInvoice();\n const clients = useClients({ pagination: { limit: 100 } });\n const [form, setForm] = useState({\n clientId: '',\n engagementId: '',\n number: '',\n currency: 'USD',\n subtotal: '',\n taxAmount: '',\n issueDate: new Date().toISOString().slice(0, 10),\n dueDate: '',\n notes: '',\n });\n const [err, setErr] = useState<string | null>(null);\n const engagements = useEngagements({\n clientId: form.clientId || undefined,\n pagination: { limit: 100 },\n });\n const set = (k: keyof typeof form) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n const total = (Number(form.subtotal) || 0) + (Number(form.taxAmount) || 0);\n\n const submit = () => {\n setErr(null);\n if (!form.clientId) return setErr('Select a client.');\n if (!form.number.trim()) return setErr('Invoice number is required.');\n create.mutate(\n {\n clientId: form.clientId,\n engagementId: form.engagementId || null,\n number: form.number.trim(),\n currency: form.currency || 'USD',\n subtotal: Number(form.subtotal) || 0,\n taxAmount: Number(form.taxAmount) || 0,\n total,\n issueDate: form.issueDate ? new Date(form.issueDate).toISOString() : null,\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n notes: form.notes.trim() || null,\n },\n {\n onSuccess: () => {\n onSaved(form.number.trim());\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"New invoice\"\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 invoice'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Client\" required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\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=\"Number\" required>\n <TextInput value={form.number} onChange={set('number')} placeholder=\"INV-2026-014\" />\n </Field>\n </div>\n <Field label=\"Engagement (optional)\">\n <NativeSelect\n value={form.engagementId}\n onChange={set('engagementId')}\n disabled={!form.clientId}\n >\n <option value=\"\">None</option>\n {engagements.data?.items.map((e) => (\n <option key={e.id} value={e.id}>\n {e.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <div className=\"grid grid-cols-3 gap-3\">\n <Field label=\"Subtotal\">\n <TextInput type=\"number\" min=\"0\" value={form.subtotal} onChange={set('subtotal')} />\n </Field>\n <Field label=\"Tax\">\n <TextInput type=\"number\" min=\"0\" value={form.taxAmount} onChange={set('taxAmount')} />\n </Field>\n <Field label=\"Currency\">\n <TextInput value={form.currency} onChange={set('currency')} maxLength={3} />\n </Field>\n </div>\n <div className=\"rounded-lg bg-bg-sunken px-3 py-2 text-sm text-text-secondary\">\n Total:{' '}\n <span className=\"font-semibold text-text-primary\">{fmtMoney(total, form.currency)}</span>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Issue date\">\n <TextInput type=\"date\" value={form.issueDate} onChange={set('issueDate')} />\n </Field>\n <Field label=\"Due date\">\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n </div>\n <Field label=\"Notes\">\n <TextArea value={form.notes} onChange={set('notes')} />\n </Field>\n </div>\n </Modal>\n );\n};\n"],"mappings":";;;;;;;;AAmCA,IAAM,IAA+B;CAAC;CAAS;CAAQ;CAAQ;CAAW;AAAW,GAExE,UAAyB;CACpC,IAAM,CAAC,GAAc,KAAmB,EAAgC,EAAE,GACpE,CAAC,GAAU,KAAe,EAAS,EAAK,GACxC,CAAC,GAAQ,KAAa,EAA8D,IAAI,GACxF,EAAE,SAAM,cAAW,UAAO,eAAY,EAAY,EAAE,QAAQ,KAAgB,KAAA,EAAU,CAAC,GACvF,IAAW,EAAmB,GAC9B,IAAU,EAAW,EAAE,YAAY,EAAE,OAAO,IAAI,EAAE,CAAC,GACnD,IAAa,QACX,IAAI,KAAK,EAAQ,MAAM,SAAS,CAAC,EAAA,CAAG,KAAK,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,GACpE,CAAC,EAAQ,IAAI,CACf,GAEM,KAAuB,GAAM,SAAS,CAAC,EAAA,CAAG,QAC7C,MAAM,EAAE,WAAW,UAAU,EAAE,WAAW,SAC7C,GACM,KAAgB,GAAM,SAAS,CAAC,EAAA,CAAG,QAAQ,MAAM,EAAE,WAAW,MAAM,GACpE,IAAc,EAAoB,QAAQ,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC,GACjE,IAAY,EAAa,QAAQ,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC;CAE9D,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IACE,OAAM;IACN,UAAS;IACT,MAAM,kBAAC,GAAD,EAAS,WAAU,UAAW,CAAA;IACpC,SACE,kBAAC,GAAD;KAAQ,eAAe,EAAY,EAAI;eAAvC,CACE,kBAAC,GAAD,EAAM,WAAU,iBAAkB,CAAA,GAAC,aAE7B;;GAEX,CAAA;GAEA,KACC,kBAAC,GAAD;IAAQ,MAAM,EAAO;IAAM,eAAe,EAAU,IAAI;cACrD,EAAO;GACF,CAAA;GAGV,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,GAAM,cAAc;MAC3B,MAAM,kBAAC,GAAD,EAAS,WAAU,UAAW,CAAA;KACrC,CAAA;KACD,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EAAS,CAAW;MAC3B,MAAM,GAAG,EAAoB,OAAO;MACpC,MAAM,kBAAC,GAAD,EAAa,WAAU,UAAW,CAAA;MACxC,MAAK;KACN,CAAA;KACD,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EAAS,CAAS;MACzB,MAAM,GAAG,EAAa,OAAO;MAC7B,MAAM,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;MACnC,MAAK;KACN,CAAA;IACE;;GAEL,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KACE,OAAO;KACP,WAAW,MAAM,EAAgB,EAAE,OAAO,KAA8B;KACxE,WAAU;eAHZ,CAKE,kBAAC,UAAD;MAAQ,OAAM;gBAAG;KAAoB,CAAA,GACpC,EAAY,CAAQ,CACT;;GACX,CAAA;GAEJ,IACC,kBAAC,GAAD,CAAe,CAAA,IACb,IACF,kBAAC,GAAD;IAAmB;IAAO,eAAe,KAAK,EAAQ;GAAI,CAAA,IACxD,CAAC,KAAQ,EAAK,MAAM,WAAW,IACjC,kBAAC,GAAD;IACE,OAAM;IACN,aAAY;IACZ,MAAM,kBAAC,GAAD,EAAS,WAAU,UAAW,CAAA;IACpC,QACE,kBAAC,GAAD;KAAQ,eAAe,EAAY,EAAI;eAAvC,CACE,kBAAC,GAAD,EAAM,WAAU,iBAAkB,CAAA,GAAC,aAE7B;;GAEX,CAAA,IAED,kBAAC,GAAD;IAAa,OAAM;cACjB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD,EAAA,UAAA;KACE,kBAAC,GAAD,EAAA,UAAI,SAAU,CAAA;KACd,kBAAC,GAAD,EAAA,UAAI,SAAU,CAAA;KACd,kBAAC,GAAD,EAAA,UAAI,QAAS,CAAA;KACb,kBAAC,GAAD,EAAA,UAAI,SAAU,CAAA;KACd,kBAAC,GAAD,EAAA,UAAI,MAAO,CAAA;KACX,kBAAC,GAAD;MAAI,WAAU;gBAAa;KAAW,CAAA;IACpC,EAAA,CAAA,EACC,CAAA,GACP,kBAAC,SAAD,EAAA,UACG,EAAK,MAAM,KAAK,MACf,kBAAC,MAAD;KAAe,WAAU;eAAzB;MACE,kBAAC,GAAD,EAAA,UACE,kBAAC,QAAD;OAAM,WAAU;iBAAiC,EAAE;MAAa,CAAA,EAC9D,CAAA;MACJ,kBAAC,GAAD;OAAI,WAAU;iBAAqB,EAAW,IAAI,EAAE,QAAQ,KAAK;MAAQ,CAAA;MACzE,kBAAC,GAAD;OAAI,WAAU;iBACX,EAAS,EAAE,OAAO,EAAE,QAAQ;MAC3B,CAAA;MACJ,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAY,QAAQ,EAAE,OAAS,CAAA,EAC7B,CAAA;MACJ,kBAAC,GAAD;OACE,WAAW,EACT,qBACA,EAAE,WAAW,aAAa,oCAC5B;iBAEC,EAAQ,EAAE,OAAO;MAChB,CAAA;MACJ,kBAAC,GAAD;OAAI,WAAU;iBACX,EAAE,WAAW,UAAU,EAAE,WAAW,eACnC,kBAAC,GAAD;QACE,SAAQ;QACR,MAAK;QACL,UAAU,EAAS;QACnB,eACE,EAAS,OAAO,EAAE,IAAI;SACpB,iBACE,EAAU;UAAE,MAAM;UAAW,MAAM,GAAG,EAAE,OAAO;SAAe,CAAC;SACjE,UAAU,MACR,EAAU;UACR,MAAM;UACN,MAAM,aAAa,QAAQ,EAAE,UAAU;SACzC,CAAC;QACL,CAAC;kBAbL,CAgBE,kBAAC,GAAD,EAAc,WAAU,eAAgB,CAAA,GAAC,WAEnC;;MAER,CAAA;KACF;OA1CK,EAAE,EA0CP,CACL,EACI,CAAA,CACE,EAAA,CAAA;GACA,CAAA;GAGd,KACC,kBAAC,GAAD;IACE,eAAe,EAAY,EAAK;IAChC,UAAU,MAAM,EAAU;KAAE,MAAM;KAAW,MAAM,GAAG,EAAE;IAAW,CAAC;GACrE,CAAA;EAEA;;AAET,GAEM,KAAgF,EACpF,YACA,iBACI;CACJ,IAAM,IAAS,EAAiB,GAC1B,IAAU,EAAW,EAAE,YAAY,EAAE,OAAO,IAAI,EAAE,CAAC,GACnD,CAAC,GAAM,KAAW,EAAS;EAC/B,UAAU;EACV,cAAc;EACd,QAAQ;EACR,UAAU;EACV,UAAU;EACV,WAAW;EACX,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE;EAC/C,SAAS;EACT,OAAO;CACT,CAAC,GACK,CAAC,GAAK,KAAU,EAAwB,IAAI,GAC5C,IAAc,EAAe;EACjC,UAAU,EAAK,YAAY,KAAA;EAC3B,YAAY,EAAE,OAAO,IAAI;CAC3B,CAAC,GACK,KAAO,OAA0B,MACrC,GAAS,OAAO;EAAE,GAAG;GAAI,IAAI,EAAE,OAAO;CAAM,EAAE,GAC1C,KAAS,OAAO,EAAK,QAAQ,KAAK,MAAM,OAAO,EAAK,SAAS,KAAK;CA6BxE,OACE,kBAAC,GAAD;EACE,MAAA;EACS;EACT,OAAM;EACN,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;GAAQ,SAAQ;GAAU,SAAS;GAAS,UAAU,EAAO;aAAW;EAEhE,CAAA,GACR,kBAAC,GAAD;GAAQ,eArCK;IAEnB,IADA,EAAO,IAAI,GACP,CAAC,EAAK,UAAU,OAAO,EAAO,kBAAkB;IACpD,IAAI,CAAC,EAAK,OAAO,KAAK,GAAG,OAAO,EAAO,6BAA6B;IACpE,EAAO,OACL;KACE,UAAU,EAAK;KACf,cAAc,EAAK,gBAAgB;KACnC,QAAQ,EAAK,OAAO,KAAK;KACzB,UAAU,EAAK,YAAY;KAC3B,UAAU,OAAO,EAAK,QAAQ,KAAK;KACnC,WAAW,OAAO,EAAK,SAAS,KAAK;KACrC;KACA,WAAW,EAAK,YAAY,IAAI,KAAK,EAAK,SAAS,CAAC,CAAC,YAAY,IAAI;KACrE,SAAS,EAAK,UAAU,IAAI,KAAK,EAAK,OAAO,CAAC,CAAC,YAAY,IAAI;KAC/D,OAAO,EAAK,MAAM,KAAK,KAAK;IAC9B,GACA;KACE,iBAAiB;MAEf,AADA,EAAQ,EAAK,OAAO,KAAK,CAAC,GAC1B,EAAQ;KACV;KACA,UAAU,MAAM,EAAO,aAAa,QAAQ,EAAE,UAAU,SAAS;IACnE,CACF;GACF;GAYiC,UAAU,EAAO;aACvC,EAAO,YAAY,cAAc;EAC5B,CAAA,CACR,EAAA,CAAA;YAGJ,kBAAC,OAAD;GAAK,WAAU;aAAf;IACG,KAAO,kBAAC,GAAD;KAAQ,MAAK;eAAU;IAAY,CAAA;IAC3C,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAO,OAAM;MAAS,UAAA;gBACpB,kBAAC,GAAD;OAAc,OAAO,EAAK;OAAU,UAAU,EAAI,UAAU;iBAA5D,CACE,kBAAC,UAAD;QAAQ,OAAM;kBAAG;OAAe,CAAA,GAC/B,EAAQ,MAAM,MAAM,KAAK,MACxB,kBAAC,UAAD;QAAmB,OAAO,EAAE;kBACzB,EAAE;OACG,GAFK,EAAE,EAEP,CACT,CACW;;KACT,CAAA,GACP,kBAAC,GAAD;MAAO,OAAM;MAAS,UAAA;gBACpB,kBAAC,GAAD;OAAW,OAAO,EAAK;OAAQ,UAAU,EAAI,QAAQ;OAAG,aAAY;MAAgB,CAAA;KAC/E,CAAA,CACJ;;IACL,kBAAC,GAAD;KAAO,OAAM;eACX,kBAAC,GAAD;MACE,OAAO,EAAK;MACZ,UAAU,EAAI,cAAc;MAC5B,UAAU,CAAC,EAAK;gBAHlB,CAKE,kBAAC,UAAD;OAAQ,OAAM;iBAAG;MAAY,CAAA,GAC5B,EAAY,MAAM,MAAM,KAAK,MAC5B,kBAAC,UAAD;OAAmB,OAAO,EAAE;iBACzB,EAAE;MACG,GAFK,EAAE,EAEP,CACT,CACW;;IACT,CAAA;IACP,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OAAO,OAAM;iBACX,kBAAC,GAAD;QAAW,MAAK;QAAS,KAAI;QAAI,OAAO,EAAK;QAAU,UAAU,EAAI,UAAU;OAAI,CAAA;MAC9E,CAAA;MACP,kBAAC,GAAD;OAAO,OAAM;iBACX,kBAAC,GAAD;QAAW,MAAK;QAAS,KAAI;QAAI,OAAO,EAAK;QAAW,UAAU,EAAI,WAAW;OAAI,CAAA;MAChF,CAAA;MACP,kBAAC,GAAD;OAAO,OAAM;iBACX,kBAAC,GAAD;QAAW,OAAO,EAAK;QAAU,UAAU,EAAI,UAAU;QAAG,WAAW;OAAI,CAAA;MACtE,CAAA;KACJ;;IACL,kBAAC,OAAD;KAAK,WAAU;eAAf;MAA+E;MACtE;MACP,kBAAC,QAAD;OAAM,WAAU;iBAAmC,EAAS,GAAO,EAAK,QAAQ;MAAQ,CAAA;KACrF;;IACL,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAO,OAAM;gBACX,kBAAC,GAAD;OAAW,MAAK;OAAO,OAAO,EAAK;OAAW,UAAU,EAAI,WAAW;MAAI,CAAA;KACtE,CAAA,GACP,kBAAC,GAAD;MAAO,OAAM;gBACX,kBAAC,GAAD;OAAW,MAAK;OAAO,OAAO,EAAK;OAAS,UAAU,EAAI,SAAS;MAAI,CAAA;KAClE,CAAA,CACJ;;IACL,kBAAC,GAAD;KAAO,OAAM;eACX,kBAAC,GAAD;MAAU,OAAO,EAAK;MAAO,UAAU,EAAI,OAAO;KAAI,CAAA;IACjD,CAAA;GACJ;;CACA,CAAA;AAEX"}
@@ -1 +1 @@
1
- {"version":3,"file":"MattersPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/MattersPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAyDhC,eAAO,MAAM,WAAW,EAAE,EAgMzB,CAAC"}
1
+ {"version":3,"file":"MattersPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/MattersPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AA+DhC,eAAO,MAAM,WAAW,EAAE,EAgOzB,CAAC"}
@@ -1,58 +1,70 @@
1
- import { useClients as e, useCloseMatter as t, useCreateMatter as n, useMatters as r, usePracticeAreas as i } from "../hooks/useProServiceWorldApi.js";
2
- import { Banner as a, Empty as o, ErrorState as s, Field as c, LoadingBlock as l, MetricCard as u, Modal as d, NativeSelect as f, PageHeader as p, SectionCard as m, StatusPill as h, TableWrap as g, Td as _, TextArea as v, TextInput as y, Th as b, enumOptions as x, fmtDate as S } from "../components/ui.js";
3
- import { useAnalytics as C } from "../hooks/useAnalytics.js";
4
- import { useState as w } from "react";
5
- import { AlertTriangle as T, CheckCircle2 as E, CircleDot as D, FolderKanban as O, Lock as k, Plus as A, Search as j } from "lucide-react";
6
- import { Fragment as M, jsx as N, jsxs as P } from "react/jsx-runtime";
7
- import { Button as F } from "@burdenoff/fe-libs/ui";
1
+ import { useClients as e, useCloseMatter as t, useCreateMatter as n, useMatters as r, usePracticeAreas as i, useUpdateMatter as a } from "../hooks/useProServiceWorldApi.js";
2
+ import { Banner as o, Empty as s, ErrorState as c, Field as l, LoadingBlock as u, MetricCard 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, enumOptions as S, fmtDate as C } from "../components/ui.js";
3
+ import { useAnalytics as w } from "../hooks/useAnalytics.js";
4
+ import { impactFeedback as T } from "../utils/native.js";
5
+ import { TagPicker as E } from "../components/TagPicker.js";
6
+ import { LoadMore as ee } from "../components/LoadMore.js";
7
+ import { useMemo as te, useState as D } from "react";
8
+ import { AlertTriangle as O, CheckCircle2 as k, CircleDot as A, FolderKanban as j, Lock as M, Plus as N, Search as P } from "lucide-react";
9
+ import { Fragment as F, jsx as I, jsxs as L } from "react/jsx-runtime";
10
+ import { Button as R } from "@burdenoff/fe-libs/ui";
8
11
  //#region src/proserviceworld/pages/MattersPage.tsx
9
- var I = [
12
+ var z = [
10
13
  "OPEN",
11
14
  "ON_HOLD",
12
15
  "CLOSED",
13
16
  "ARCHIVED"
14
- ], L = [
17
+ ], B = [
15
18
  "LOW",
16
19
  "MEDIUM",
17
20
  "HIGH",
18
21
  "CRITICAL"
19
- ], R = () => /* @__PURE__ */ N("span", {
22
+ ], ne = () => /* @__PURE__ */ I("span", {
20
23
  className: "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text",
21
24
  title: "Privileged / confidential",
22
25
  "aria-label": "Privileged",
23
- children: /* @__PURE__ */ N(k, { className: "h-3 w-3" })
24
- }), z = () => {
25
- let { emitIntent: e, emitFact: n } = C(), [i, c] = w(""), [d, v] = w(""), [L, z] = w(!1), [V, H] = w(null), { data: U, isLoading: W, error: G, refetch: K } = r({
26
+ children: /* @__PURE__ */ I(M, { className: "h-3 w-3" })
27
+ }), V = 25, H = () => {
28
+ let { emitIntent: e, emitFact: n } = w(), [i, l] = D(""), [f, y] = D(""), [B, H] = D(!1), [U, W] = D(null), [G, K] = D({
29
+ limit: V,
30
+ offset: 0
31
+ }), { data: q, isLoading: J, error: Y, refetch: X } = r({
26
32
  search: i.trim() || void 0,
27
- status: d || void 0
28
- }), q = t(), J = U?.items ?? [], Y = J.filter((e) => e.status === "OPEN").length, X = J.filter((e) => e.isPrivileged).length, Z = J.filter((e) => e.priority === "HIGH" || e.priority === "CRITICAL").length;
29
- return /* @__PURE__ */ P("div", {
33
+ status: f || void 0,
34
+ pagination: G
35
+ }), Z = t(), ie = a(), Q = te(() => q?.items ?? [], [q]), ae = Q.filter((e) => e.status === "OPEN").length, oe = Q.filter((e) => e.isPrivileged).length, $ = Q.filter((e) => e.priority === "HIGH" || e.priority === "CRITICAL").length;
36
+ return /* @__PURE__ */ L("div", {
30
37
  className: "space-y-6",
31
38
  children: [
32
- /* @__PURE__ */ N(p, {
39
+ /* @__PURE__ */ I(m, {
33
40
  title: "Matters",
34
41
  subtitle: "The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.",
35
- icon: /* @__PURE__ */ N(O, { className: "h-6 w-6" }),
36
- actions: /* @__PURE__ */ P(F, {
42
+ icon: /* @__PURE__ */ I(j, { className: "h-6 w-6" }),
43
+ actions: /* @__PURE__ */ L(R, {
37
44
  onClick: () => {
38
- e("psw.matter.create_clicked"), z(!0);
45
+ T("light"), e("psw.matter.create_clicked"), H(!0);
39
46
  },
40
- children: [/* @__PURE__ */ N(A, { className: "mr-1.5 h-4 w-4" }), "New matter"]
47
+ children: [/* @__PURE__ */ I(N, { className: "mr-1.5 h-4 w-4" }), "New matter"]
41
48
  })
42
49
  }),
43
- V && /* @__PURE__ */ N(a, {
44
- tone: V.tone,
45
- onClose: () => H(null),
46
- children: V.text
50
+ U && /* @__PURE__ */ I(o, {
51
+ tone: U.tone,
52
+ onClose: () => W(null),
53
+ children: U.text
47
54
  }),
48
- /* @__PURE__ */ P("div", {
55
+ /* @__PURE__ */ L("div", {
49
56
  className: "flex flex-col gap-2 sm:flex-row sm:items-center",
50
- children: [/* @__PURE__ */ P("div", {
57
+ children: [/* @__PURE__ */ L("div", {
51
58
  className: "relative flex-1",
52
- children: [/* @__PURE__ */ N(j, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ N(y, {
59
+ children: [/* @__PURE__ */ I(P, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ I(b, {
53
60
  placeholder: "Search matters…",
54
61
  value: i,
55
- onChange: (e) => c(e.target.value),
62
+ onChange: (e) => {
63
+ l(e.target.value), K({
64
+ limit: V,
65
+ offset: 0
66
+ });
67
+ },
56
68
  onKeyDown: (e) => {
57
69
  e.key === "Enter" && i.trim() && n("psw.search.performed", {
58
70
  entityType: "matter",
@@ -61,124 +73,151 @@ var I = [
61
73
  },
62
74
  className: "pl-9"
63
75
  })]
64
- }), /* @__PURE__ */ P(f, {
65
- value: d,
66
- onChange: (e) => v(e.target.value),
76
+ }), /* @__PURE__ */ L(p, {
77
+ value: f,
78
+ onChange: (e) => {
79
+ y(e.target.value), K({
80
+ limit: V,
81
+ offset: 0
82
+ });
83
+ },
67
84
  className: "sm:w-48",
68
- children: [/* @__PURE__ */ N("option", {
85
+ children: [/* @__PURE__ */ I("option", {
69
86
  value: "",
70
87
  children: "All statuses"
71
- }), x(I)]
88
+ }), S(z)]
72
89
  })]
73
90
  }),
74
- W ? /* @__PURE__ */ N(l, {}) : G ? /* @__PURE__ */ N(s, {
75
- error: G,
76
- onRetry: () => void K()
77
- }) : !U || U.items.length === 0 ? /* @__PURE__ */ N(o, {
91
+ J ? /* @__PURE__ */ I(u, {}) : Y ? /* @__PURE__ */ I(c, {
92
+ error: Y,
93
+ onRetry: () => void X()
94
+ }) : !q || q.items.length === 0 ? /* @__PURE__ */ I(s, {
78
95
  title: "No matters yet",
79
96
  description: "Open a matter to track a regulated thread of work for a client.",
80
- icon: /* @__PURE__ */ N(O, { className: "h-8 w-8" }),
81
- action: /* @__PURE__ */ P(F, {
82
- onClick: () => z(!0),
83
- children: [/* @__PURE__ */ N(A, { className: "mr-1.5 h-4 w-4" }), "New matter"]
97
+ icon: /* @__PURE__ */ I(j, { className: "h-8 w-8" }),
98
+ action: /* @__PURE__ */ L(R, {
99
+ onClick: () => H(!0),
100
+ children: [/* @__PURE__ */ I(N, { className: "mr-1.5 h-4 w-4" }), "New matter"]
84
101
  })
85
- }) : /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ P("div", {
102
+ }) : /* @__PURE__ */ L(F, { children: [/* @__PURE__ */ L("div", {
86
103
  className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
87
104
  children: [
88
- /* @__PURE__ */ N(u, {
105
+ /* @__PURE__ */ I(d, {
89
106
  label: "Matters",
90
- value: U.totalCount,
91
- icon: /* @__PURE__ */ N(O, { className: "h-4 w-4" })
107
+ value: q.totalCount,
108
+ icon: /* @__PURE__ */ I(j, { className: "h-4 w-4" })
92
109
  }),
93
- /* @__PURE__ */ N(u, {
110
+ /* @__PURE__ */ I(d, {
94
111
  label: "Open",
95
- value: Y,
96
- icon: /* @__PURE__ */ N(D, { className: "h-4 w-4" }),
112
+ value: ae,
113
+ icon: /* @__PURE__ */ I(A, { className: "h-4 w-4" }),
97
114
  tone: "accent"
98
115
  }),
99
- /* @__PURE__ */ N(u, {
116
+ /* @__PURE__ */ I(d, {
100
117
  label: "Privileged",
101
- value: X,
102
- icon: /* @__PURE__ */ N(k, { className: "h-4 w-4" }),
118
+ value: oe,
119
+ icon: /* @__PURE__ */ I(M, { className: "h-4 w-4" }),
103
120
  tone: "warning"
104
121
  }),
105
- /* @__PURE__ */ N(u, {
122
+ /* @__PURE__ */ I(d, {
106
123
  label: "High priority",
107
- value: Z,
108
- icon: /* @__PURE__ */ N(T, { className: "h-4 w-4" }),
109
- tone: Z ? "danger" : "neutral"
124
+ value: $,
125
+ icon: /* @__PURE__ */ I(O, { className: "h-4 w-4" }),
126
+ tone: $ ? "danger" : "neutral"
110
127
  })
111
128
  ]
112
- }), /* @__PURE__ */ N(m, {
113
- title: `${U.totalCount} matter${U.totalCount === 1 ? "" : "s"}`,
114
- children: /* @__PURE__ */ P(g, { children: [/* @__PURE__ */ N("thead", { children: /* @__PURE__ */ P("tr", { children: [
115
- /* @__PURE__ */ N(b, { children: "Matter" }),
116
- /* @__PURE__ */ N(b, { children: "Client" }),
117
- /* @__PURE__ */ N(b, { children: "Priority" }),
118
- /* @__PURE__ */ N(b, { children: "Status" }),
119
- /* @__PURE__ */ N(b, { children: "Due" }),
120
- /* @__PURE__ */ N(b, {
129
+ }), /* @__PURE__ */ L(h, {
130
+ title: `${q.totalCount} matter${q.totalCount === 1 ? "" : "s"}`,
131
+ children: [/* @__PURE__ */ L(_, { children: [/* @__PURE__ */ I("thead", { children: /* @__PURE__ */ L("tr", { children: [
132
+ /* @__PURE__ */ I(x, { children: "Matter" }),
133
+ /* @__PURE__ */ I(x, { children: "Client" }),
134
+ /* @__PURE__ */ I(x, { children: "Priority" }),
135
+ /* @__PURE__ */ I(x, { children: "Status" }),
136
+ /* @__PURE__ */ I(x, { children: "Due" }),
137
+ /* @__PURE__ */ I(x, { children: "Tags" }),
138
+ /* @__PURE__ */ I(x, {
121
139
  className: "text-right",
122
140
  children: "Actions"
123
141
  })
124
- ] }) }), /* @__PURE__ */ N("tbody", { children: U.items.map((e) => /* @__PURE__ */ P("tr", {
142
+ ] }) }), /* @__PURE__ */ I("tbody", { children: q.items.map((e) => /* @__PURE__ */ L("tr", {
125
143
  className: "transition-colors hover:bg-bg-sunken/60",
126
144
  children: [
127
- /* @__PURE__ */ P(_, { children: [/* @__PURE__ */ P("span", {
145
+ /* @__PURE__ */ L(v, { children: [/* @__PURE__ */ L("span", {
128
146
  className: "flex items-center gap-2 font-medium text-text-primary",
129
- children: [e.isPrivileged && /* @__PURE__ */ N(R, {}), /* @__PURE__ */ N("span", {
147
+ children: [e.isPrivileged && /* @__PURE__ */ I(ne, {}), /* @__PURE__ */ I("span", {
130
148
  className: "truncate",
131
149
  children: e.title
132
150
  })]
133
- }), e.reference ? /* @__PURE__ */ P("div", {
151
+ }), e.reference ? /* @__PURE__ */ L("div", {
134
152
  className: "mt-0.5 pl-0 text-xs text-text-tertiary",
135
153
  children: ["Ref: ", e.reference]
136
154
  }) : null] }),
137
- /* @__PURE__ */ N(_, {
155
+ /* @__PURE__ */ I(v, {
138
156
  className: "text-text-primary",
139
157
  children: e.client?.name ?? "—"
140
158
  }),
141
- /* @__PURE__ */ N(_, { children: /* @__PURE__ */ N(h, { status: e.priority }) }),
142
- /* @__PURE__ */ N(_, { children: /* @__PURE__ */ N(h, { status: e.status }) }),
143
- /* @__PURE__ */ N(_, { children: S(e.dueDate) }),
144
- /* @__PURE__ */ N(_, {
159
+ /* @__PURE__ */ I(v, { children: /* @__PURE__ */ I(g, { status: e.priority }) }),
160
+ /* @__PURE__ */ I(v, { children: /* @__PURE__ */ I(g, { status: e.status }) }),
161
+ /* @__PURE__ */ I(v, { children: C(e.dueDate) }),
162
+ /* @__PURE__ */ I(v, { children: /* @__PURE__ */ I(E, {
163
+ entityType: "PswMatter",
164
+ entityId: e.id,
165
+ tags: e.tags ?? [],
166
+ onChange: async (t) => {
167
+ await ie.mutateAsync({
168
+ id: e.id,
169
+ input: { tags: t }
170
+ }), X();
171
+ },
172
+ maxTags: 5
173
+ }) }),
174
+ /* @__PURE__ */ I(v, {
145
175
  className: "text-right",
146
- children: e.status !== "CLOSED" && e.status !== "ARCHIVED" ? /* @__PURE__ */ P(F, {
176
+ children: e.status !== "CLOSED" && e.status !== "ARCHIVED" ? /* @__PURE__ */ L(R, {
147
177
  variant: "ghost",
148
178
  size: "sm",
149
- disabled: q.isPending,
150
- onClick: () => q.mutate(e.id, {
179
+ disabled: Z.isPending,
180
+ onClick: () => Z.mutate(e.id, {
151
181
  onSuccess: () => {
152
- n("psw.matter.closed", { matterId: e.id }), H({
182
+ n("psw.matter.closed", { matterId: e.id }), W({
153
183
  tone: "success",
154
184
  text: `${e.title} closed.`
155
185
  });
156
186
  },
157
- onError: (e) => H({
187
+ onError: (e) => W({
158
188
  tone: "danger",
159
189
  text: e instanceof Error ? e.message : "Failed."
160
190
  })
161
191
  }),
162
- children: [/* @__PURE__ */ N(E, { className: "mr-1 h-4 w-4" }), " Close"]
163
- }) : /* @__PURE__ */ N("span", {
192
+ children: [/* @__PURE__ */ I(k, { className: "mr-1 h-4 w-4" }), " Close"]
193
+ }) : /* @__PURE__ */ I("span", {
164
194
  className: "text-xs text-text-tertiary",
165
- children: e.closedAt ? `Closed ${S(e.closedAt)}` : "—"
195
+ children: e.closedAt ? `Closed ${C(e.closedAt)}` : "—"
166
196
  })
167
197
  })
168
198
  ]
169
- }, e.id)) })] })
199
+ }, e.id)) })] }), /* @__PURE__ */ I(ee, {
200
+ hasMore: q?.pageInfo?.hasMore ?? !1,
201
+ loading: J,
202
+ loadedCount: Q.length,
203
+ totalCount: q?.totalCount ?? Q.length,
204
+ onLoadMore: () => K((e) => ({
205
+ limit: V,
206
+ offset: e.offset + V
207
+ }))
208
+ })]
170
209
  })] }),
171
- L && /* @__PURE__ */ N(B, {
172
- onClose: () => z(!1),
173
- onSaved: (e) => H({
210
+ B && /* @__PURE__ */ I(re, {
211
+ onClose: () => H(!1),
212
+ onSaved: (e) => W({
174
213
  tone: "success",
175
214
  text: `${e} opened.`
176
215
  })
177
216
  })
178
217
  ]
179
218
  });
180
- }, B = ({ onClose: t, onSaved: r }) => {
181
- let o = n(), { emitFact: s } = C(), l = e({ pagination: { limit: 100 } }), u = i(), [p, m] = w({
219
+ }, re = ({ onClose: t, onSaved: r }) => {
220
+ let a = n(), { emitFact: s } = w(), c = e({ pagination: { limit: 100 } }), u = i(), [d, m] = D({
182
221
  clientId: "",
183
222
  practiceAreaId: "",
184
223
  title: "",
@@ -187,138 +226,138 @@ var I = [
187
226
  priority: "MEDIUM",
188
227
  dueDate: "",
189
228
  isPrivileged: !1
190
- }), [h, g] = w(null), _ = (e) => (t) => m((n) => ({
229
+ }), [h, g] = D(null), _ = (e) => (t) => m((n) => ({
191
230
  ...n,
192
231
  [e]: t.target.value
193
232
  }));
194
- return /* @__PURE__ */ N(d, {
233
+ return /* @__PURE__ */ I(f, {
195
234
  open: !0,
196
235
  onClose: t,
197
236
  title: "New matter",
198
- footer: /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ N(F, {
237
+ footer: /* @__PURE__ */ L(F, { children: [/* @__PURE__ */ I(R, {
199
238
  variant: "outline",
200
239
  onClick: t,
201
- disabled: o.isPending,
240
+ disabled: a.isPending,
202
241
  children: "Cancel"
203
- }), /* @__PURE__ */ N(F, {
242
+ }), /* @__PURE__ */ I(R, {
204
243
  onClick: () => {
205
- if (g(null), !p.clientId) return g("Select a client.");
206
- if (!p.title.trim()) return g("Matter title is required.");
207
- o.mutate({
208
- clientId: p.clientId,
209
- practiceAreaId: p.practiceAreaId || null,
210
- title: p.title.trim(),
211
- reference: p.reference.trim() || null,
212
- description: p.description.trim() || null,
213
- priority: p.priority,
214
- isPrivileged: p.isPrivileged,
215
- dueDate: p.dueDate ? new Date(p.dueDate).toISOString() : null
244
+ if (g(null), !d.clientId) return g("Select a client.");
245
+ if (!d.title.trim()) return g("Matter title is required.");
246
+ a.mutate({
247
+ clientId: d.clientId,
248
+ practiceAreaId: d.practiceAreaId || null,
249
+ title: d.title.trim(),
250
+ reference: d.reference.trim() || null,
251
+ description: d.description.trim() || null,
252
+ priority: d.priority,
253
+ isPrivileged: d.isPrivileged,
254
+ dueDate: d.dueDate ? new Date(d.dueDate).toISOString() : null
216
255
  }, {
217
256
  onSuccess: (e) => {
218
257
  let n = e.pswCreateMatter;
219
258
  s("psw.matter.created", {
220
259
  matterId: n.id,
221
- clientId: p.clientId
222
- }), r(p.title.trim()), t();
260
+ clientId: d.clientId
261
+ }), r(d.title.trim()), t();
223
262
  },
224
263
  onError: (e) => g(e instanceof Error ? e.message : "Failed.")
225
264
  });
226
265
  },
227
- disabled: o.isPending,
228
- children: o.isPending ? "Opening…" : "Open matter"
266
+ disabled: a.isPending,
267
+ children: a.isPending ? "Opening…" : "Open matter"
229
268
  })] }),
230
- children: /* @__PURE__ */ P("div", {
269
+ children: /* @__PURE__ */ L("div", {
231
270
  className: "space-y-3",
232
271
  children: [
233
- h && /* @__PURE__ */ N(a, {
272
+ h && /* @__PURE__ */ I(o, {
234
273
  tone: "danger",
235
274
  children: h
236
275
  }),
237
- /* @__PURE__ */ N(c, {
276
+ /* @__PURE__ */ I(l, {
238
277
  label: "Client",
239
278
  required: !0,
240
- children: /* @__PURE__ */ P(f, {
241
- value: p.clientId,
279
+ children: /* @__PURE__ */ L(p, {
280
+ value: d.clientId,
242
281
  onChange: _("clientId"),
243
- children: [/* @__PURE__ */ N("option", {
282
+ children: [/* @__PURE__ */ I("option", {
244
283
  value: "",
245
284
  children: "Select a client…"
246
- }), l.data?.items.map((e) => /* @__PURE__ */ N("option", {
285
+ }), c.data?.items.map((e) => /* @__PURE__ */ I("option", {
247
286
  value: e.id,
248
287
  children: e.name
249
288
  }, e.id))]
250
289
  })
251
290
  }),
252
- /* @__PURE__ */ N(c, {
291
+ /* @__PURE__ */ I(l, {
253
292
  label: "Title",
254
293
  required: !0,
255
- children: /* @__PURE__ */ N(y, {
256
- value: p.title,
294
+ children: /* @__PURE__ */ I(b, {
295
+ value: d.title,
257
296
  onChange: _("title"),
258
297
  placeholder: "Regulatory investigation — SEC inquiry"
259
298
  })
260
299
  }),
261
- /* @__PURE__ */ P("div", {
300
+ /* @__PURE__ */ L("div", {
262
301
  className: "grid grid-cols-2 gap-3",
263
- children: [/* @__PURE__ */ N(c, {
302
+ children: [/* @__PURE__ */ I(l, {
264
303
  label: "Reference",
265
- children: /* @__PURE__ */ N(y, {
266
- value: p.reference,
304
+ children: /* @__PURE__ */ I(b, {
305
+ value: d.reference,
267
306
  onChange: _("reference"),
268
307
  placeholder: "MAT-2026-014"
269
308
  })
270
- }), /* @__PURE__ */ N(c, {
309
+ }), /* @__PURE__ */ I(l, {
271
310
  label: "Priority",
272
- children: /* @__PURE__ */ N(f, {
273
- value: p.priority,
311
+ children: /* @__PURE__ */ I(p, {
312
+ value: d.priority,
274
313
  onChange: _("priority"),
275
- children: x(L)
314
+ children: S(B)
276
315
  })
277
316
  })]
278
317
  }),
279
- /* @__PURE__ */ P("div", {
318
+ /* @__PURE__ */ L("div", {
280
319
  className: "grid grid-cols-2 gap-3",
281
- children: [/* @__PURE__ */ N(c, {
320
+ children: [/* @__PURE__ */ I(l, {
282
321
  label: "Practice area",
283
- children: /* @__PURE__ */ P(f, {
284
- value: p.practiceAreaId,
322
+ children: /* @__PURE__ */ L(p, {
323
+ value: d.practiceAreaId,
285
324
  onChange: _("practiceAreaId"),
286
- children: [/* @__PURE__ */ N("option", {
325
+ children: [/* @__PURE__ */ I("option", {
287
326
  value: "",
288
327
  children: "Unassigned"
289
- }), u.data?.map((e) => /* @__PURE__ */ N("option", {
328
+ }), u.data?.map((e) => /* @__PURE__ */ I("option", {
290
329
  value: e.id,
291
330
  children: e.name
292
331
  }, e.id))]
293
332
  })
294
- }), /* @__PURE__ */ N(c, {
333
+ }), /* @__PURE__ */ I(l, {
295
334
  label: "Due date",
296
- children: /* @__PURE__ */ N(y, {
335
+ children: /* @__PURE__ */ I(b, {
297
336
  type: "date",
298
- value: p.dueDate,
337
+ value: d.dueDate,
299
338
  onChange: _("dueDate")
300
339
  })
301
340
  })]
302
341
  }),
303
- /* @__PURE__ */ N(c, {
342
+ /* @__PURE__ */ I(l, {
304
343
  label: "Description",
305
- children: /* @__PURE__ */ N(v, {
306
- value: p.description,
344
+ children: /* @__PURE__ */ I(y, {
345
+ value: d.description,
307
346
  onChange: _("description")
308
347
  })
309
348
  }),
310
- /* @__PURE__ */ P("label", {
349
+ /* @__PURE__ */ L("label", {
311
350
  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",
312
- children: [/* @__PURE__ */ N("input", {
351
+ children: [/* @__PURE__ */ I("input", {
313
352
  type: "checkbox",
314
- checked: p.isPrivileged,
353
+ checked: d.isPrivileged,
315
354
  onChange: (e) => m((t) => ({
316
355
  ...t,
317
356
  isPrivileged: e.target.checked
318
357
  }))
319
- }), /* @__PURE__ */ P("span", {
358
+ }), /* @__PURE__ */ L("span", {
320
359
  className: "flex items-center gap-1.5",
321
- children: [/* @__PURE__ */ N(k, { className: "h-3.5 w-3.5 text-status-warning-text" }), "Privileged / confidential matter"]
360
+ children: [/* @__PURE__ */ I(M, { className: "h-3.5 w-3.5 text-status-warning-text" }), "Privileged / confidential matter"]
322
361
  })]
323
362
  })
324
363
  ]
@@ -326,6 +365,6 @@ var I = [
326
365
  });
327
366
  };
328
367
  //#endregion
329
- export { z as MattersPage };
368
+ export { H as MattersPage };
330
369
 
331
370
  //# sourceMappingURL=MattersPage.js.map