@burdenoff/microfe-proserviceworld 2026.709.2 → 2026.709.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/node_modules/clsx/dist/clsx.js +1 -1
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +130 -130
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
- package/dist/proserviceworld/ProServiceWorldRoot.js +4 -2
- package/dist/proserviceworld/ProServiceWorldRoot.js.map +1 -1
- package/dist/proserviceworld/ProServiceWorldRoutes.js.map +1 -1
- package/dist/proserviceworld/components/DiscussionThread.js.map +1 -1
- package/dist/proserviceworld/components/FeatureFlaggedPage.js.map +1 -1
- package/dist/proserviceworld/components/LoadMore.js.map +1 -1
- package/dist/proserviceworld/components/TagPicker.js.map +1 -1
- package/dist/proserviceworld/components/ui.js.map +1 -1
- package/dist/proserviceworld/hooks/useAnalytics.js.map +1 -1
- package/dist/proserviceworld/hooks/useEntityComments.js.map +1 -1
- package/dist/proserviceworld/hooks/useFiles.js.map +1 -1
- package/dist/proserviceworld/hooks/usePageViewAnalytics.js.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
- package/dist/proserviceworld/i18n/index.d.ts.map +1 -1
- package/dist/proserviceworld/i18n/index.js +30 -1
- package/dist/proserviceworld/i18n/index.js.map +1 -1
- package/dist/proserviceworld/index.js +5 -4
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/ClientsPage.js +1 -1
- package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
- package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -1
- package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/EngagementsPage.js +123 -122
- package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
- package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/MattersPage.js +124 -123
- package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -1
- package/dist/proserviceworld/pages/TimePage.js.map +1 -1
- package/dist/proserviceworld/providers/ProServiceWorldProvider.js.map +1 -1
- package/dist/proserviceworld/services/assistantApi.js.map +1 -1
- package/dist/proserviceworld/services/createSandboxAssistantTransport.js.map +1 -1
- package/dist/proserviceworld/utils/cn.js +1 -1
- package/dist/proserviceworld/utils/cn.js.map +1 -1
- package/dist/proserviceworld/utils/native.js.map +1 -1
- package/dist/proserviceworld/utils/nav.js.map +1 -1
- package/dist/proserviceworld/utils/navigation.js.map +1 -1
- package/dist/proserviceworld/utils/pageContext.js +14 -16
- package/dist/proserviceworld/utils/pageContext.js.map +1 -1
- 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":"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"}
|
|
@@ -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;
|
|
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;AAgEhC,eAAO,MAAM,WAAW,EAAE,EAgOzB,CAAC"}
|
|
@@ -1,67 +1,68 @@
|
|
|
1
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
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 {
|
|
4
|
-
import {
|
|
3
|
+
import { t as w } from "../i18n/index.js";
|
|
4
|
+
import { useAnalytics as T } from "../hooks/useAnalytics.js";
|
|
5
|
+
import { impactFeedback as ee } from "../utils/native.js";
|
|
5
6
|
import { TagPicker as E } from "../components/TagPicker.js";
|
|
6
|
-
import { LoadMore as
|
|
7
|
-
import { useMemo as
|
|
8
|
-
import { AlertTriangle as
|
|
9
|
-
import { Fragment as
|
|
10
|
-
import { Button as
|
|
7
|
+
import { LoadMore as D } from "../components/LoadMore.js";
|
|
8
|
+
import { useMemo as O, useState as k } from "react";
|
|
9
|
+
import { AlertTriangle as te, CheckCircle2 as A, CircleDot as j, FolderKanban as M, Lock as N, Plus as P, Search as F } from "lucide-react";
|
|
10
|
+
import { Fragment as I, jsx as L, jsxs as R } from "react/jsx-runtime";
|
|
11
|
+
import { Button as z } from "@burdenoff/fe-libs/ui";
|
|
11
12
|
//#region src/proserviceworld/pages/MattersPage.tsx
|
|
12
|
-
var
|
|
13
|
+
var B = [
|
|
13
14
|
"OPEN",
|
|
14
15
|
"ON_HOLD",
|
|
15
16
|
"CLOSED",
|
|
16
17
|
"ARCHIVED"
|
|
17
|
-
],
|
|
18
|
+
], V = [
|
|
18
19
|
"LOW",
|
|
19
20
|
"MEDIUM",
|
|
20
21
|
"HIGH",
|
|
21
22
|
"CRITICAL"
|
|
22
|
-
], ne = () => /* @__PURE__ */
|
|
23
|
+
], ne = () => /* @__PURE__ */ L("span", {
|
|
23
24
|
className: "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text",
|
|
24
25
|
title: "Privileged / confidential",
|
|
25
26
|
"aria-label": "Privileged",
|
|
26
|
-
children: /* @__PURE__ */
|
|
27
|
-
}),
|
|
28
|
-
let { emitIntent: e, emitFact: n } =
|
|
29
|
-
limit:
|
|
27
|
+
children: /* @__PURE__ */ L(N, { className: "h-3 w-3" })
|
|
28
|
+
}), H = 25, U = () => {
|
|
29
|
+
let { emitIntent: e, emitFact: n } = T(), [i, l] = k(""), [f, y] = k(""), [V, U] = k(!1), [W, G] = k(null), [ie, K] = k({
|
|
30
|
+
limit: H,
|
|
30
31
|
offset: 0
|
|
31
32
|
}), { data: q, isLoading: J, error: Y, refetch: X } = r({
|
|
32
33
|
search: i.trim() || void 0,
|
|
33
34
|
status: f || void 0,
|
|
34
|
-
pagination:
|
|
35
|
-
}), Z = t(),
|
|
36
|
-
return /* @__PURE__ */
|
|
35
|
+
pagination: ie
|
|
36
|
+
}), Z = t(), ae = a(), Q = O(() => q?.items ?? [], [q]), oe = Q.filter((e) => e.status === "OPEN").length, se = Q.filter((e) => e.isPrivileged).length, $ = Q.filter((e) => e.priority === "HIGH" || e.priority === "CRITICAL").length;
|
|
37
|
+
return /* @__PURE__ */ R("div", {
|
|
37
38
|
className: "space-y-6",
|
|
38
39
|
children: [
|
|
39
|
-
/* @__PURE__ */
|
|
40
|
-
title: "
|
|
41
|
-
subtitle: "
|
|
42
|
-
icon: /* @__PURE__ */
|
|
43
|
-
actions: /* @__PURE__ */
|
|
40
|
+
/* @__PURE__ */ L(m, {
|
|
41
|
+
title: w("psw.matters.title"),
|
|
42
|
+
subtitle: w("psw.matters.subtitle"),
|
|
43
|
+
icon: /* @__PURE__ */ L(M, { className: "h-6 w-6" }),
|
|
44
|
+
actions: /* @__PURE__ */ R(z, {
|
|
44
45
|
onClick: () => {
|
|
45
|
-
|
|
46
|
+
ee("light"), e("psw.matter.create_clicked"), U(!0);
|
|
46
47
|
},
|
|
47
|
-
children: [/* @__PURE__ */
|
|
48
|
+
children: [/* @__PURE__ */ L(P, { className: "mr-1.5 h-4 w-4" }), w("psw.matters.new")]
|
|
48
49
|
})
|
|
49
50
|
}),
|
|
50
|
-
|
|
51
|
-
tone:
|
|
52
|
-
onClose: () =>
|
|
53
|
-
children:
|
|
51
|
+
W && /* @__PURE__ */ L(o, {
|
|
52
|
+
tone: W.tone,
|
|
53
|
+
onClose: () => G(null),
|
|
54
|
+
children: W.text
|
|
54
55
|
}),
|
|
55
|
-
/* @__PURE__ */
|
|
56
|
+
/* @__PURE__ */ R("div", {
|
|
56
57
|
className: "flex flex-col gap-2 sm:flex-row sm:items-center",
|
|
57
|
-
children: [/* @__PURE__ */
|
|
58
|
+
children: [/* @__PURE__ */ R("div", {
|
|
58
59
|
className: "relative flex-1",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
60
|
-
placeholder: "
|
|
60
|
+
children: [/* @__PURE__ */ L(F, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ L(b, {
|
|
61
|
+
placeholder: w("psw.matters.searchPlaceholder"),
|
|
61
62
|
value: i,
|
|
62
63
|
onChange: (e) => {
|
|
63
64
|
l(e.target.value), K({
|
|
64
|
-
limit:
|
|
65
|
+
limit: H,
|
|
65
66
|
offset: 0
|
|
66
67
|
});
|
|
67
68
|
},
|
|
@@ -73,143 +74,143 @@ var z = [
|
|
|
73
74
|
},
|
|
74
75
|
className: "pl-9"
|
|
75
76
|
})]
|
|
76
|
-
}), /* @__PURE__ */
|
|
77
|
+
}), /* @__PURE__ */ R(p, {
|
|
77
78
|
value: f,
|
|
78
79
|
onChange: (e) => {
|
|
79
80
|
y(e.target.value), K({
|
|
80
|
-
limit:
|
|
81
|
+
limit: H,
|
|
81
82
|
offset: 0
|
|
82
83
|
});
|
|
83
84
|
},
|
|
84
85
|
className: "sm:w-48",
|
|
85
|
-
children: [/* @__PURE__ */
|
|
86
|
+
children: [/* @__PURE__ */ L("option", {
|
|
86
87
|
value: "",
|
|
87
|
-
children: "
|
|
88
|
-
}), S(
|
|
88
|
+
children: w("psw.matters.allStatuses")
|
|
89
|
+
}), S(B)]
|
|
89
90
|
})]
|
|
90
91
|
}),
|
|
91
|
-
J ? /* @__PURE__ */
|
|
92
|
+
J ? /* @__PURE__ */ L(u, {}) : Y ? /* @__PURE__ */ L(c, {
|
|
92
93
|
error: Y,
|
|
93
94
|
onRetry: () => void X()
|
|
94
|
-
}) : !q || q.items.length === 0 ? /* @__PURE__ */
|
|
95
|
-
title: "
|
|
96
|
-
description: "
|
|
97
|
-
icon: /* @__PURE__ */
|
|
98
|
-
action: /* @__PURE__ */
|
|
99
|
-
onClick: () =>
|
|
100
|
-
children: [/* @__PURE__ */
|
|
95
|
+
}) : !q || q.items.length === 0 ? /* @__PURE__ */ L(s, {
|
|
96
|
+
title: w("psw.matters.emptyTitle"),
|
|
97
|
+
description: w("psw.matters.emptyDescription"),
|
|
98
|
+
icon: /* @__PURE__ */ L(M, { className: "h-8 w-8" }),
|
|
99
|
+
action: /* @__PURE__ */ R(z, {
|
|
100
|
+
onClick: () => U(!0),
|
|
101
|
+
children: [/* @__PURE__ */ L(P, { className: "mr-1.5 h-4 w-4" }), w("psw.matters.new")]
|
|
101
102
|
})
|
|
102
|
-
}) : /* @__PURE__ */
|
|
103
|
+
}) : /* @__PURE__ */ R(I, { children: [/* @__PURE__ */ R("div", {
|
|
103
104
|
className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
|
|
104
105
|
children: [
|
|
105
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ L(d, {
|
|
106
107
|
label: "Matters",
|
|
107
108
|
value: q.totalCount,
|
|
108
|
-
icon: /* @__PURE__ */
|
|
109
|
+
icon: /* @__PURE__ */ L(M, { className: "h-4 w-4" })
|
|
109
110
|
}),
|
|
110
|
-
/* @__PURE__ */
|
|
111
|
+
/* @__PURE__ */ L(d, {
|
|
111
112
|
label: "Open",
|
|
112
|
-
value:
|
|
113
|
-
icon: /* @__PURE__ */
|
|
113
|
+
value: oe,
|
|
114
|
+
icon: /* @__PURE__ */ L(j, { className: "h-4 w-4" }),
|
|
114
115
|
tone: "accent"
|
|
115
116
|
}),
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ L(d, {
|
|
117
118
|
label: "Privileged",
|
|
118
|
-
value:
|
|
119
|
-
icon: /* @__PURE__ */
|
|
119
|
+
value: se,
|
|
120
|
+
icon: /* @__PURE__ */ L(N, { className: "h-4 w-4" }),
|
|
120
121
|
tone: "warning"
|
|
121
122
|
}),
|
|
122
|
-
/* @__PURE__ */
|
|
123
|
+
/* @__PURE__ */ L(d, {
|
|
123
124
|
label: "High priority",
|
|
124
125
|
value: $,
|
|
125
|
-
icon: /* @__PURE__ */
|
|
126
|
+
icon: /* @__PURE__ */ L(te, { className: "h-4 w-4" }),
|
|
126
127
|
tone: $ ? "danger" : "neutral"
|
|
127
128
|
})
|
|
128
129
|
]
|
|
129
|
-
}), /* @__PURE__ */
|
|
130
|
+
}), /* @__PURE__ */ R(h, {
|
|
130
131
|
title: `${q.totalCount} matter${q.totalCount === 1 ? "" : "s"}`,
|
|
131
|
-
children: [/* @__PURE__ */
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
-
/* @__PURE__ */
|
|
135
|
-
/* @__PURE__ */
|
|
136
|
-
/* @__PURE__ */
|
|
137
|
-
/* @__PURE__ */
|
|
138
|
-
/* @__PURE__ */
|
|
132
|
+
children: [/* @__PURE__ */ R(_, { children: [/* @__PURE__ */ L("thead", { children: /* @__PURE__ */ R("tr", { children: [
|
|
133
|
+
/* @__PURE__ */ L(x, { children: w("psw.matters.tableMatter") }),
|
|
134
|
+
/* @__PURE__ */ L(x, { children: w("psw.matters.tableClient") }),
|
|
135
|
+
/* @__PURE__ */ L(x, { children: w("psw.matters.tablePriority") }),
|
|
136
|
+
/* @__PURE__ */ L(x, { children: w("psw.matters.tableStatus") }),
|
|
137
|
+
/* @__PURE__ */ L(x, { children: w("psw.matters.tableDue") }),
|
|
138
|
+
/* @__PURE__ */ L(x, { children: w("psw.matters.tableTags") }),
|
|
139
|
+
/* @__PURE__ */ L(x, {
|
|
139
140
|
className: "text-right",
|
|
140
|
-
children: "
|
|
141
|
+
children: w("psw.common.actions")
|
|
141
142
|
})
|
|
142
|
-
] }) }), /* @__PURE__ */
|
|
143
|
+
] }) }), /* @__PURE__ */ L("tbody", { children: q.items.map((e) => /* @__PURE__ */ R("tr", {
|
|
143
144
|
className: "transition-colors hover:bg-bg-sunken/60",
|
|
144
145
|
children: [
|
|
145
|
-
/* @__PURE__ */
|
|
146
|
+
/* @__PURE__ */ R(v, { children: [/* @__PURE__ */ R("span", {
|
|
146
147
|
className: "flex items-center gap-2 font-medium text-text-primary",
|
|
147
|
-
children: [e.isPrivileged && /* @__PURE__ */
|
|
148
|
+
children: [e.isPrivileged && /* @__PURE__ */ L(ne, {}), /* @__PURE__ */ L("span", {
|
|
148
149
|
className: "truncate",
|
|
149
150
|
children: e.title
|
|
150
151
|
})]
|
|
151
|
-
}), e.reference ? /* @__PURE__ */
|
|
152
|
+
}), e.reference ? /* @__PURE__ */ R("div", {
|
|
152
153
|
className: "mt-0.5 pl-0 text-xs text-text-tertiary",
|
|
153
154
|
children: ["Ref: ", e.reference]
|
|
154
155
|
}) : null] }),
|
|
155
|
-
/* @__PURE__ */
|
|
156
|
+
/* @__PURE__ */ L(v, {
|
|
156
157
|
className: "text-text-primary",
|
|
157
158
|
children: e.client?.name ?? "—"
|
|
158
159
|
}),
|
|
159
|
-
/* @__PURE__ */
|
|
160
|
-
/* @__PURE__ */
|
|
161
|
-
/* @__PURE__ */
|
|
162
|
-
/* @__PURE__ */
|
|
160
|
+
/* @__PURE__ */ L(v, { children: /* @__PURE__ */ L(g, { status: e.priority }) }),
|
|
161
|
+
/* @__PURE__ */ L(v, { children: /* @__PURE__ */ L(g, { status: e.status }) }),
|
|
162
|
+
/* @__PURE__ */ L(v, { children: C(e.dueDate) }),
|
|
163
|
+
/* @__PURE__ */ L(v, { children: /* @__PURE__ */ L(E, {
|
|
163
164
|
entityType: "PswMatter",
|
|
164
165
|
entityId: e.id,
|
|
165
166
|
tags: e.tags ?? [],
|
|
166
167
|
onChange: async (t) => {
|
|
167
|
-
await
|
|
168
|
+
await ae.mutateAsync({
|
|
168
169
|
id: e.id,
|
|
169
170
|
input: { tags: t }
|
|
170
171
|
}), X();
|
|
171
172
|
},
|
|
172
173
|
maxTags: 5
|
|
173
174
|
}) }),
|
|
174
|
-
/* @__PURE__ */
|
|
175
|
+
/* @__PURE__ */ L(v, {
|
|
175
176
|
className: "text-right",
|
|
176
|
-
children: e.status !== "CLOSED" && e.status !== "ARCHIVED" ? /* @__PURE__ */
|
|
177
|
+
children: e.status !== "CLOSED" && e.status !== "ARCHIVED" ? /* @__PURE__ */ R(z, {
|
|
177
178
|
variant: "ghost",
|
|
178
179
|
size: "sm",
|
|
179
180
|
disabled: Z.isPending,
|
|
180
181
|
onClick: () => Z.mutate(e.id, {
|
|
181
182
|
onSuccess: () => {
|
|
182
|
-
n("psw.matter.closed", { matterId: e.id }),
|
|
183
|
+
n("psw.matter.closed", { matterId: e.id }), G({
|
|
183
184
|
tone: "success",
|
|
184
185
|
text: `${e.title} closed.`
|
|
185
186
|
});
|
|
186
187
|
},
|
|
187
|
-
onError: (e) =>
|
|
188
|
+
onError: (e) => G({
|
|
188
189
|
tone: "danger",
|
|
189
190
|
text: e instanceof Error ? e.message : "Failed."
|
|
190
191
|
})
|
|
191
192
|
}),
|
|
192
|
-
children: [/* @__PURE__ */
|
|
193
|
-
}) : /* @__PURE__ */
|
|
193
|
+
children: [/* @__PURE__ */ L(A, { className: "mr-1 h-4 w-4" }), " Close"]
|
|
194
|
+
}) : /* @__PURE__ */ L("span", {
|
|
194
195
|
className: "text-xs text-text-tertiary",
|
|
195
196
|
children: e.closedAt ? `Closed ${C(e.closedAt)}` : "—"
|
|
196
197
|
})
|
|
197
198
|
})
|
|
198
199
|
]
|
|
199
|
-
}, e.id)) })] }), /* @__PURE__ */
|
|
200
|
+
}, e.id)) })] }), /* @__PURE__ */ L(D, {
|
|
200
201
|
hasMore: q?.pageInfo?.hasMore ?? !1,
|
|
201
202
|
loading: J,
|
|
202
203
|
loadedCount: Q.length,
|
|
203
204
|
totalCount: q?.totalCount ?? Q.length,
|
|
204
205
|
onLoadMore: () => K((e) => ({
|
|
205
|
-
limit:
|
|
206
|
-
offset: e.offset +
|
|
206
|
+
limit: H,
|
|
207
|
+
offset: e.offset + H
|
|
207
208
|
}))
|
|
208
209
|
})]
|
|
209
210
|
})] }),
|
|
210
|
-
|
|
211
|
-
onClose: () =>
|
|
212
|
-
onSaved: (e) =>
|
|
211
|
+
V && /* @__PURE__ */ L(re, {
|
|
212
|
+
onClose: () => U(!1),
|
|
213
|
+
onSaved: (e) => G({
|
|
213
214
|
tone: "success",
|
|
214
215
|
text: `${e} opened.`
|
|
215
216
|
})
|
|
@@ -217,7 +218,7 @@ var z = [
|
|
|
217
218
|
]
|
|
218
219
|
});
|
|
219
220
|
}, re = ({ onClose: t, onSaved: r }) => {
|
|
220
|
-
let a = n(), { emitFact: s } =
|
|
221
|
+
let a = n(), { emitFact: s } = T(), c = e({ pagination: { limit: 100 } }), u = i(), [d, m] = k({
|
|
221
222
|
clientId: "",
|
|
222
223
|
practiceAreaId: "",
|
|
223
224
|
title: "",
|
|
@@ -226,20 +227,20 @@ var z = [
|
|
|
226
227
|
priority: "MEDIUM",
|
|
227
228
|
dueDate: "",
|
|
228
229
|
isPrivileged: !1
|
|
229
|
-
}), [h, g] =
|
|
230
|
+
}), [h, g] = k(null), _ = (e) => (t) => m((n) => ({
|
|
230
231
|
...n,
|
|
231
232
|
[e]: t.target.value
|
|
232
233
|
}));
|
|
233
|
-
return /* @__PURE__ */
|
|
234
|
+
return /* @__PURE__ */ L(f, {
|
|
234
235
|
open: !0,
|
|
235
236
|
onClose: t,
|
|
236
|
-
title: "
|
|
237
|
-
footer: /* @__PURE__ */
|
|
237
|
+
title: w("psw.matters.newTitle"),
|
|
238
|
+
footer: /* @__PURE__ */ R(I, { children: [/* @__PURE__ */ L(z, {
|
|
238
239
|
variant: "outline",
|
|
239
240
|
onClick: t,
|
|
240
241
|
disabled: a.isPending,
|
|
241
242
|
children: "Cancel"
|
|
242
|
-
}), /* @__PURE__ */
|
|
243
|
+
}), /* @__PURE__ */ L(z, {
|
|
243
244
|
onClick: () => {
|
|
244
245
|
if (g(null), !d.clientId) return g("Select a client.");
|
|
245
246
|
if (!d.title.trim()) return g("Matter title is required.");
|
|
@@ -266,98 +267,98 @@ var z = [
|
|
|
266
267
|
disabled: a.isPending,
|
|
267
268
|
children: a.isPending ? "Opening…" : "Open matter"
|
|
268
269
|
})] }),
|
|
269
|
-
children: /* @__PURE__ */
|
|
270
|
+
children: /* @__PURE__ */ R("div", {
|
|
270
271
|
className: "space-y-3",
|
|
271
272
|
children: [
|
|
272
|
-
h && /* @__PURE__ */
|
|
273
|
+
h && /* @__PURE__ */ L(o, {
|
|
273
274
|
tone: "danger",
|
|
274
275
|
children: h
|
|
275
276
|
}),
|
|
276
|
-
/* @__PURE__ */
|
|
277
|
+
/* @__PURE__ */ L(l, {
|
|
277
278
|
label: "Client",
|
|
278
279
|
required: !0,
|
|
279
|
-
children: /* @__PURE__ */
|
|
280
|
+
children: /* @__PURE__ */ R(p, {
|
|
280
281
|
value: d.clientId,
|
|
281
282
|
onChange: _("clientId"),
|
|
282
|
-
children: [/* @__PURE__ */
|
|
283
|
+
children: [/* @__PURE__ */ L("option", {
|
|
283
284
|
value: "",
|
|
284
285
|
children: "Select a client…"
|
|
285
|
-
}), c.data?.items.map((e) => /* @__PURE__ */
|
|
286
|
+
}), c.data?.items.map((e) => /* @__PURE__ */ L("option", {
|
|
286
287
|
value: e.id,
|
|
287
288
|
children: e.name
|
|
288
289
|
}, e.id))]
|
|
289
290
|
})
|
|
290
291
|
}),
|
|
291
|
-
/* @__PURE__ */
|
|
292
|
+
/* @__PURE__ */ L(l, {
|
|
292
293
|
label: "Title",
|
|
293
294
|
required: !0,
|
|
294
|
-
children: /* @__PURE__ */
|
|
295
|
+
children: /* @__PURE__ */ L(b, {
|
|
295
296
|
value: d.title,
|
|
296
297
|
onChange: _("title"),
|
|
297
298
|
placeholder: "Regulatory investigation — SEC inquiry"
|
|
298
299
|
})
|
|
299
300
|
}),
|
|
300
|
-
/* @__PURE__ */
|
|
301
|
+
/* @__PURE__ */ R("div", {
|
|
301
302
|
className: "grid grid-cols-2 gap-3",
|
|
302
|
-
children: [/* @__PURE__ */
|
|
303
|
+
children: [/* @__PURE__ */ L(l, {
|
|
303
304
|
label: "Reference",
|
|
304
|
-
children: /* @__PURE__ */
|
|
305
|
+
children: /* @__PURE__ */ L(b, {
|
|
305
306
|
value: d.reference,
|
|
306
307
|
onChange: _("reference"),
|
|
307
308
|
placeholder: "MAT-2026-014"
|
|
308
309
|
})
|
|
309
|
-
}), /* @__PURE__ */
|
|
310
|
+
}), /* @__PURE__ */ L(l, {
|
|
310
311
|
label: "Priority",
|
|
311
|
-
children: /* @__PURE__ */
|
|
312
|
+
children: /* @__PURE__ */ L(p, {
|
|
312
313
|
value: d.priority,
|
|
313
314
|
onChange: _("priority"),
|
|
314
|
-
children: S(
|
|
315
|
+
children: S(V)
|
|
315
316
|
})
|
|
316
317
|
})]
|
|
317
318
|
}),
|
|
318
|
-
/* @__PURE__ */
|
|
319
|
+
/* @__PURE__ */ R("div", {
|
|
319
320
|
className: "grid grid-cols-2 gap-3",
|
|
320
|
-
children: [/* @__PURE__ */
|
|
321
|
+
children: [/* @__PURE__ */ L(l, {
|
|
321
322
|
label: "Practice area",
|
|
322
|
-
children: /* @__PURE__ */
|
|
323
|
+
children: /* @__PURE__ */ R(p, {
|
|
323
324
|
value: d.practiceAreaId,
|
|
324
325
|
onChange: _("practiceAreaId"),
|
|
325
|
-
children: [/* @__PURE__ */
|
|
326
|
+
children: [/* @__PURE__ */ L("option", {
|
|
326
327
|
value: "",
|
|
327
328
|
children: "Unassigned"
|
|
328
|
-
}), u.data?.map((e) => /* @__PURE__ */
|
|
329
|
+
}), u.data?.map((e) => /* @__PURE__ */ L("option", {
|
|
329
330
|
value: e.id,
|
|
330
331
|
children: e.name
|
|
331
332
|
}, e.id))]
|
|
332
333
|
})
|
|
333
|
-
}), /* @__PURE__ */
|
|
334
|
+
}), /* @__PURE__ */ L(l, {
|
|
334
335
|
label: "Due date",
|
|
335
|
-
children: /* @__PURE__ */
|
|
336
|
+
children: /* @__PURE__ */ L(b, {
|
|
336
337
|
type: "date",
|
|
337
338
|
value: d.dueDate,
|
|
338
339
|
onChange: _("dueDate")
|
|
339
340
|
})
|
|
340
341
|
})]
|
|
341
342
|
}),
|
|
342
|
-
/* @__PURE__ */
|
|
343
|
+
/* @__PURE__ */ L(l, {
|
|
343
344
|
label: "Description",
|
|
344
|
-
children: /* @__PURE__ */
|
|
345
|
+
children: /* @__PURE__ */ L(y, {
|
|
345
346
|
value: d.description,
|
|
346
347
|
onChange: _("description")
|
|
347
348
|
})
|
|
348
349
|
}),
|
|
349
|
-
/* @__PURE__ */
|
|
350
|
+
/* @__PURE__ */ R("label", {
|
|
350
351
|
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",
|
|
351
|
-
children: [/* @__PURE__ */
|
|
352
|
+
children: [/* @__PURE__ */ L("input", {
|
|
352
353
|
type: "checkbox",
|
|
353
354
|
checked: d.isPrivileged,
|
|
354
355
|
onChange: (e) => m((t) => ({
|
|
355
356
|
...t,
|
|
356
357
|
isPrivileged: e.target.checked
|
|
357
358
|
}))
|
|
358
|
-
}), /* @__PURE__ */
|
|
359
|
+
}), /* @__PURE__ */ R("span", {
|
|
359
360
|
className: "flex items-center gap-1.5",
|
|
360
|
-
children: [/* @__PURE__ */
|
|
361
|
+
children: [/* @__PURE__ */ L(N, { className: "h-3.5 w-3.5 text-status-warning-text" }), "Privileged / confidential matter"]
|
|
361
362
|
})]
|
|
362
363
|
})
|
|
363
364
|
]
|
|
@@ -365,6 +366,6 @@ var z = [
|
|
|
365
366
|
});
|
|
366
367
|
};
|
|
367
368
|
//#endregion
|
|
368
|
-
export {
|
|
369
|
+
export { U as MattersPage };
|
|
369
370
|
|
|
370
371
|
//# sourceMappingURL=MattersPage.js.map
|