@burdenoff/microfe-proserviceworld 2026.706.3 → 2026.709.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +18199 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +43046 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -1
- package/dist/proserviceworld/ProServiceWorldRoot.d.ts +5 -0
- package/dist/proserviceworld/ProServiceWorldRoot.d.ts.map +1 -0
- package/dist/proserviceworld/ProServiceWorldRoutes.d.ts +2 -0
- package/dist/proserviceworld/ProServiceWorldRoutes.d.ts.map +1 -0
- package/dist/proserviceworld/components/DiscussionThread.d.ts +12 -0
- package/dist/proserviceworld/components/DiscussionThread.d.ts.map +1 -0
- package/dist/proserviceworld/components/ui.d.ts +82 -0
- package/dist/proserviceworld/components/ui.d.ts.map +1 -0
- package/dist/proserviceworld/hooks/useAnalytics.d.ts +18 -0
- package/dist/proserviceworld/hooks/useAnalytics.d.ts.map +1 -0
- package/dist/proserviceworld/hooks/useAnalytics.js +21 -0
- package/dist/proserviceworld/hooks/useAnalytics.js.map +1 -0
- package/dist/proserviceworld/hooks/useEntityComments.d.ts +27 -0
- package/dist/proserviceworld/hooks/useEntityComments.d.ts.map +1 -0
- package/dist/proserviceworld/hooks/useFiles.d.ts +23 -0
- package/dist/proserviceworld/hooks/useFiles.d.ts.map +1 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +351 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -0
- package/dist/proserviceworld/index.d.ts +5 -0
- package/dist/proserviceworld/index.d.ts.map +1 -0
- package/dist/proserviceworld/index.js +1 -0
- package/dist/proserviceworld/pages/AnalyticsPage.d.ts +4 -0
- package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/ClientDetailPage.d.ts +4 -0
- package/dist/proserviceworld/pages/ClientDetailPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/ClientsPage.d.ts +9 -0
- package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/ClientsPage.js +157 -146
- package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.d.ts +4 -0
- package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/ConflictsPage.d.ts +4 -0
- package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/DashboardPage.d.ts +4 -0
- package/dist/proserviceworld/pages/DashboardPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/DocumentsPage.d.ts +4 -0
- package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/EngagementDetailPage.d.ts +4 -0
- package/dist/proserviceworld/pages/EngagementDetailPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/EngagementDetailPage.js +162 -156
- package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementsPage.d.ts +4 -0
- package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/EngagementsPage.js +141 -128
- package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.d.ts +4 -0
- package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/MattersPage.d.ts +4 -0
- package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/MattersPage.js +165 -150
- package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.d.ts +4 -0
- package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/TimePage.d.ts +4 -0
- package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -0
- package/dist/proserviceworld/providers/ProServiceWorldProvider.d.ts +6 -0
- package/dist/proserviceworld/providers/ProServiceWorldProvider.d.ts.map +1 -0
- package/dist/proserviceworld/services/assistantApi.d.ts +74 -0
- package/dist/proserviceworld/services/assistantApi.d.ts.map +1 -0
- package/dist/proserviceworld/services/assistantApi.js +203 -0
- package/dist/proserviceworld/services/assistantApi.js.map +1 -0
- package/dist/proserviceworld/services/createSandboxAssistantTransport.d.ts +28 -0
- package/dist/proserviceworld/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/proserviceworld/services/createSandboxAssistantTransport.js +120 -0
- package/dist/proserviceworld/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/proserviceworld/types/index.d.ts +57 -0
- package/dist/proserviceworld/types/index.d.ts.map +1 -0
- package/dist/proserviceworld/utils/cn.d.ts +4 -0
- package/dist/proserviceworld/utils/cn.d.ts.map +1 -0
- package/dist/proserviceworld/utils/nav.d.ts +6 -0
- package/dist/proserviceworld/utils/nav.d.ts.map +1 -0
- package/dist/proserviceworld/utils/navigation.d.ts +2 -0
- package/dist/proserviceworld/utils/navigation.d.ts.map +1 -0
- package/dist/proserviceworld/utils/pageContext.d.ts +12 -0
- package/dist/proserviceworld/utils/pageContext.d.ts.map +1 -0
- package/dist/proserviceworld/utils/pageContext.js +74 -0
- package/dist/proserviceworld/utils/pageContext.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EngagementsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/EngagementsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, Briefcase, ChevronRight } from 'lucide-react';\nimport {\n useEngagements,\n useCreateEngagement,\n useClients,\n usePracticeAreas,\n type PswEngagementStatus,\n} from '../hooks/useProServiceWorldApi';\nimport { useNav } from '../utils/nav';\nimport {\n PageHeader,\n SectionCard,\n LoadingBlock,\n ErrorState,\n Empty,\n StatusPill,\n Modal,\n Field,\n TextInput,\n TextArea,\n NativeSelect,\n Banner,\n TableWrap,\n Th,\n Td,\n enumOptions,\n fmtMoney,\n fmtDate,\n humanize,\n} from '../components/ui';\n\nconst STATUSES: PswEngagementStatus[] = [\n 'PROPOSAL',\n 'ACCEPTED',\n 'IN_PROGRESS',\n 'REVIEW',\n 'DELIVERED',\n 'INVOICED',\n 'CLOSED',\n 'CANCELLED',\n];\nconst FEE_ARRANGEMENTS = ['FIXED', 'HOURLY', 'RETAINER', 'VALUE_BASED'] as const;\n\nconst initials = (name: string): string =>\n name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((w) => w[0]?.toUpperCase() ?? '')\n .join('') || '?';\n\nconst ClientAvatar: FC<{ name: string }> = ({ name }) => (\n <span\n className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-accent/10 text-[10px] font-semibold text-accent ring-1 ring-inset ring-accent/15\"\n aria-hidden\n >\n {initials(name)}\n </span>\n);\n\nexport const EngagementsPage: FC = () => {\n const nav = useNav();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswEngagementStatus | ''>('');\n const [clientFilter, setClientFilter] = useState('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<string | null>(null);\n const clients = useClients({ pagination: { limit: 100 } });\n const { data, isLoading, error, refetch } = useEngagements({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n clientId: clientFilter || undefined,\n });\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Engagements\"\n subtitle=\"The commercial containers of contracted work — scope, fee arrangement, delivery lifecycle, and billing.\"\n icon={<Briefcase className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New engagement\n </Button>\n }\n />\n\n {banner && (\n <Banner tone=\"success\" onClose={() => setBanner(null)}>\n {banner}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder=\"Search engagements…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswEngagementStatus | '')}\n className=\"sm:w-44\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n <NativeSelect\n value={clientFilter}\n onChange={(e) => setClientFilter(e.target.value)}\n className=\"sm:w-48\"\n >\n <option value=\"\">All clients</option>\n {clients.data?.items.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\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 engagements yet\"\n description=\"Scope your first engagement against a client to begin delivery and billing.\"\n icon={<Briefcase className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New engagement\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${data.totalCount} engagement${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Engagement</Th>\n <Th>Client</Th>\n <Th>Fee</Th>\n <Th>Status</Th>\n <Th>Started</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((e) => (\n <tr\n key={e.id}\n className=\"group cursor-pointer transition-colors hover:bg-bg-sunken/60\"\n onClick={() => nav(`engagements/${e.id}`)}\n >\n <Td>\n <div className=\"flex items-center gap-1 font-medium text-text-primary transition-colors group-hover:text-accent\">\n <span>{e.name}</span>\n <ChevronRight className=\"h-3.5 w-3.5 shrink-0 text-text-tertiary opacity-0 transition-opacity group-hover:opacity-100\" />\n </div>\n {e.description ? (\n <div className=\"mt-0.5 max-w-md truncate text-xs text-text-tertiary\">\n {e.description}\n </div>\n ) : null}\n </Td>\n <Td>\n <span className=\"inline-flex items-center gap-2.5\">\n <ClientAvatar name={e.client?.name ?? '—'} />\n <span className=\"text-text-secondary\">{e.client?.name ?? '—'}</span>\n </span>\n </Td>\n <Td className=\"whitespace-nowrap\">\n <span className=\"font-medium text-text-primary\">\n {fmtMoney(e.feeAmount, e.currency)}\n </span>{' '}\n <span className=\"text-xs text-text-tertiary\">\n / {humanize(e.feeArrangement)}\n </span>\n </Td>\n <Td>\n <StatusPill status={e.status} />\n </Td>\n <Td className=\"whitespace-nowrap\">{fmtDate(e.startDate)}</Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <EngagementModal\n onClose={() => setCreating(false)}\n onSaved={(name) => setBanner(`${name} created.`)}\n />\n )}\n </div>\n );\n};\n\nconst EngagementModal: FC<{ onClose: () => void; onSaved: (name: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const create = useCreateEngagement();\n const clients = useClients({ pagination: { limit: 100 } });\n const practiceAreas = usePracticeAreas();\n const [form, setForm] = useState({\n clientId: '',\n practiceAreaId: '',\n name: '',\n description: '',\n feeArrangement: 'FIXED',\n feeAmount: '',\n currency: 'USD',\n startDate: '',\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('Select a client.');\n if (!form.name.trim()) return setErr('Engagement name is required.');\n create.mutate(\n {\n clientId: form.clientId,\n practiceAreaId: form.practiceAreaId || null,\n name: form.name.trim(),\n description: form.description.trim() || null,\n feeArrangement: form.feeArrangement,\n feeAmount: form.feeAmount ? Number(form.feeAmount) : 0,\n currency: form.currency || 'USD',\n startDate: form.startDate ? new Date(form.startDate).toISOString() : null,\n },\n {\n onSuccess: () => {\n onSaved(form.name.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 engagement\"\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 engagement'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Client\" required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\n <option value=\"\">Select a client…</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=\"Name\" required>\n <TextInput value={form.name} onChange={set('name')} placeholder=\"FY26 Statutory Audit\" />\n </Field>\n <Field label=\"Practice area\">\n <NativeSelect value={form.practiceAreaId} onChange={set('practiceAreaId')}>\n <option value=\"\">Unassigned</option>\n {practiceAreas.data?.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <div className=\"grid grid-cols-3 gap-3\">\n <Field label=\"Fee type\">\n <NativeSelect value={form.feeArrangement} onChange={set('feeArrangement')}>\n {enumOptions(FEE_ARRANGEMENTS)}\n </NativeSelect>\n </Field>\n <Field label=\"Fee amount\">\n <TextInput\n type=\"number\"\n min=\"0\"\n value={form.feeAmount}\n onChange={set('feeAmount')}\n placeholder=\"50000\"\n />\n </Field>\n <Field label=\"Currency\">\n <TextInput value={form.currency} onChange={set('currency')} maxLength={3} />\n </Field>\n </div>\n <Field label=\"Start date\">\n <TextInput type=\"date\" value={form.startDate} onChange={set('startDate')} />\n </Field>\n <Field label=\"Description\">\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EngagementsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/EngagementsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, Briefcase, ChevronRight } from 'lucide-react';\nimport {\n useEngagements,\n useCreateEngagement,\n useClients,\n usePracticeAreas,\n type PswEngagementStatus,\n type PswEngagement,\n} from '../hooks/useProServiceWorldApi';\nimport { useNav } from '../utils/nav';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport {\n PageHeader,\n SectionCard,\n LoadingBlock,\n ErrorState,\n Empty,\n StatusPill,\n Modal,\n Field,\n TextInput,\n TextArea,\n NativeSelect,\n Banner,\n TableWrap,\n Th,\n Td,\n enumOptions,\n fmtMoney,\n fmtDate,\n humanize,\n} from '../components/ui';\n\nconst STATUSES: PswEngagementStatus[] = [\n 'PROPOSAL',\n 'ACCEPTED',\n 'IN_PROGRESS',\n 'REVIEW',\n 'DELIVERED',\n 'INVOICED',\n 'CLOSED',\n 'CANCELLED',\n];\nconst FEE_ARRANGEMENTS = ['FIXED', 'HOURLY', 'RETAINER', 'VALUE_BASED'] as const;\n\nconst initials = (name: string): string =>\n name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((w) => w[0]?.toUpperCase() ?? '')\n .join('') || '?';\n\nconst ClientAvatar: FC<{ name: string }> = ({ name }) => (\n <span\n className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-accent/10 text-[10px] font-semibold text-accent ring-1 ring-inset ring-accent/15\"\n aria-hidden\n >\n {initials(name)}\n </span>\n);\n\nexport const EngagementsPage: FC = () => {\n const nav = useNav();\n const { emitIntent, emitFact } = useAnalytics();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswEngagementStatus | ''>('');\n const [clientFilter, setClientFilter] = useState('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<string | null>(null);\n const clients = useClients({ pagination: { limit: 100 } });\n const { data, isLoading, error, refetch } = useEngagements({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n clientId: clientFilter || undefined,\n });\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Engagements\"\n subtitle=\"The commercial containers of contracted work — scope, fee arrangement, delivery lifecycle, and billing.\"\n icon={<Briefcase className=\"h-6 w-6\" />}\n actions={\n <Button\n onClick={() => {\n emitIntent('psw.engagement.create_clicked');\n setCreating(true);\n }}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New engagement\n </Button>\n }\n />\n\n {banner && (\n <Banner tone=\"success\" onClose={() => setBanner(null)}>\n {banner}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder=\"Search engagements…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && search.trim()) {\n emitFact('psw.search.performed', {\n entityType: 'engagement',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswEngagementStatus | '')}\n className=\"sm:w-44\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n <NativeSelect\n value={clientFilter}\n onChange={(e) => setClientFilter(e.target.value)}\n className=\"sm:w-48\"\n >\n <option value=\"\">All clients</option>\n {clients.data?.items.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\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 engagements yet\"\n description=\"Scope your first engagement against a client to begin delivery and billing.\"\n icon={<Briefcase className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New engagement\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${data.totalCount} engagement${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Engagement</Th>\n <Th>Client</Th>\n <Th>Fee</Th>\n <Th>Status</Th>\n <Th>Started</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((e) => (\n <tr\n key={e.id}\n className=\"group cursor-pointer transition-colors hover:bg-bg-sunken/60\"\n onClick={() => nav(`engagements/${e.id}`)}\n >\n <Td>\n <div className=\"flex items-center gap-1 font-medium text-text-primary transition-colors group-hover:text-accent\">\n <span>{e.name}</span>\n <ChevronRight className=\"h-3.5 w-3.5 shrink-0 text-text-tertiary opacity-0 transition-opacity group-hover:opacity-100\" />\n </div>\n {e.description ? (\n <div className=\"mt-0.5 max-w-md truncate text-xs text-text-tertiary\">\n {e.description}\n </div>\n ) : null}\n </Td>\n <Td>\n <span className=\"inline-flex items-center gap-2.5\">\n <ClientAvatar name={e.client?.name ?? '—'} />\n <span className=\"text-text-secondary\">{e.client?.name ?? '—'}</span>\n </span>\n </Td>\n <Td className=\"whitespace-nowrap\">\n <span className=\"font-medium text-text-primary\">\n {fmtMoney(e.feeAmount, e.currency)}\n </span>{' '}\n <span className=\"text-xs text-text-tertiary\">\n / {humanize(e.feeArrangement)}\n </span>\n </Td>\n <Td>\n <StatusPill status={e.status} />\n </Td>\n <Td className=\"whitespace-nowrap\">{fmtDate(e.startDate)}</Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n )}\n\n {creating && (\n <EngagementModal\n onClose={() => setCreating(false)}\n onSaved={(name) => setBanner(`${name} created.`)}\n />\n )}\n </div>\n );\n};\n\nconst EngagementModal: FC<{ onClose: () => void; onSaved: (name: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const create = useCreateEngagement();\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 name: '',\n description: '',\n feeArrangement: 'FIXED',\n feeAmount: '',\n currency: 'USD',\n startDate: '',\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('Select a client.');\n if (!form.name.trim()) return setErr('Engagement name is required.');\n create.mutate(\n {\n clientId: form.clientId,\n practiceAreaId: form.practiceAreaId || null,\n name: form.name.trim(),\n description: form.description.trim() || null,\n feeArrangement: form.feeArrangement,\n feeAmount: form.feeAmount ? Number(form.feeAmount) : 0,\n currency: form.currency || 'USD',\n startDate: form.startDate ? new Date(form.startDate).toISOString() : null,\n },\n {\n onSuccess: (created) => {\n const engagement = (created as { pswCreateEngagement: PswEngagement })\n .pswCreateEngagement;\n emitFact('psw.engagement.created', {\n engagementId: engagement.id,\n clientId: form.clientId,\n });\n onSaved(form.name.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 engagement\"\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 engagement'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Client\" required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\n <option value=\"\">Select a client…</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=\"Name\" required>\n <TextInput value={form.name} onChange={set('name')} placeholder=\"FY26 Statutory Audit\" />\n </Field>\n <Field label=\"Practice area\">\n <NativeSelect value={form.practiceAreaId} onChange={set('practiceAreaId')}>\n <option value=\"\">Unassigned</option>\n {practiceAreas.data?.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <div className=\"grid grid-cols-3 gap-3\">\n <Field label=\"Fee type\">\n <NativeSelect value={form.feeArrangement} onChange={set('feeArrangement')}>\n {enumOptions(FEE_ARRANGEMENTS)}\n </NativeSelect>\n </Field>\n <Field label=\"Fee amount\">\n <TextInput\n type=\"number\"\n min=\"0\"\n value={form.feeAmount}\n onChange={set('feeAmount')}\n placeholder=\"50000\"\n />\n </Field>\n <Field label=\"Currency\">\n <TextInput value={form.currency} onChange={set('currency')} maxLength={3} />\n </Field>\n </div>\n <Field label=\"Start date\">\n <TextInput type=\"date\" value={form.startDate} onChange={set('startDate')} />\n </Field>\n <Field label=\"Description\">\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvoicesPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/InvoicesPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAqChC,eAAO,MAAM,YAAY,EAAE,EAgK1B,CAAC"}
|
|
@@ -0,0 +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,155 +1,166 @@
|
|
|
1
1
|
import { useClients as e, useCloseMatter as t, useCreateMatter as n, useMatters as r, usePracticeAreas as i } from "../hooks/useProServiceWorldApi.js";
|
|
2
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 {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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";
|
|
7
8
|
//#region src/proserviceworld/pages/MattersPage.tsx
|
|
8
|
-
var
|
|
9
|
+
var I = [
|
|
9
10
|
"OPEN",
|
|
10
11
|
"ON_HOLD",
|
|
11
12
|
"CLOSED",
|
|
12
13
|
"ARCHIVED"
|
|
13
|
-
],
|
|
14
|
+
], L = [
|
|
14
15
|
"LOW",
|
|
15
16
|
"MEDIUM",
|
|
16
17
|
"HIGH",
|
|
17
18
|
"CRITICAL"
|
|
18
|
-
],
|
|
19
|
+
], R = () => /* @__PURE__ */ N("span", {
|
|
19
20
|
className: "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text",
|
|
20
21
|
title: "Privileged / confidential",
|
|
21
22
|
"aria-label": "Privileged",
|
|
22
|
-
children: /* @__PURE__ */
|
|
23
|
-
}),
|
|
24
|
-
let
|
|
25
|
-
search:
|
|
26
|
-
status:
|
|
27
|
-
}),
|
|
28
|
-
return /* @__PURE__ */
|
|
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
|
+
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", {
|
|
29
30
|
className: "space-y-6",
|
|
30
31
|
children: [
|
|
31
|
-
/* @__PURE__ */
|
|
32
|
+
/* @__PURE__ */ N(p, {
|
|
32
33
|
title: "Matters",
|
|
33
34
|
subtitle: "The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.",
|
|
34
|
-
icon: /* @__PURE__ */
|
|
35
|
-
actions: /* @__PURE__ */
|
|
36
|
-
onClick: () =>
|
|
37
|
-
|
|
35
|
+
icon: /* @__PURE__ */ N(O, { className: "h-6 w-6" }),
|
|
36
|
+
actions: /* @__PURE__ */ P(F, {
|
|
37
|
+
onClick: () => {
|
|
38
|
+
e("psw.matter.create_clicked"), z(!0);
|
|
39
|
+
},
|
|
40
|
+
children: [/* @__PURE__ */ N(A, { className: "mr-1.5 h-4 w-4" }), "New matter"]
|
|
38
41
|
})
|
|
39
42
|
}),
|
|
40
|
-
|
|
41
|
-
tone:
|
|
42
|
-
onClose: () =>
|
|
43
|
-
children:
|
|
43
|
+
V && /* @__PURE__ */ N(a, {
|
|
44
|
+
tone: V.tone,
|
|
45
|
+
onClose: () => H(null),
|
|
46
|
+
children: V.text
|
|
44
47
|
}),
|
|
45
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ P("div", {
|
|
46
49
|
className: "flex flex-col gap-2 sm:flex-row sm:items-center",
|
|
47
|
-
children: [/* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ P("div", {
|
|
48
51
|
className: "relative flex-1",
|
|
49
|
-
children: [/* @__PURE__ */
|
|
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, {
|
|
50
53
|
placeholder: "Search matters…",
|
|
51
|
-
value:
|
|
52
|
-
onChange: (e) =>
|
|
54
|
+
value: i,
|
|
55
|
+
onChange: (e) => c(e.target.value),
|
|
56
|
+
onKeyDown: (e) => {
|
|
57
|
+
e.key === "Enter" && i.trim() && n("psw.search.performed", {
|
|
58
|
+
entityType: "matter",
|
|
59
|
+
queryLength: i.trim().length
|
|
60
|
+
});
|
|
61
|
+
},
|
|
53
62
|
className: "pl-9"
|
|
54
63
|
})]
|
|
55
|
-
}), /* @__PURE__ */
|
|
56
|
-
value:
|
|
57
|
-
onChange: (e) =>
|
|
64
|
+
}), /* @__PURE__ */ P(f, {
|
|
65
|
+
value: d,
|
|
66
|
+
onChange: (e) => v(e.target.value),
|
|
58
67
|
className: "sm:w-48",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
68
|
+
children: [/* @__PURE__ */ N("option", {
|
|
60
69
|
value: "",
|
|
61
70
|
children: "All statuses"
|
|
62
|
-
}), x(
|
|
71
|
+
}), x(I)]
|
|
63
72
|
})]
|
|
64
73
|
}),
|
|
65
|
-
|
|
66
|
-
error:
|
|
67
|
-
onRetry: () => void
|
|
68
|
-
}) : !
|
|
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, {
|
|
69
78
|
title: "No matters yet",
|
|
70
79
|
description: "Open a matter to track a regulated thread of work for a client.",
|
|
71
|
-
icon: /* @__PURE__ */
|
|
72
|
-
action: /* @__PURE__ */
|
|
73
|
-
onClick: () =>
|
|
74
|
-
children: [/* @__PURE__ */
|
|
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"]
|
|
75
84
|
})
|
|
76
|
-
}) : /* @__PURE__ */
|
|
85
|
+
}) : /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ P("div", {
|
|
77
86
|
className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
|
|
78
87
|
children: [
|
|
79
|
-
/* @__PURE__ */
|
|
88
|
+
/* @__PURE__ */ N(u, {
|
|
80
89
|
label: "Matters",
|
|
81
|
-
value:
|
|
82
|
-
icon: /* @__PURE__ */
|
|
90
|
+
value: U.totalCount,
|
|
91
|
+
icon: /* @__PURE__ */ N(O, { className: "h-4 w-4" })
|
|
83
92
|
}),
|
|
84
|
-
/* @__PURE__ */
|
|
93
|
+
/* @__PURE__ */ N(u, {
|
|
85
94
|
label: "Open",
|
|
86
|
-
value:
|
|
87
|
-
icon: /* @__PURE__ */
|
|
95
|
+
value: Y,
|
|
96
|
+
icon: /* @__PURE__ */ N(D, { className: "h-4 w-4" }),
|
|
88
97
|
tone: "accent"
|
|
89
98
|
}),
|
|
90
|
-
/* @__PURE__ */
|
|
99
|
+
/* @__PURE__ */ N(u, {
|
|
91
100
|
label: "Privileged",
|
|
92
|
-
value:
|
|
93
|
-
icon: /* @__PURE__ */
|
|
101
|
+
value: X,
|
|
102
|
+
icon: /* @__PURE__ */ N(k, { className: "h-4 w-4" }),
|
|
94
103
|
tone: "warning"
|
|
95
104
|
}),
|
|
96
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ N(u, {
|
|
97
106
|
label: "High priority",
|
|
98
|
-
value:
|
|
99
|
-
icon: /* @__PURE__ */
|
|
100
|
-
tone:
|
|
107
|
+
value: Z,
|
|
108
|
+
icon: /* @__PURE__ */ N(T, { className: "h-4 w-4" }),
|
|
109
|
+
tone: Z ? "danger" : "neutral"
|
|
101
110
|
})
|
|
102
111
|
]
|
|
103
|
-
}), /* @__PURE__ */
|
|
104
|
-
title: `${
|
|
105
|
-
children: /* @__PURE__ */
|
|
106
|
-
/* @__PURE__ */
|
|
107
|
-
/* @__PURE__ */
|
|
108
|
-
/* @__PURE__ */
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
-
/* @__PURE__ */
|
|
111
|
-
/* @__PURE__ */
|
|
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, {
|
|
112
121
|
className: "text-right",
|
|
113
122
|
children: "Actions"
|
|
114
123
|
})
|
|
115
|
-
] }) }), /* @__PURE__ */
|
|
124
|
+
] }) }), /* @__PURE__ */ N("tbody", { children: U.items.map((e) => /* @__PURE__ */ P("tr", {
|
|
116
125
|
className: "transition-colors hover:bg-bg-sunken/60",
|
|
117
126
|
children: [
|
|
118
|
-
/* @__PURE__ */
|
|
127
|
+
/* @__PURE__ */ P(_, { children: [/* @__PURE__ */ P("span", {
|
|
119
128
|
className: "flex items-center gap-2 font-medium text-text-primary",
|
|
120
|
-
children: [e.isPrivileged && /* @__PURE__ */
|
|
129
|
+
children: [e.isPrivileged && /* @__PURE__ */ N(R, {}), /* @__PURE__ */ N("span", {
|
|
121
130
|
className: "truncate",
|
|
122
131
|
children: e.title
|
|
123
132
|
})]
|
|
124
|
-
}), e.reference ? /* @__PURE__ */
|
|
133
|
+
}), e.reference ? /* @__PURE__ */ P("div", {
|
|
125
134
|
className: "mt-0.5 pl-0 text-xs text-text-tertiary",
|
|
126
135
|
children: ["Ref: ", e.reference]
|
|
127
136
|
}) : null] }),
|
|
128
|
-
/* @__PURE__ */
|
|
137
|
+
/* @__PURE__ */ N(_, {
|
|
129
138
|
className: "text-text-primary",
|
|
130
139
|
children: e.client?.name ?? "—"
|
|
131
140
|
}),
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
-
/* @__PURE__ */
|
|
135
|
-
/* @__PURE__ */
|
|
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(_, {
|
|
136
145
|
className: "text-right",
|
|
137
|
-
children: e.status !== "CLOSED" && e.status !== "ARCHIVED" ? /* @__PURE__ */
|
|
146
|
+
children: e.status !== "CLOSED" && e.status !== "ARCHIVED" ? /* @__PURE__ */ P(F, {
|
|
138
147
|
variant: "ghost",
|
|
139
148
|
size: "sm",
|
|
140
|
-
disabled:
|
|
141
|
-
onClick: () =>
|
|
142
|
-
onSuccess: () =>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
disabled: q.isPending,
|
|
150
|
+
onClick: () => q.mutate(e.id, {
|
|
151
|
+
onSuccess: () => {
|
|
152
|
+
n("psw.matter.closed", { matterId: e.id }), H({
|
|
153
|
+
tone: "success",
|
|
154
|
+
text: `${e.title} closed.`
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
onError: (e) => H({
|
|
147
158
|
tone: "danger",
|
|
148
159
|
text: e instanceof Error ? e.message : "Failed."
|
|
149
160
|
})
|
|
150
161
|
}),
|
|
151
|
-
children: [/* @__PURE__ */
|
|
152
|
-
}) : /* @__PURE__ */
|
|
162
|
+
children: [/* @__PURE__ */ N(E, { className: "mr-1 h-4 w-4" }), " Close"]
|
|
163
|
+
}) : /* @__PURE__ */ N("span", {
|
|
153
164
|
className: "text-xs text-text-tertiary",
|
|
154
165
|
children: e.closedAt ? `Closed ${S(e.closedAt)}` : "—"
|
|
155
166
|
})
|
|
@@ -157,17 +168,17 @@ var F = [
|
|
|
157
168
|
]
|
|
158
169
|
}, e.id)) })] })
|
|
159
170
|
})] }),
|
|
160
|
-
|
|
161
|
-
onClose: () =>
|
|
162
|
-
onSaved: (e) =>
|
|
171
|
+
L && /* @__PURE__ */ N(B, {
|
|
172
|
+
onClose: () => z(!1),
|
|
173
|
+
onSaved: (e) => H({
|
|
163
174
|
tone: "success",
|
|
164
175
|
text: `${e} opened.`
|
|
165
176
|
})
|
|
166
177
|
})
|
|
167
178
|
]
|
|
168
179
|
});
|
|
169
|
-
},
|
|
170
|
-
let o = n(), s = e({ pagination: { limit: 100 } }),
|
|
180
|
+
}, B = ({ onClose: t, onSaved: r }) => {
|
|
181
|
+
let o = n(), { emitFact: s } = C(), l = e({ pagination: { limit: 100 } }), u = i(), [p, m] = w({
|
|
171
182
|
clientId: "",
|
|
172
183
|
practiceAreaId: "",
|
|
173
184
|
title: "",
|
|
@@ -176,134 +187,138 @@ var F = [
|
|
|
176
187
|
priority: "MEDIUM",
|
|
177
188
|
dueDate: "",
|
|
178
189
|
isPrivileged: !1
|
|
179
|
-
}), [
|
|
190
|
+
}), [h, g] = w(null), _ = (e) => (t) => m((n) => ({
|
|
180
191
|
...n,
|
|
181
192
|
[e]: t.target.value
|
|
182
193
|
}));
|
|
183
|
-
return /* @__PURE__ */
|
|
194
|
+
return /* @__PURE__ */ N(d, {
|
|
184
195
|
open: !0,
|
|
185
196
|
onClose: t,
|
|
186
197
|
title: "New matter",
|
|
187
|
-
footer: /* @__PURE__ */
|
|
198
|
+
footer: /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ N(F, {
|
|
188
199
|
variant: "outline",
|
|
189
200
|
onClick: t,
|
|
190
201
|
disabled: o.isPending,
|
|
191
202
|
children: "Cancel"
|
|
192
|
-
}), /* @__PURE__ */
|
|
203
|
+
}), /* @__PURE__ */ N(F, {
|
|
193
204
|
onClick: () => {
|
|
194
|
-
if (
|
|
195
|
-
if (!
|
|
205
|
+
if (g(null), !p.clientId) return g("Select a client.");
|
|
206
|
+
if (!p.title.trim()) return g("Matter title is required.");
|
|
196
207
|
o.mutate({
|
|
197
|
-
clientId:
|
|
198
|
-
practiceAreaId:
|
|
199
|
-
title:
|
|
200
|
-
reference:
|
|
201
|
-
description:
|
|
202
|
-
priority:
|
|
203
|
-
isPrivileged:
|
|
204
|
-
dueDate:
|
|
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
|
|
205
216
|
}, {
|
|
206
|
-
onSuccess: () => {
|
|
207
|
-
|
|
217
|
+
onSuccess: (e) => {
|
|
218
|
+
let n = e.pswCreateMatter;
|
|
219
|
+
s("psw.matter.created", {
|
|
220
|
+
matterId: n.id,
|
|
221
|
+
clientId: p.clientId
|
|
222
|
+
}), r(p.title.trim()), t();
|
|
208
223
|
},
|
|
209
|
-
onError: (e) =>
|
|
224
|
+
onError: (e) => g(e instanceof Error ? e.message : "Failed.")
|
|
210
225
|
});
|
|
211
226
|
},
|
|
212
227
|
disabled: o.isPending,
|
|
213
228
|
children: o.isPending ? "Opening…" : "Open matter"
|
|
214
229
|
})] }),
|
|
215
|
-
children: /* @__PURE__ */
|
|
230
|
+
children: /* @__PURE__ */ P("div", {
|
|
216
231
|
className: "space-y-3",
|
|
217
232
|
children: [
|
|
218
|
-
|
|
233
|
+
h && /* @__PURE__ */ N(a, {
|
|
219
234
|
tone: "danger",
|
|
220
|
-
children:
|
|
235
|
+
children: h
|
|
221
236
|
}),
|
|
222
|
-
/* @__PURE__ */
|
|
237
|
+
/* @__PURE__ */ N(c, {
|
|
223
238
|
label: "Client",
|
|
224
239
|
required: !0,
|
|
225
|
-
children: /* @__PURE__ */
|
|
226
|
-
value:
|
|
227
|
-
onChange:
|
|
228
|
-
children: [/* @__PURE__ */
|
|
240
|
+
children: /* @__PURE__ */ P(f, {
|
|
241
|
+
value: p.clientId,
|
|
242
|
+
onChange: _("clientId"),
|
|
243
|
+
children: [/* @__PURE__ */ N("option", {
|
|
229
244
|
value: "",
|
|
230
245
|
children: "Select a client…"
|
|
231
|
-
}),
|
|
246
|
+
}), l.data?.items.map((e) => /* @__PURE__ */ N("option", {
|
|
232
247
|
value: e.id,
|
|
233
248
|
children: e.name
|
|
234
249
|
}, e.id))]
|
|
235
250
|
})
|
|
236
251
|
}),
|
|
237
|
-
/* @__PURE__ */
|
|
252
|
+
/* @__PURE__ */ N(c, {
|
|
238
253
|
label: "Title",
|
|
239
254
|
required: !0,
|
|
240
|
-
children: /* @__PURE__ */
|
|
241
|
-
value:
|
|
242
|
-
onChange:
|
|
255
|
+
children: /* @__PURE__ */ N(y, {
|
|
256
|
+
value: p.title,
|
|
257
|
+
onChange: _("title"),
|
|
243
258
|
placeholder: "Regulatory investigation — SEC inquiry"
|
|
244
259
|
})
|
|
245
260
|
}),
|
|
246
|
-
/* @__PURE__ */
|
|
261
|
+
/* @__PURE__ */ P("div", {
|
|
247
262
|
className: "grid grid-cols-2 gap-3",
|
|
248
|
-
children: [/* @__PURE__ */
|
|
263
|
+
children: [/* @__PURE__ */ N(c, {
|
|
249
264
|
label: "Reference",
|
|
250
|
-
children: /* @__PURE__ */
|
|
251
|
-
value:
|
|
252
|
-
onChange:
|
|
265
|
+
children: /* @__PURE__ */ N(y, {
|
|
266
|
+
value: p.reference,
|
|
267
|
+
onChange: _("reference"),
|
|
253
268
|
placeholder: "MAT-2026-014"
|
|
254
269
|
})
|
|
255
|
-
}), /* @__PURE__ */
|
|
270
|
+
}), /* @__PURE__ */ N(c, {
|
|
256
271
|
label: "Priority",
|
|
257
|
-
children: /* @__PURE__ */
|
|
258
|
-
value:
|
|
259
|
-
onChange:
|
|
260
|
-
children: x(
|
|
272
|
+
children: /* @__PURE__ */ N(f, {
|
|
273
|
+
value: p.priority,
|
|
274
|
+
onChange: _("priority"),
|
|
275
|
+
children: x(L)
|
|
261
276
|
})
|
|
262
277
|
})]
|
|
263
278
|
}),
|
|
264
|
-
/* @__PURE__ */
|
|
279
|
+
/* @__PURE__ */ P("div", {
|
|
265
280
|
className: "grid grid-cols-2 gap-3",
|
|
266
|
-
children: [/* @__PURE__ */
|
|
281
|
+
children: [/* @__PURE__ */ N(c, {
|
|
267
282
|
label: "Practice area",
|
|
268
|
-
children: /* @__PURE__ */
|
|
269
|
-
value:
|
|
270
|
-
onChange:
|
|
271
|
-
children: [/* @__PURE__ */
|
|
283
|
+
children: /* @__PURE__ */ P(f, {
|
|
284
|
+
value: p.practiceAreaId,
|
|
285
|
+
onChange: _("practiceAreaId"),
|
|
286
|
+
children: [/* @__PURE__ */ N("option", {
|
|
272
287
|
value: "",
|
|
273
288
|
children: "Unassigned"
|
|
274
|
-
}),
|
|
289
|
+
}), u.data?.map((e) => /* @__PURE__ */ N("option", {
|
|
275
290
|
value: e.id,
|
|
276
291
|
children: e.name
|
|
277
292
|
}, e.id))]
|
|
278
293
|
})
|
|
279
|
-
}), /* @__PURE__ */
|
|
294
|
+
}), /* @__PURE__ */ N(c, {
|
|
280
295
|
label: "Due date",
|
|
281
|
-
children: /* @__PURE__ */
|
|
296
|
+
children: /* @__PURE__ */ N(y, {
|
|
282
297
|
type: "date",
|
|
283
|
-
value:
|
|
284
|
-
onChange:
|
|
298
|
+
value: p.dueDate,
|
|
299
|
+
onChange: _("dueDate")
|
|
285
300
|
})
|
|
286
301
|
})]
|
|
287
302
|
}),
|
|
288
|
-
/* @__PURE__ */
|
|
303
|
+
/* @__PURE__ */ N(c, {
|
|
289
304
|
label: "Description",
|
|
290
|
-
children: /* @__PURE__ */
|
|
291
|
-
value:
|
|
292
|
-
onChange:
|
|
305
|
+
children: /* @__PURE__ */ N(v, {
|
|
306
|
+
value: p.description,
|
|
307
|
+
onChange: _("description")
|
|
293
308
|
})
|
|
294
309
|
}),
|
|
295
|
-
/* @__PURE__ */
|
|
310
|
+
/* @__PURE__ */ P("label", {
|
|
296
311
|
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",
|
|
297
|
-
children: [/* @__PURE__ */
|
|
312
|
+
children: [/* @__PURE__ */ N("input", {
|
|
298
313
|
type: "checkbox",
|
|
299
|
-
checked:
|
|
300
|
-
onChange: (e) =>
|
|
314
|
+
checked: p.isPrivileged,
|
|
315
|
+
onChange: (e) => m((t) => ({
|
|
301
316
|
...t,
|
|
302
317
|
isPrivileged: e.target.checked
|
|
303
318
|
}))
|
|
304
|
-
}), /* @__PURE__ */
|
|
319
|
+
}), /* @__PURE__ */ P("span", {
|
|
305
320
|
className: "flex items-center gap-1.5",
|
|
306
|
-
children: [/* @__PURE__ */
|
|
321
|
+
children: [/* @__PURE__ */ N(k, { className: "h-3.5 w-3.5 text-status-warning-text" }), "Privileged / confidential matter"]
|
|
307
322
|
})]
|
|
308
323
|
})
|
|
309
324
|
]
|
|
@@ -311,6 +326,6 @@ var F = [
|
|
|
311
326
|
});
|
|
312
327
|
};
|
|
313
328
|
//#endregion
|
|
314
|
-
export {
|
|
329
|
+
export { z as MattersPage };
|
|
315
330
|
|
|
316
331
|
//# sourceMappingURL=MattersPage.js.map
|