@burdenoff/microfe-proserviceworld 2026.709.3 → 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.
@@ -1 +1 @@
1
- {"version":3,"file":"EngagementsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/EngagementsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, Briefcase, ChevronRight } from 'lucide-react';\nimport {\n useEngagements,\n useCreateEngagement,\n useUpdateEngagement,\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 { impactFeedback } from '../utils/native';\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';\nimport { TagPicker } from '../components/TagPicker';\nimport { LoadMore } from '../components/LoadMore';\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\nconst PAGE_SIZE = 25;\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 [pagination, setPagination] = useState({ limit: PAGE_SIZE, offset: 0 });\n const clients = useClients({ pagination: { limit: 100 } });\n const update = useUpdateEngagement();\n const { data, isLoading, error, refetch } = useEngagements({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n clientId: clientFilter || undefined,\n pagination,\n });\n\n const allItems = useMemo(() => data?.items ?? [], [data]);\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 void impactFeedback('light');\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) => {\n setSearch(e.target.value);\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && search.trim()) {\n emitFact('psw.search.performed', {\n entityType: 'engagement',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as PswEngagementStatus | '');\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\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) => {\n setClientFilter(e.target.value);\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\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 <Th>Tags</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 <Td>\n <div onClick={(ev) => ev.stopPropagation()} role=\"presentation\">\n <TagPicker\n entityType=\"PswEngagement\"\n entityId={e.id}\n tags={e.tags ?? []}\n onChange={async (tags) => {\n await update.mutateAsync({ id: e.id, input: { tags } });\n void refetch();\n }}\n maxTags={5}\n />\n </div>\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n <LoadMore\n hasMore={data?.pageInfo?.hasMore ?? false}\n loading={isLoading}\n loadedCount={allItems.length}\n totalCount={data?.totalCount ?? allItems.length}\n onLoadMore={() =>\n setPagination((p) => ({ limit: PAGE_SIZE, offset: p.offset + PAGE_SIZE }))\n }\n />\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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"}
1
+ {"version":3,"file":"EngagementsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/EngagementsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, Briefcase, ChevronRight } from 'lucide-react';\nimport {\n useEngagements,\n useCreateEngagement,\n useUpdateEngagement,\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 { impactFeedback } from '../utils/native';\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';\nimport { TagPicker } from '../components/TagPicker';\nimport { LoadMore } from '../components/LoadMore';\nimport { t } from '../i18n';\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\nconst PAGE_SIZE = 25;\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 [pagination, setPagination] = useState({ limit: PAGE_SIZE, offset: 0 });\n const clients = useClients({ pagination: { limit: 100 } });\n const update = useUpdateEngagement();\n const { data, isLoading, error, refetch } = useEngagements({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n clientId: clientFilter || undefined,\n pagination,\n });\n\n const allItems = useMemo(() => data?.items ?? [], [data]);\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={t('psw.engagements.title')}\n subtitle={t('psw.engagements.subtitle')}\n icon={<Briefcase className=\"h-6 w-6\" />}\n actions={\n <Button\n onClick={() => {\n void impactFeedback('light');\n emitIntent('psw.engagement.create_clicked');\n setCreating(true);\n }}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {t('psw.engagements.new')}\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={t('psw.engagements.searchPlaceholder')}\n value={search}\n onChange={(e) => {\n setSearch(e.target.value);\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && search.trim()) {\n emitFact('psw.search.performed', {\n entityType: 'engagement',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as PswEngagementStatus | '');\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n className=\"sm:w-44\"\n >\n <option value=\"\">{t('psw.engagements.allStatuses')}</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n <NativeSelect\n value={clientFilter}\n onChange={(e) => {\n setClientFilter(e.target.value);\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n className=\"sm:w-48\"\n >\n <option value=\"\">{t('psw.engagements.allClients')}</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={t('psw.engagements.emptyTitle')}\n description={t('psw.engagements.emptyDescription')}\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 {t('psw.engagements.new')}\n </Button>\n }\n />\n ) : (\n <SectionCard title={`${data.totalCount} engagement${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>{t('psw.engagements.tableEngagement')}</Th>\n <Th>{t('psw.engagements.tableClient')}</Th>\n <Th>{t('psw.engagements.tableFee')}</Th>\n <Th>{t('psw.engagements.tableStatus')}</Th>\n <Th>{t('psw.engagements.tableStarted')}</Th>\n <Th>{t('psw.engagements.tableTags')}</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 <Td>\n <div onClick={(ev) => ev.stopPropagation()} role=\"presentation\">\n <TagPicker\n entityType=\"PswEngagement\"\n entityId={e.id}\n tags={e.tags ?? []}\n onChange={async (tags) => {\n await update.mutateAsync({ id: e.id, input: { tags } });\n void refetch();\n }}\n maxTags={5}\n />\n </div>\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n <LoadMore\n hasMore={data?.pageInfo?.hasMore ?? false}\n loading={isLoading}\n loadedCount={allItems.length}\n totalCount={data?.totalCount ?? allItems.length}\n onLoadMore={() =>\n setPagination((p) => ({ limit: PAGE_SIZE, offset: p.offset + PAGE_SIZE }))\n }\n />\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={t('psw.engagements.newTitle')}\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 +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;AA+DhC,eAAO,MAAM,WAAW,EAAE,EAgOzB,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 { useAnalytics as w } from "../hooks/useAnalytics.js";
4
- import { impactFeedback as T } from "../utils/native.js";
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 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";
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 z = [
13
+ var B = [
13
14
  "OPEN",
14
15
  "ON_HOLD",
15
16
  "CLOSED",
16
17
  "ARCHIVED"
17
- ], B = [
18
+ ], V = [
18
19
  "LOW",
19
20
  "MEDIUM",
20
21
  "HIGH",
21
22
  "CRITICAL"
22
- ], ne = () => /* @__PURE__ */ I("span", {
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__ */ 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,
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: 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", {
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__ */ I(m, {
40
- title: "Matters",
41
- subtitle: "The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.",
42
- icon: /* @__PURE__ */ I(j, { className: "h-6 w-6" }),
43
- actions: /* @__PURE__ */ L(R, {
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
- T("light"), e("psw.matter.create_clicked"), H(!0);
46
+ ee("light"), e("psw.matter.create_clicked"), U(!0);
46
47
  },
47
- children: [/* @__PURE__ */ I(N, { className: "mr-1.5 h-4 w-4" }), "New matter"]
48
+ children: [/* @__PURE__ */ L(P, { className: "mr-1.5 h-4 w-4" }), w("psw.matters.new")]
48
49
  })
49
50
  }),
50
- U && /* @__PURE__ */ I(o, {
51
- tone: U.tone,
52
- onClose: () => W(null),
53
- children: U.text
51
+ W && /* @__PURE__ */ L(o, {
52
+ tone: W.tone,
53
+ onClose: () => G(null),
54
+ children: W.text
54
55
  }),
55
- /* @__PURE__ */ L("div", {
56
+ /* @__PURE__ */ R("div", {
56
57
  className: "flex flex-col gap-2 sm:flex-row sm:items-center",
57
- children: [/* @__PURE__ */ L("div", {
58
+ children: [/* @__PURE__ */ R("div", {
58
59
  className: "relative flex-1",
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, {
60
- placeholder: "Search matters…",
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: V,
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__ */ L(p, {
77
+ }), /* @__PURE__ */ R(p, {
77
78
  value: f,
78
79
  onChange: (e) => {
79
80
  y(e.target.value), K({
80
- limit: V,
81
+ limit: H,
81
82
  offset: 0
82
83
  });
83
84
  },
84
85
  className: "sm:w-48",
85
- children: [/* @__PURE__ */ I("option", {
86
+ children: [/* @__PURE__ */ L("option", {
86
87
  value: "",
87
- children: "All statuses"
88
- }), S(z)]
88
+ children: w("psw.matters.allStatuses")
89
+ }), S(B)]
89
90
  })]
90
91
  }),
91
- J ? /* @__PURE__ */ I(u, {}) : Y ? /* @__PURE__ */ I(c, {
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__ */ I(s, {
95
- title: "No matters yet",
96
- description: "Open a matter to track a regulated thread of work for a client.",
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"]
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__ */ L(F, { children: [/* @__PURE__ */ L("div", {
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__ */ I(d, {
106
+ /* @__PURE__ */ L(d, {
106
107
  label: "Matters",
107
108
  value: q.totalCount,
108
- icon: /* @__PURE__ */ I(j, { className: "h-4 w-4" })
109
+ icon: /* @__PURE__ */ L(M, { className: "h-4 w-4" })
109
110
  }),
110
- /* @__PURE__ */ I(d, {
111
+ /* @__PURE__ */ L(d, {
111
112
  label: "Open",
112
- value: ae,
113
- icon: /* @__PURE__ */ I(A, { className: "h-4 w-4" }),
113
+ value: oe,
114
+ icon: /* @__PURE__ */ L(j, { className: "h-4 w-4" }),
114
115
  tone: "accent"
115
116
  }),
116
- /* @__PURE__ */ I(d, {
117
+ /* @__PURE__ */ L(d, {
117
118
  label: "Privileged",
118
- value: oe,
119
- icon: /* @__PURE__ */ I(M, { className: "h-4 w-4" }),
119
+ value: se,
120
+ icon: /* @__PURE__ */ L(N, { className: "h-4 w-4" }),
120
121
  tone: "warning"
121
122
  }),
122
- /* @__PURE__ */ I(d, {
123
+ /* @__PURE__ */ L(d, {
123
124
  label: "High priority",
124
125
  value: $,
125
- icon: /* @__PURE__ */ I(O, { className: "h-4 w-4" }),
126
+ icon: /* @__PURE__ */ L(te, { className: "h-4 w-4" }),
126
127
  tone: $ ? "danger" : "neutral"
127
128
  })
128
129
  ]
129
- }), /* @__PURE__ */ L(h, {
130
+ }), /* @__PURE__ */ R(h, {
130
131
  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, {
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: "Actions"
141
+ children: w("psw.common.actions")
141
142
  })
142
- ] }) }), /* @__PURE__ */ I("tbody", { children: q.items.map((e) => /* @__PURE__ */ L("tr", {
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__ */ L(v, { children: [/* @__PURE__ */ L("span", {
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__ */ I(ne, {}), /* @__PURE__ */ I("span", {
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__ */ L("div", {
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__ */ I(v, {
156
+ /* @__PURE__ */ L(v, {
156
157
  className: "text-text-primary",
157
158
  children: e.client?.name ?? "—"
158
159
  }),
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, {
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 ie.mutateAsync({
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__ */ I(v, {
175
+ /* @__PURE__ */ L(v, {
175
176
  className: "text-right",
176
- children: e.status !== "CLOSED" && e.status !== "ARCHIVED" ? /* @__PURE__ */ L(R, {
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 }), W({
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) => W({
188
+ onError: (e) => G({
188
189
  tone: "danger",
189
190
  text: e instanceof Error ? e.message : "Failed."
190
191
  })
191
192
  }),
192
- children: [/* @__PURE__ */ I(k, { className: "mr-1 h-4 w-4" }), " Close"]
193
- }) : /* @__PURE__ */ I("span", {
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__ */ I(ee, {
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: V,
206
- offset: e.offset + V
206
+ limit: H,
207
+ offset: e.offset + H
207
208
  }))
208
209
  })]
209
210
  })] }),
210
- B && /* @__PURE__ */ I(re, {
211
- onClose: () => H(!1),
212
- onSaved: (e) => W({
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 } = w(), c = e({ pagination: { limit: 100 } }), u = i(), [d, m] = D({
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] = D(null), _ = (e) => (t) => m((n) => ({
230
+ }), [h, g] = k(null), _ = (e) => (t) => m((n) => ({
230
231
  ...n,
231
232
  [e]: t.target.value
232
233
  }));
233
- return /* @__PURE__ */ I(f, {
234
+ return /* @__PURE__ */ L(f, {
234
235
  open: !0,
235
236
  onClose: t,
236
- title: "New matter",
237
- footer: /* @__PURE__ */ L(F, { children: [/* @__PURE__ */ I(R, {
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__ */ I(R, {
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__ */ L("div", {
270
+ children: /* @__PURE__ */ R("div", {
270
271
  className: "space-y-3",
271
272
  children: [
272
- h && /* @__PURE__ */ I(o, {
273
+ h && /* @__PURE__ */ L(o, {
273
274
  tone: "danger",
274
275
  children: h
275
276
  }),
276
- /* @__PURE__ */ I(l, {
277
+ /* @__PURE__ */ L(l, {
277
278
  label: "Client",
278
279
  required: !0,
279
- children: /* @__PURE__ */ L(p, {
280
+ children: /* @__PURE__ */ R(p, {
280
281
  value: d.clientId,
281
282
  onChange: _("clientId"),
282
- children: [/* @__PURE__ */ I("option", {
283
+ children: [/* @__PURE__ */ L("option", {
283
284
  value: "",
284
285
  children: "Select a client…"
285
- }), c.data?.items.map((e) => /* @__PURE__ */ I("option", {
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__ */ I(l, {
292
+ /* @__PURE__ */ L(l, {
292
293
  label: "Title",
293
294
  required: !0,
294
- children: /* @__PURE__ */ I(b, {
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__ */ L("div", {
301
+ /* @__PURE__ */ R("div", {
301
302
  className: "grid grid-cols-2 gap-3",
302
- children: [/* @__PURE__ */ I(l, {
303
+ children: [/* @__PURE__ */ L(l, {
303
304
  label: "Reference",
304
- children: /* @__PURE__ */ I(b, {
305
+ children: /* @__PURE__ */ L(b, {
305
306
  value: d.reference,
306
307
  onChange: _("reference"),
307
308
  placeholder: "MAT-2026-014"
308
309
  })
309
- }), /* @__PURE__ */ I(l, {
310
+ }), /* @__PURE__ */ L(l, {
310
311
  label: "Priority",
311
- children: /* @__PURE__ */ I(p, {
312
+ children: /* @__PURE__ */ L(p, {
312
313
  value: d.priority,
313
314
  onChange: _("priority"),
314
- children: S(B)
315
+ children: S(V)
315
316
  })
316
317
  })]
317
318
  }),
318
- /* @__PURE__ */ L("div", {
319
+ /* @__PURE__ */ R("div", {
319
320
  className: "grid grid-cols-2 gap-3",
320
- children: [/* @__PURE__ */ I(l, {
321
+ children: [/* @__PURE__ */ L(l, {
321
322
  label: "Practice area",
322
- children: /* @__PURE__ */ L(p, {
323
+ children: /* @__PURE__ */ R(p, {
323
324
  value: d.practiceAreaId,
324
325
  onChange: _("practiceAreaId"),
325
- children: [/* @__PURE__ */ I("option", {
326
+ children: [/* @__PURE__ */ L("option", {
326
327
  value: "",
327
328
  children: "Unassigned"
328
- }), u.data?.map((e) => /* @__PURE__ */ I("option", {
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__ */ I(l, {
334
+ }), /* @__PURE__ */ L(l, {
334
335
  label: "Due date",
335
- children: /* @__PURE__ */ I(b, {
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__ */ I(l, {
343
+ /* @__PURE__ */ L(l, {
343
344
  label: "Description",
344
- children: /* @__PURE__ */ I(y, {
345
+ children: /* @__PURE__ */ L(y, {
345
346
  value: d.description,
346
347
  onChange: _("description")
347
348
  })
348
349
  }),
349
- /* @__PURE__ */ L("label", {
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__ */ I("input", {
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__ */ L("span", {
359
+ }), /* @__PURE__ */ R("span", {
359
360
  className: "flex items-center gap-1.5",
360
- children: [/* @__PURE__ */ I(M, { className: "h-3.5 w-3.5 text-status-warning-text" }), "Privileged / confidential matter"]
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 { H as MattersPage };
369
+ export { U as MattersPage };
369
370
 
370
371
  //# sourceMappingURL=MattersPage.js.map