@burdenoff/microfe-proserviceworld 2026.1026.2 → 2026.1031.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/proserviceworld/components/CredentialDirectory.js +44 -43
- package/dist/proserviceworld/components/CredentialDirectory.js.map +1 -1
- package/dist/proserviceworld/components/CredentialReminderPanel.js +5 -4
- package/dist/proserviceworld/components/CredentialReminderPanel.js.map +1 -1
- package/dist/proserviceworld/components/ui.d.ts +7 -3
- package/dist/proserviceworld/components/ui.d.ts.map +1 -1
- package/dist/proserviceworld/components/ui.js +135 -121
- package/dist/proserviceworld/components/ui.js.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +28 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js +95 -73
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
- package/dist/proserviceworld/hooks/useTr.d.ts +49 -8
- package/dist/proserviceworld/hooks/useTr.d.ts.map +1 -1
- package/dist/proserviceworld/hooks/useTr.js +45 -21
- package/dist/proserviceworld/hooks/useTr.js.map +1 -1
- package/dist/proserviceworld/i18n/catalog/analytics.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/analytics.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/analytics.js +271 -0
- package/dist/proserviceworld/i18n/catalog/analytics.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/common.d.ts +9 -0
- package/dist/proserviceworld/i18n/catalog/common.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/common.js +163 -0
- package/dist/proserviceworld/i18n/catalog/common.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/compliance.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/compliance.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/compliance.js +157 -0
- package/dist/proserviceworld/i18n/catalog/compliance.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.js +145 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/documents.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/documents.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/documents.js +157 -0
- package/dist/proserviceworld/i18n/catalog/documents.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/enums.d.ts +10 -0
- package/dist/proserviceworld/i18n/catalog/enums.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/enums.js +481 -0
- package/dist/proserviceworld/i18n/catalog/enums.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/index.d.ts +9 -0
- package/dist/proserviceworld/i18n/catalog/index.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/index.js +25 -0
- package/dist/proserviceworld/i18n/catalog/index.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/invoices.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/invoices.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/invoices.js +247 -0
- package/dist/proserviceworld/i18n/catalog/invoices.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.js +97 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/time.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/time.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/time.js +301 -0
- package/dist/proserviceworld/i18n/catalog/time.js.map +1 -0
- package/dist/proserviceworld/i18n/index.d.ts +10 -9
- package/dist/proserviceworld/i18n/index.d.ts.map +1 -1
- package/dist/proserviceworld/i18n/index.js +16 -12
- package/dist/proserviceworld/i18n/index.js.map +1 -1
- package/dist/proserviceworld/i18n/types.d.ts +13 -0
- package/dist/proserviceworld/i18n/types.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/types.js +18 -0
- package/dist/proserviceworld/i18n/types.js.map +1 -0
- package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/AnalyticsPage.js +236 -152
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientDetailPage.js +99 -98
- 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 +181 -181
- package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.js +210 -209
- package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
- package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/ConflictsPage.js +139 -138
- package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.js +150 -149
- package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementDetailPage.js +105 -104
- 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 +137 -137
- package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.js +275 -258
- 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 +166 -166
- package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.js +100 -99
- package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -1
- package/dist/proserviceworld/pages/PractitionerCredentialsPage.js +30 -29
- package/dist/proserviceworld/pages/PractitionerCredentialsPage.js.map +1 -1
- package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/TimePage.js +343 -350
- package/dist/proserviceworld/pages/TimePage.js.map +1 -1
- package/dist/proserviceworld/utils/humanize.d.ts +3 -0
- package/dist/proserviceworld/utils/humanize.d.ts.map +1 -0
- package/dist/proserviceworld/utils/humanize.js +6 -0
- package/dist/proserviceworld/utils/humanize.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ClientsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, Users, Pencil, Archive, Building2, User, ChevronRight } from 'lucide-react';\nimport {\n useClients,\n useCreateClient,\n useUpdateClient,\n useArchiveClient,\n type PswClient,\n type PswClientStatus,\n} from '../hooks/useProServiceWorldApi';\nimport { useNav } from '../utils/nav';\nimport { cn } from '../utils/cn';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport { useTr } from '../hooks/useTr';\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 fmtDate,\n} from '../components/ui';\nimport { TagPicker } from '../components/TagPicker';\nimport { LoadMore } from '../components/LoadMore';\n\nconst CLIENT_TYPES = ['ORGANIZATION', 'INDIVIDUAL'] as const;\nconst CLIENT_STATUSES: PswClientStatus[] = ['PROSPECT', 'ACTIVE', 'INACTIVE', 'ARCHIVED'];\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\n/** Tinted initials avatar (semantic tokens only). */\nexport const Avatar: FC<{ name: string; className?: string }> = ({ name, className }) => (\n <span\n className={cn(\n 'flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-accent/10 text-xs font-semibold text-accent ring-1 ring-inset ring-accent/15',\n className\n )}\n aria-hidden\n >\n {initials(name)}\n </span>\n);\n\ninterface FormState {\n name: string;\n type: string;\n status: string;\n industry: string;\n contactName: string;\n contactEmail: string;\n contactPhone: string;\n notes: string;\n}\nconst emptyForm: FormState = {\n name: '',\n type: 'ORGANIZATION',\n status: 'PROSPECT',\n industry: '',\n contactName: '',\n contactEmail: '',\n contactPhone: '',\n notes: '',\n};\n\nconst PAGE_SIZE = 25;\n\nexport const ClientsPage: FC = () => {\n const nav = useNav();\n const tr = useTr();\n const { emitIntent, emitFact } = useAnalytics();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswClientStatus | ''>('');\n const [editing, setEditing] = useState<PswClient | null>(null);\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const [pagination, setPagination] = useState({ limit: PAGE_SIZE, offset: 0 });\n\n const { data, isLoading, error, refetch } = useClients({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n pagination,\n });\n const update = useUpdateClient();\n\n const allItems = useMemo(() => data?.items ?? [], [data]);\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={tr('psw.clients.title', 'Clients')}\n subtitle={tr('psw.clients.subtitle', 'Every person or organization your firm serves.')}\n icon={<Users className=\"h-6 w-6\" />}\n actions={\n <Button\n onClick={() => {\n void impactFeedback('light');\n emitIntent('psw.client.create_clicked');\n setCreating(true);\n }}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" /> {tr('psw.clients.new', 'New client')}\n </Button>\n }\n />\n\n {banner && (\n <Banner tone={banner.tone} onClose={() => setBanner(null)}>\n {banner.text}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder={tr('psw.clients.searchPlaceholder', 'Search clients…')}\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: 'client',\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 PswClientStatus | '');\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n className=\"sm:w-48\"\n >\n <option value=\"\">{tr('psw.clients.allStatuses', 'All statuses')}</option>\n {enumOptions(CLIENT_STATUSES)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title={tr('psw.clients.emptyTitle', 'No clients yet')}\n description={tr(\n 'psw.clients.emptyDescription',\n 'Add your first client to start scoping engagements and matters.'\n )}\n icon={<Users className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> {tr('psw.clients.new', 'New client')}\n </Button>\n }\n />\n ) : (\n <SectionCard\n title={\n data.totalCount === 1\n ? tr('psw.clients.count', '{{count}} client', { count: data.totalCount })\n : tr('psw.clients.countPlural', '{{count}} clients', { count: data.totalCount })\n }\n >\n {/*\n Phones get a tappable card list: the desktop table carries seven\n columns behind a horizontal scroll, which hides the status and the\n row actions on a narrow viewport. Same fields, same affordances.\n */}\n <ul className=\"space-y-2.5 sm:hidden\">\n {data.items.map((c) => (\n <li\n key={c.id}\n className=\"overflow-hidden rounded-xl border border-border-seam bg-bg-canvas\"\n >\n <button\n type=\"button\"\n onClick={() => {\n void impactFeedback('light');\n nav(`clients/${c.id}`);\n }}\n className=\"flex w-full items-center gap-3 p-3.5 text-left transition-colors active:bg-bg-sunken/60\"\n >\n <Avatar name={c.name} className=\"h-11 w-11 text-sm\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-semibold text-text-primary\">\n {c.name}\n </span>\n <span className=\"mt-0.5 block truncate text-sm text-text-secondary\">\n {c.contactName ||\n (c.type === 'ORGANIZATION'\n ? tr('psw.clients.typeOrganization', 'Organization')\n : tr('psw.clients.typeIndividual', 'Individual'))}\n </span>\n <span className=\"mt-1.5 flex items-center gap-2\">\n <span className=\"truncate text-xs text-text-tertiary\">\n {c.industry || fmtDate(c.createdAt)}\n </span>\n <StatusPill status={c.status} />\n </span>\n </span>\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-tertiary\" />\n </button>\n <div className=\"flex items-center justify-between gap-2 border-t border-border-seam px-3.5 py-2\">\n <div className=\"min-w-0 flex-1\">\n <TagPicker\n entityType=\"PswClient\"\n entityId={c.id}\n tags={c.tags ?? []}\n onChange={async (tags) => {\n await update.mutateAsync({ id: c.id, input: { tags } });\n void refetch();\n }}\n maxTags={5}\n />\n </div>\n <div className=\"flex shrink-0 gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setEditing(c)}\n aria-label={tr('psw.common.edit', 'Edit')}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n {c.status !== 'ARCHIVED' && (\n <ArchiveButton\n id={c.id}\n name={c.name}\n onDone={(ok) =>\n setBanner(\n ok\n ? {\n tone: 'success',\n text: tr('psw.clients.archived', '{{name}} archived.', {\n name: c.name,\n }),\n }\n : {\n tone: 'danger',\n text: tr(\n 'psw.clients.archiveFailed',\n 'Could not archive client.'\n ),\n }\n )\n }\n />\n )}\n </div>\n </div>\n </li>\n ))}\n </ul>\n\n <div className=\"hidden sm:block\">\n <TableWrap>\n <thead>\n <tr>\n <Th>{tr('psw.common.name', 'Name')}</Th>\n <Th>{tr('psw.common.type', 'Type')}</Th>\n <Th>{tr('psw.clients.tableIndustry', 'Industry')}</Th>\n <Th>{tr('psw.common.status', 'Status')}</Th>\n <Th>{tr('psw.common.added', 'Added')}</Th>\n <Th>{tr('psw.clients.tableTags', 'Tags')}</Th>\n <Th className=\"text-right\">{tr('psw.common.actions', 'Actions')}</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((c) => (\n <tr\n key={c.id}\n className=\"group cursor-pointer transition-colors hover:bg-bg-sunken/60\"\n onClick={() => nav(`clients/${c.id}`)}\n >\n <Td>\n <div className=\"flex items-center gap-3\">\n <Avatar name={c.name} />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1 font-medium text-text-primary transition-colors group-hover:text-accent\">\n <span className=\"truncate\">{c.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 {c.contactName ? (\n <div className=\"truncate text-xs text-text-tertiary\">\n {c.contactName}\n </div>\n ) : null}\n </div>\n </div>\n </Td>\n <Td>\n <span className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n {c.type === 'ORGANIZATION' ? (\n <Building2 className=\"h-3.5 w-3.5 text-text-tertiary\" />\n ) : (\n <User className=\"h-3.5 w-3.5 text-text-tertiary\" />\n )}\n {c.type === 'ORGANIZATION'\n ? tr('psw.clients.typeOrganization', 'Organization')\n : tr('psw.clients.typeIndividual', 'Individual')}\n </span>\n </Td>\n <Td>{c.industry || tr('psw.common.dash', '—')}</Td>\n <Td>\n <StatusPill status={c.status} />\n </Td>\n <Td className=\"whitespace-nowrap\">{fmtDate(c.createdAt)}</Td>\n <Td>\n <div onClick={(ev) => ev.stopPropagation()} role=\"presentation\">\n <TagPicker\n entityType=\"PswClient\"\n entityId={c.id}\n tags={c.tags ?? []}\n onChange={async (tags) => {\n await update.mutateAsync({ id: c.id, input: { tags } });\n void refetch();\n }}\n maxTags={5}\n />\n </div>\n </Td>\n <Td className=\"text-right\">\n <div\n className=\"flex justify-end gap-1\"\n onClick={(ev) => ev.stopPropagation()}\n role=\"presentation\"\n >\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setEditing(c)}\n aria-label={tr('psw.common.edit', 'Edit')}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n {c.status !== 'ARCHIVED' && (\n <ArchiveButton\n id={c.id}\n name={c.name}\n onDone={(ok) =>\n setBanner(\n ok\n ? {\n tone: 'success',\n text: tr('psw.clients.archived', '{{name}} archived.', {\n name: c.name,\n }),\n }\n : {\n tone: 'danger',\n text: tr(\n 'psw.clients.archiveFailed',\n 'Could not archive client.'\n ),\n }\n )\n }\n />\n )}\n </div>\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </div>\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 <ClientModal\n onClose={() => setCreating(false)}\n onSaved={(name) =>\n setBanner({\n tone: 'success',\n text: tr('psw.clients.created', '{{name}} created.', { name }),\n })\n }\n />\n )}\n {editing && (\n <ClientModal\n client={editing}\n onClose={() => setEditing(null)}\n onSaved={(name) =>\n setBanner({\n tone: 'success',\n text: tr('psw.clients.updated', '{{name}} updated.', { name }),\n })\n }\n />\n )}\n </div>\n );\n};\n\nconst ArchiveButton: FC<{ id: string; name: string; onDone: (ok: boolean) => void }> = ({\n id,\n name,\n onDone,\n}) => {\n const archive = useArchiveClient();\n const tr = useTr();\n const { emitFact } = useAnalytics();\n return (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={tr('psw.common.archive', 'Archive')}\n disabled={archive.isPending}\n onClick={() => {\n if (\n !window.confirm(\n tr(\n 'psw.clients.archiveConfirm',\n 'Archive this client? Their engagements and matters remain.'\n )\n )\n )\n return;\n archive.mutate(id, {\n onSuccess: (r) => {\n emitFact('psw.client.archived', { clientId: id });\n onDone(Boolean(r));\n },\n onError: () => onDone(false),\n });\n }}\n >\n <Archive className=\"h-4 w-4\" />\n </Button>\n );\n};\n\nconst ClientModal: FC<{\n client?: PswClient;\n onClose: () => void;\n onSaved: (name: string) => void;\n}> = ({ client, onClose, onSaved }) => {\n const tr = useTr();\n const create = useCreateClient();\n const update = useUpdateClient();\n const { emitFact } = useAnalytics();\n const [form, setForm] = useState<FormState>(\n client\n ? {\n name: client.name,\n type: client.type,\n status: client.status,\n industry: client.industry ?? '',\n contactName: client.contactName ?? '',\n contactEmail: client.contactEmail ?? '',\n contactPhone: client.contactPhone ?? '',\n notes: client.notes ?? '',\n }\n : emptyForm\n );\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof FormState) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n const pending = create.isPending || update.isPending;\n\n const payload = useMemo(\n () => ({\n name: form.name.trim(),\n type: form.type,\n status: form.status,\n industry: form.industry.trim() || null,\n contactName: form.contactName.trim() || null,\n contactEmail: form.contactEmail.trim() || null,\n contactPhone: form.contactPhone.trim() || null,\n notes: form.notes.trim() || null,\n }),\n [form]\n );\n\n const submit = () => {\n setErr(null);\n if (!payload.name) return setErr(tr('psw.clients.nameRequired', 'Client name is required.'));\n const onError = (e: unknown) =>\n setErr(e instanceof Error ? e.message : tr('psw.clients.saveFailed', 'Save failed.'));\n if (client) {\n update.mutate(\n { id: client.id, input: payload },\n {\n onSuccess: () => {\n emitFact('psw.client.updated', { clientId: client.id });\n onSaved(payload.name);\n onClose();\n },\n onError,\n }\n );\n } else {\n create.mutate(payload, {\n onSuccess: (created) => {\n emitFact('psw.client.created', { clientId: created.pswCreateClient.id });\n onSaved(payload.name);\n onClose();\n },\n onError,\n });\n }\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title={\n client ? tr('psw.clients.edit', 'Edit client') : tr('psw.clients.newTitle', 'New client')\n }\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={pending}>\n {tr('psw.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submit} disabled={pending}>\n {pending\n ? tr('psw.common.saving', 'Saving…')\n : client\n ? tr('psw.common.save', 'Save changes')\n : tr('psw.common.create', 'Create client')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.common.name', 'Name')} required>\n <TextInput value={form.name} onChange={set('name')} placeholder=\"Acme Holdings Ltd.\" />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label={tr('psw.common.type', 'Type')}>\n <NativeSelect value={form.type} onChange={set('type')}>\n {enumOptions(CLIENT_TYPES)}\n </NativeSelect>\n </Field>\n <Field label={tr('psw.common.status', 'Status')}>\n <NativeSelect value={form.status} onChange={set('status')}>\n {enumOptions(CLIENT_STATUSES)}\n </NativeSelect>\n </Field>\n </div>\n <Field label={tr('psw.clients.industry', 'Industry')}>\n <TextInput\n value={form.industry}\n onChange={set('industry')}\n placeholder=\"Financial services\"\n />\n </Field>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <Field label={tr('psw.clients.contactName', 'Contact name')}>\n <TextInput value={form.contactName} onChange={set('contactName')} />\n </Field>\n <Field label={tr('psw.clients.contactEmail', 'Contact email')}>\n <TextInput type=\"email\" value={form.contactEmail} onChange={set('contactEmail')} />\n </Field>\n </div>\n <Field label={tr('psw.clients.contactPhone', 'Contact phone')}>\n <TextInput value={form.contactPhone} onChange={set('contactPhone')} />\n </Field>\n <Field label={tr('psw.clients.notes', '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":"ClientsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ClientsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, Users, Pencil, Archive, Building2, User, ChevronRight } from 'lucide-react';\nimport {\n useClients,\n useCreateClient,\n useUpdateClient,\n useArchiveClient,\n type PswClient,\n type PswClientStatus,\n} from '../hooks/useProServiceWorldApi';\nimport { useNav } from '../utils/nav';\nimport { cn } from '../utils/cn';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport { useEnumLabel, useTr } from '../hooks/useTr';\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 fmtDate,\n} from '../components/ui';\nimport { TagPicker } from '../components/TagPicker';\nimport { LoadMore } from '../components/LoadMore';\n\nconst CLIENT_TYPES = ['ORGANIZATION', 'INDIVIDUAL'] as const;\nconst CLIENT_STATUSES: PswClientStatus[] = ['PROSPECT', 'ACTIVE', 'INACTIVE', 'ARCHIVED'];\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\n/** Tinted initials avatar (semantic tokens only). */\nexport const Avatar: FC<{ name: string; className?: string }> = ({ name, className }) => (\n <span\n className={cn(\n 'flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-accent/10 text-xs font-semibold text-accent ring-1 ring-inset ring-accent/15',\n className\n )}\n aria-hidden\n >\n {initials(name)}\n </span>\n);\n\ninterface FormState {\n name: string;\n type: string;\n status: string;\n industry: string;\n contactName: string;\n contactEmail: string;\n contactPhone: string;\n notes: string;\n}\nconst emptyForm: FormState = {\n name: '',\n type: 'ORGANIZATION',\n status: 'PROSPECT',\n industry: '',\n contactName: '',\n contactEmail: '',\n contactPhone: '',\n notes: '',\n};\n\nconst PAGE_SIZE = 25;\n\nexport const ClientsPage: FC = () => {\n const enumLabel = useEnumLabel();\n const nav = useNav();\n const tr = useTr();\n const { emitIntent, emitFact } = useAnalytics();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswClientStatus | ''>('');\n const [editing, setEditing] = useState<PswClient | null>(null);\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const [pagination, setPagination] = useState({ limit: PAGE_SIZE, offset: 0 });\n\n const { data, isLoading, error, refetch } = useClients({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n pagination,\n });\n const update = useUpdateClient();\n\n const allItems = useMemo(() => data?.items ?? [], [data]);\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title={tr('psw.clients.title', 'Clients')}\n subtitle={tr('psw.clients.subtitle', 'Every person or organization your firm serves.')}\n icon={<Users className=\"h-6 w-6\" />}\n actions={\n <Button\n onClick={() => {\n void impactFeedback('light');\n emitIntent('psw.client.create_clicked');\n setCreating(true);\n }}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" /> {tr('psw.clients.new', 'New client')}\n </Button>\n }\n />\n\n {banner && (\n <Banner tone={banner.tone} onClose={() => setBanner(null)}>\n {banner.text}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder={tr('psw.clients.searchPlaceholder', 'Search clients…')}\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: 'client',\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 PswClientStatus | '');\n setPagination({ limit: PAGE_SIZE, offset: 0 });\n }}\n className=\"sm:w-48\"\n >\n <option value=\"\">{tr('psw.clients.allStatuses', 'All statuses')}</option>\n {enumOptions(CLIENT_STATUSES, enumLabel)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title={tr('psw.clients.emptyTitle', 'No clients yet')}\n description={tr(\n 'psw.clients.emptyDescription',\n 'Add your first client to start scoping engagements and matters.'\n )}\n icon={<Users className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> {tr('psw.clients.new', 'New client')}\n </Button>\n }\n />\n ) : (\n <SectionCard\n title={\n data.totalCount === 1\n ? tr('psw.clients.count', '{{count}} client', { count: data.totalCount })\n : tr('psw.clients.countPlural', '{{count}} clients', { count: data.totalCount })\n }\n >\n {/*\n Phones get a tappable card list: the desktop table carries seven\n columns behind a horizontal scroll, which hides the status and the\n row actions on a narrow viewport. Same fields, same affordances.\n */}\n <ul className=\"space-y-2.5 sm:hidden\">\n {data.items.map((c) => (\n <li\n key={c.id}\n className=\"overflow-hidden rounded-xl border border-border-seam bg-bg-canvas\"\n >\n <button\n type=\"button\"\n onClick={() => {\n void impactFeedback('light');\n nav(`clients/${c.id}`);\n }}\n className=\"flex w-full items-center gap-3 p-3.5 text-left transition-colors active:bg-bg-sunken/60\"\n >\n <Avatar name={c.name} className=\"h-11 w-11 text-sm\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-semibold text-text-primary\">\n {c.name}\n </span>\n <span className=\"mt-0.5 block truncate text-sm text-text-secondary\">\n {c.contactName ||\n (c.type === 'ORGANIZATION'\n ? tr('psw.clients.typeOrganization', 'Organization')\n : tr('psw.clients.typeIndividual', 'Individual'))}\n </span>\n <span className=\"mt-1.5 flex items-center gap-2\">\n <span className=\"truncate text-xs text-text-tertiary\">\n {c.industry || fmtDate(c.createdAt)}\n </span>\n <StatusPill status={c.status} />\n </span>\n </span>\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-tertiary\" />\n </button>\n <div className=\"flex items-center justify-between gap-2 border-t border-border-seam px-3.5 py-2\">\n <div className=\"min-w-0 flex-1\">\n <TagPicker\n entityType=\"PswClient\"\n entityId={c.id}\n tags={c.tags ?? []}\n onChange={async (tags) => {\n await update.mutateAsync({ id: c.id, input: { tags } });\n void refetch();\n }}\n maxTags={5}\n />\n </div>\n <div className=\"flex shrink-0 gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setEditing(c)}\n aria-label={tr('psw.common.edit', 'Edit')}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n {c.status !== 'ARCHIVED' && (\n <ArchiveButton\n id={c.id}\n name={c.name}\n onDone={(ok) =>\n setBanner(\n ok\n ? {\n tone: 'success',\n text: tr('psw.clients.archived', '{{name}} archived.', {\n name: c.name,\n }),\n }\n : {\n tone: 'danger',\n text: tr(\n 'psw.clients.archiveFailed',\n 'Could not archive client.'\n ),\n }\n )\n }\n />\n )}\n </div>\n </div>\n </li>\n ))}\n </ul>\n\n <div className=\"hidden sm:block\">\n <TableWrap>\n <thead>\n <tr>\n <Th>{tr('psw.common.name', 'Name')}</Th>\n <Th>{tr('psw.common.type', 'Type')}</Th>\n <Th>{tr('psw.clients.tableIndustry', 'Industry')}</Th>\n <Th>{tr('psw.common.status', 'Status')}</Th>\n <Th>{tr('psw.common.added', 'Added')}</Th>\n <Th>{tr('psw.clients.tableTags', 'Tags')}</Th>\n <Th className=\"text-right\">{tr('psw.common.actions', 'Actions')}</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((c) => (\n <tr\n key={c.id}\n className=\"group cursor-pointer transition-colors hover:bg-bg-sunken/60\"\n onClick={() => nav(`clients/${c.id}`)}\n >\n <Td>\n <div className=\"flex items-center gap-3\">\n <Avatar name={c.name} />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1 font-medium text-text-primary transition-colors group-hover:text-accent\">\n <span className=\"truncate\">{c.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 {c.contactName ? (\n <div className=\"truncate text-xs text-text-tertiary\">\n {c.contactName}\n </div>\n ) : null}\n </div>\n </div>\n </Td>\n <Td>\n <span className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n {c.type === 'ORGANIZATION' ? (\n <Building2 className=\"h-3.5 w-3.5 text-text-tertiary\" />\n ) : (\n <User className=\"h-3.5 w-3.5 text-text-tertiary\" />\n )}\n {c.type === 'ORGANIZATION'\n ? tr('psw.clients.typeOrganization', 'Organization')\n : tr('psw.clients.typeIndividual', 'Individual')}\n </span>\n </Td>\n <Td>{c.industry || tr('psw.common.dash', '—')}</Td>\n <Td>\n <StatusPill status={c.status} />\n </Td>\n <Td className=\"whitespace-nowrap\">{fmtDate(c.createdAt)}</Td>\n <Td>\n <div onClick={(ev) => ev.stopPropagation()} role=\"presentation\">\n <TagPicker\n entityType=\"PswClient\"\n entityId={c.id}\n tags={c.tags ?? []}\n onChange={async (tags) => {\n await update.mutateAsync({ id: c.id, input: { tags } });\n void refetch();\n }}\n maxTags={5}\n />\n </div>\n </Td>\n <Td className=\"text-right\">\n <div\n className=\"flex justify-end gap-1\"\n onClick={(ev) => ev.stopPropagation()}\n role=\"presentation\"\n >\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setEditing(c)}\n aria-label={tr('psw.common.edit', 'Edit')}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n {c.status !== 'ARCHIVED' && (\n <ArchiveButton\n id={c.id}\n name={c.name}\n onDone={(ok) =>\n setBanner(\n ok\n ? {\n tone: 'success',\n text: tr('psw.clients.archived', '{{name}} archived.', {\n name: c.name,\n }),\n }\n : {\n tone: 'danger',\n text: tr(\n 'psw.clients.archiveFailed',\n 'Could not archive client.'\n ),\n }\n )\n }\n />\n )}\n </div>\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </div>\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 <ClientModal\n onClose={() => setCreating(false)}\n onSaved={(name) =>\n setBanner({\n tone: 'success',\n text: tr('psw.clients.created', '{{name}} created.', { name }),\n })\n }\n />\n )}\n {editing && (\n <ClientModal\n client={editing}\n onClose={() => setEditing(null)}\n onSaved={(name) =>\n setBanner({\n tone: 'success',\n text: tr('psw.clients.updated', '{{name}} updated.', { name }),\n })\n }\n />\n )}\n </div>\n );\n};\n\nconst ArchiveButton: FC<{ id: string; name: string; onDone: (ok: boolean) => void }> = ({\n id,\n name,\n onDone,\n}) => {\n const archive = useArchiveClient();\n const tr = useTr();\n const { emitFact } = useAnalytics();\n return (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={tr('psw.common.archive', 'Archive')}\n disabled={archive.isPending}\n onClick={() => {\n if (\n !window.confirm(\n tr(\n 'psw.clients.archiveConfirm',\n 'Archive this client? Their engagements and matters remain.'\n )\n )\n )\n return;\n archive.mutate(id, {\n onSuccess: (r) => {\n emitFact('psw.client.archived', { clientId: id });\n onDone(Boolean(r));\n },\n onError: () => onDone(false),\n });\n }}\n >\n <Archive className=\"h-4 w-4\" />\n </Button>\n );\n};\n\nconst ClientModal: FC<{\n client?: PswClient;\n onClose: () => void;\n onSaved: (name: string) => void;\n}> = ({ client, onClose, onSaved }) => {\n const tr = useTr();\n const enumLabel = useEnumLabel();\n const create = useCreateClient();\n const update = useUpdateClient();\n const { emitFact } = useAnalytics();\n const [form, setForm] = useState<FormState>(\n client\n ? {\n name: client.name,\n type: client.type,\n status: client.status,\n industry: client.industry ?? '',\n contactName: client.contactName ?? '',\n contactEmail: client.contactEmail ?? '',\n contactPhone: client.contactPhone ?? '',\n notes: client.notes ?? '',\n }\n : emptyForm\n );\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof FormState) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n const pending = create.isPending || update.isPending;\n\n const payload = useMemo(\n () => ({\n name: form.name.trim(),\n type: form.type,\n status: form.status,\n industry: form.industry.trim() || null,\n contactName: form.contactName.trim() || null,\n contactEmail: form.contactEmail.trim() || null,\n contactPhone: form.contactPhone.trim() || null,\n notes: form.notes.trim() || null,\n }),\n [form]\n );\n\n const submit = () => {\n setErr(null);\n if (!payload.name) return setErr(tr('psw.clients.nameRequired', 'Client name is required.'));\n const onError = (e: unknown) =>\n setErr(e instanceof Error ? e.message : tr('psw.clients.saveFailed', 'Save failed.'));\n if (client) {\n update.mutate(\n { id: client.id, input: payload },\n {\n onSuccess: () => {\n emitFact('psw.client.updated', { clientId: client.id });\n onSaved(payload.name);\n onClose();\n },\n onError,\n }\n );\n } else {\n create.mutate(payload, {\n onSuccess: (created) => {\n emitFact('psw.client.created', { clientId: created.pswCreateClient.id });\n onSaved(payload.name);\n onClose();\n },\n onError,\n });\n }\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title={\n client ? tr('psw.clients.edit', 'Edit client') : tr('psw.clients.newTitle', 'New client')\n }\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={pending}>\n {tr('psw.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submit} disabled={pending}>\n {pending\n ? tr('psw.common.saving', 'Saving…')\n : client\n ? tr('psw.clients.saveChanges', 'Save changes')\n : tr('psw.clients.create', 'Create client')}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label={tr('psw.common.name', 'Name')} required>\n <TextInput value={form.name} onChange={set('name')} placeholder=\"Acme Holdings Ltd.\" />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label={tr('psw.common.type', 'Type')}>\n <NativeSelect value={form.type} onChange={set('type')}>\n {enumOptions(CLIENT_TYPES, enumLabel)}\n </NativeSelect>\n </Field>\n <Field label={tr('psw.common.status', 'Status')}>\n <NativeSelect value={form.status} onChange={set('status')}>\n {enumOptions(CLIENT_STATUSES, enumLabel)}\n </NativeSelect>\n </Field>\n </div>\n <Field label={tr('psw.clients.industry', 'Industry')}>\n <TextInput\n value={form.industry}\n onChange={set('industry')}\n placeholder=\"Financial services\"\n />\n </Field>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <Field label={tr('psw.clients.contactName', 'Contact name')}>\n <TextInput value={form.contactName} onChange={set('contactName')} />\n </Field>\n <Field label={tr('psw.clients.contactEmail', 'Contact email')}>\n <TextInput type=\"email\" value={form.contactEmail} onChange={set('contactEmail')} />\n </Field>\n </div>\n <Field label={tr('psw.clients.contactPhone', 'Contact phone')}>\n <TextInput value={form.contactPhone} onChange={set('contactPhone')} />\n </Field>\n <Field label={tr('psw.clients.notes', '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":"CompliancePage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/CompliancePage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAa,MAAM,OAAO,CAAC;AAsE3C,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"CompliancePage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/CompliancePage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAa,MAAM,OAAO,CAAC;AAsE3C,eAAO,MAAM,cAAc,EAAE,EA2M5B,CAAC"}
|