@burdenoff/microfe-proserviceworld 2026.706.2 → 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.
Files changed (108) hide show
  1. package/dist/dev/main.d.ts +2 -0
  2. package/dist/dev/main.d.ts.map +1 -0
  3. package/dist/generated/global-operations.d.ts +2 -0
  4. package/dist/generated/global-operations.d.ts.map +1 -0
  5. package/dist/generated/global-types.d.ts +18199 -0
  6. package/dist/generated/global-types.d.ts.map +1 -0
  7. package/dist/generated/wspace-operations.d.ts +2 -0
  8. package/dist/generated/wspace-operations.d.ts.map +1 -0
  9. package/dist/generated/wspace-types.d.ts +43046 -0
  10. package/dist/generated/wspace-types.d.ts.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +2 -1
  14. package/dist/proserviceworld/ProServiceWorldRoot.d.ts +5 -0
  15. package/dist/proserviceworld/ProServiceWorldRoot.d.ts.map +1 -0
  16. package/dist/proserviceworld/ProServiceWorldRoutes.d.ts +2 -0
  17. package/dist/proserviceworld/ProServiceWorldRoutes.d.ts.map +1 -0
  18. package/dist/proserviceworld/components/DiscussionThread.d.ts +12 -0
  19. package/dist/proserviceworld/components/DiscussionThread.d.ts.map +1 -0
  20. package/dist/proserviceworld/components/DiscussionThread.js +1 -1
  21. package/dist/proserviceworld/components/DiscussionThread.js.map +1 -1
  22. package/dist/proserviceworld/components/ui.d.ts +82 -0
  23. package/dist/proserviceworld/components/ui.d.ts.map +1 -0
  24. package/dist/proserviceworld/components/ui.js +18 -18
  25. package/dist/proserviceworld/components/ui.js.map +1 -1
  26. package/dist/proserviceworld/hooks/useAnalytics.d.ts +18 -0
  27. package/dist/proserviceworld/hooks/useAnalytics.d.ts.map +1 -0
  28. package/dist/proserviceworld/hooks/useAnalytics.js +21 -0
  29. package/dist/proserviceworld/hooks/useAnalytics.js.map +1 -0
  30. package/dist/proserviceworld/hooks/useEntityComments.d.ts +27 -0
  31. package/dist/proserviceworld/hooks/useEntityComments.d.ts.map +1 -0
  32. package/dist/proserviceworld/hooks/useEntityComments.js.map +1 -1
  33. package/dist/proserviceworld/hooks/useFiles.d.ts +23 -0
  34. package/dist/proserviceworld/hooks/useFiles.d.ts.map +1 -0
  35. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +351 -0
  36. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -0
  37. package/dist/proserviceworld/index.d.ts +5 -0
  38. package/dist/proserviceworld/index.d.ts.map +1 -0
  39. package/dist/proserviceworld/index.js +1 -0
  40. package/dist/proserviceworld/pages/AnalyticsPage.d.ts +4 -0
  41. package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -0
  42. package/dist/proserviceworld/pages/AnalyticsPage.js +277 -111
  43. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  44. package/dist/proserviceworld/pages/ClientDetailPage.d.ts +4 -0
  45. package/dist/proserviceworld/pages/ClientDetailPage.d.ts.map +1 -0
  46. package/dist/proserviceworld/pages/ClientDetailPage.js +219 -151
  47. package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
  48. package/dist/proserviceworld/pages/ClientsPage.d.ts +9 -0
  49. package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -0
  50. package/dist/proserviceworld/pages/ClientsPage.js +180 -148
  51. package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
  52. package/dist/proserviceworld/pages/CompliancePage.d.ts +4 -0
  53. package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -0
  54. package/dist/proserviceworld/pages/CompliancePage.js +140 -96
  55. package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
  56. package/dist/proserviceworld/pages/ConflictsPage.d.ts +4 -0
  57. package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -0
  58. package/dist/proserviceworld/pages/DashboardPage.d.ts +4 -0
  59. package/dist/proserviceworld/pages/DashboardPage.d.ts.map +1 -0
  60. package/dist/proserviceworld/pages/DashboardPage.js +221 -104
  61. package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
  62. package/dist/proserviceworld/pages/DocumentsPage.d.ts +4 -0
  63. package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -0
  64. package/dist/proserviceworld/pages/EngagementDetailPage.d.ts +4 -0
  65. package/dist/proserviceworld/pages/EngagementDetailPage.d.ts.map +1 -0
  66. package/dist/proserviceworld/pages/EngagementDetailPage.js +233 -197
  67. package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
  68. package/dist/proserviceworld/pages/EngagementsPage.d.ts +4 -0
  69. package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -0
  70. package/dist/proserviceworld/pages/EngagementsPage.js +187 -136
  71. package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
  72. package/dist/proserviceworld/pages/InvoicesPage.d.ts +4 -0
  73. package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -0
  74. package/dist/proserviceworld/pages/InvoicesPage.js +144 -129
  75. package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
  76. package/dist/proserviceworld/pages/MattersPage.d.ts +4 -0
  77. package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -0
  78. package/dist/proserviceworld/pages/MattersPage.js +198 -142
  79. package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
  80. package/dist/proserviceworld/pages/PracticeAreasPage.d.ts +4 -0
  81. package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -0
  82. package/dist/proserviceworld/pages/TimePage.d.ts +4 -0
  83. package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -0
  84. package/dist/proserviceworld/pages/TimePage.js +112 -92
  85. package/dist/proserviceworld/pages/TimePage.js.map +1 -1
  86. package/dist/proserviceworld/providers/ProServiceWorldProvider.d.ts +6 -0
  87. package/dist/proserviceworld/providers/ProServiceWorldProvider.d.ts.map +1 -0
  88. package/dist/proserviceworld/services/assistantApi.d.ts +74 -0
  89. package/dist/proserviceworld/services/assistantApi.d.ts.map +1 -0
  90. package/dist/proserviceworld/services/assistantApi.js +203 -0
  91. package/dist/proserviceworld/services/assistantApi.js.map +1 -0
  92. package/dist/proserviceworld/services/createSandboxAssistantTransport.d.ts +28 -0
  93. package/dist/proserviceworld/services/createSandboxAssistantTransport.d.ts.map +1 -0
  94. package/dist/proserviceworld/services/createSandboxAssistantTransport.js +120 -0
  95. package/dist/proserviceworld/services/createSandboxAssistantTransport.js.map +1 -0
  96. package/dist/proserviceworld/types/index.d.ts +57 -0
  97. package/dist/proserviceworld/types/index.d.ts.map +1 -0
  98. package/dist/proserviceworld/utils/cn.d.ts +4 -0
  99. package/dist/proserviceworld/utils/cn.d.ts.map +1 -0
  100. package/dist/proserviceworld/utils/nav.d.ts +6 -0
  101. package/dist/proserviceworld/utils/nav.d.ts.map +1 -0
  102. package/dist/proserviceworld/utils/navigation.d.ts +2 -0
  103. package/dist/proserviceworld/utils/navigation.d.ts.map +1 -0
  104. package/dist/proserviceworld/utils/pageContext.d.ts +12 -0
  105. package/dist/proserviceworld/utils/pageContext.d.ts.map +1 -0
  106. package/dist/proserviceworld/utils/pageContext.js +74 -0
  107. package/dist/proserviceworld/utils/pageContext.js.map +1 -0
  108. 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 } 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} 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\nexport const EngagementsPage: FC = () => {\n const nav = useNav();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswEngagementStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<string | null>(null);\n const { data, isLoading, error, refetch } = useEngagements({\n search: search.trim() || undefined,\n status: statusFilter || 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-52\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title=\"No 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=\"cursor-pointer hover:bg-bg-sunken/50\"\n onClick={() => nav(`engagements/${e.id}`)}\n >\n <Td>\n <span className=\"font-medium text-text-primary\">{e.name}</span>\n </Td>\n <Td>{e.client?.name ?? '—'}</Td>\n <Td>\n {fmtMoney(e.feeAmount, e.currency)}{' '}\n <span className=\"text-xs text-text-tertiary\">\n / {e.feeArrangement.toLowerCase()}\n </span>\n </Td>\n <Td>\n <StatusPill status={e.status} />\n </Td>\n <Td>{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,4 @@
1
+ import { FC } from 'react';
2
+
3
+ export declare const InvoicesPage: FC;
4
+ //# sourceMappingURL=InvoicesPage.d.ts.map
@@ -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"}
@@ -1,133 +1,148 @@
1
1
  import { useClients as e, useCreateInvoice as t, useEngagements as n, useInvoices as r, useMarkInvoicePaid as i } from "../hooks/useProServiceWorldApi.js";
2
- import { Banner as a, Empty as o, ErrorState as s, Field as c, LoadingBlock as l, MetricCard as u, Modal as d, NativeSelect as f, PageHeader as p, SectionCard as m, StatusPill as h, TableWrap as g, Td as _, TextArea as v, TextInput as y, Th as b, enumOptions as x, fmtDate as S, fmtMoney as C } from "../components/ui.js";
3
- import { useMemo as w, useState as T } from "react";
4
- import { CheckCircle2 as E, Plus as D, Receipt as O } from "lucide-react";
5
- import { Fragment as k, jsx as A, jsxs as j } from "react/jsx-runtime";
6
- import { Button as M } from "@burdenoff/fe-libs/ui";
2
+ import { cn as a } from "../utils/cn.js";
3
+ 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, fmtMoney as w } from "../components/ui.js";
4
+ import { useMemo as T, useState as E } from "react";
5
+ import { AlertCircle as D, CheckCircle2 as O, Plus as k, Receipt as A, Wallet 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/InvoicesPage.tsx
8
- var N = [
9
+ var I = [
9
10
  "DRAFT",
10
11
  "SENT",
11
12
  "PAID",
12
13
  "OVERDUE",
13
14
  "CANCELLED"
14
- ], P = () => {
15
- let [t, n] = T(""), [c, d] = T(!1), [v, y] = T(null), { data: k, isLoading: P, error: I, refetch: L } = r({ status: t || void 0 }), R = i(), z = e({ pagination: { limit: 100 } }), B = w(() => new Map((z.data?.items ?? []).map((e) => [e.id, e.name])), [z.data]), V = (k?.items ?? []).filter((e) => e.status === "SENT" || e.status === "OVERDUE").reduce((e, t) => e + t.total, 0), H = (k?.items ?? []).filter((e) => e.status === "PAID").reduce((e, t) => e + t.total, 0);
16
- return /* @__PURE__ */ j("div", {
15
+ ], L = () => {
16
+ let [t, n] = E(""), [l, f] = E(!1), [y, b] = E(null), { data: M, isLoading: L, error: z, refetch: B } = r({ status: t || void 0 }), V = i(), H = e({ pagination: { limit: 100 } }), U = T(() => new Map((H.data?.items ?? []).map((e) => [e.id, e.name])), [H.data]), W = (M?.items ?? []).filter((e) => e.status === "SENT" || e.status === "OVERDUE"), G = (M?.items ?? []).filter((e) => e.status === "PAID"), K = W.reduce((e, t) => e + t.total, 0), q = G.reduce((e, t) => e + t.total, 0);
17
+ return /* @__PURE__ */ P("div", {
17
18
  className: "space-y-6",
18
19
  children: [
19
- /* @__PURE__ */ A(p, {
20
+ /* @__PURE__ */ N(m, {
20
21
  title: "Invoices",
21
22
  subtitle: "Assemble invoices from time, milestones and fixed-fee schedules — and track what's outstanding.",
22
- icon: /* @__PURE__ */ A(O, { className: "h-6 w-6" }),
23
- actions: /* @__PURE__ */ j(M, {
24
- onClick: () => d(!0),
25
- children: [/* @__PURE__ */ A(D, { className: "mr-1.5 h-4 w-4" }), "New invoice"]
23
+ icon: /* @__PURE__ */ N(A, { className: "h-6 w-6" }),
24
+ actions: /* @__PURE__ */ P(F, {
25
+ onClick: () => f(!0),
26
+ children: [/* @__PURE__ */ N(k, { className: "mr-1.5 h-4 w-4" }), "New invoice"]
26
27
  })
27
28
  }),
28
- v && /* @__PURE__ */ A(a, {
29
- tone: v.tone,
30
- onClose: () => y(null),
31
- children: v.text
29
+ y && /* @__PURE__ */ N(o, {
30
+ tone: y.tone,
31
+ onClose: () => b(null),
32
+ children: y.text
32
33
  }),
33
- /* @__PURE__ */ j("div", {
34
- className: "grid grid-cols-3 gap-3",
34
+ /* @__PURE__ */ P("div", {
35
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-3",
35
36
  children: [
36
- /* @__PURE__ */ A(u, {
37
+ /* @__PURE__ */ N(d, {
37
38
  label: "Invoices",
38
- value: k?.totalCount ?? 0
39
+ value: M?.totalCount ?? 0,
40
+ icon: /* @__PURE__ */ N(A, { className: "h-4 w-4" })
39
41
  }),
40
- /* @__PURE__ */ A(u, {
42
+ /* @__PURE__ */ N(d, {
41
43
  label: "Outstanding",
42
- value: C(V),
44
+ value: w(K),
45
+ hint: `${W.length} sent + overdue`,
46
+ icon: /* @__PURE__ */ N(D, { className: "h-4 w-4" }),
43
47
  tone: "warning"
44
48
  }),
45
- /* @__PURE__ */ A(u, {
49
+ /* @__PURE__ */ N(d, {
46
50
  label: "Collected",
47
- value: C(H),
51
+ value: w(q),
52
+ hint: `${G.length} paid`,
53
+ icon: /* @__PURE__ */ N(j, { className: "h-4 w-4" }),
48
54
  tone: "success"
49
55
  })
50
56
  ]
51
57
  }),
52
- /* @__PURE__ */ A("div", {
58
+ /* @__PURE__ */ N("div", {
53
59
  className: "flex justify-end",
54
- children: /* @__PURE__ */ j(f, {
60
+ children: /* @__PURE__ */ P(p, {
55
61
  value: t,
56
62
  onChange: (e) => n(e.target.value),
57
63
  className: "sm:w-48",
58
- children: [/* @__PURE__ */ A("option", {
64
+ children: [/* @__PURE__ */ N("option", {
59
65
  value: "",
60
66
  children: "All statuses"
61
- }), x(N)]
67
+ }), S(I)]
62
68
  })
63
69
  }),
64
- P ? /* @__PURE__ */ A(l, {}) : I ? /* @__PURE__ */ A(s, {
65
- error: I,
66
- onRetry: () => void L()
67
- }) : !k || k.items.length === 0 ? /* @__PURE__ */ A(o, {
70
+ L ? /* @__PURE__ */ N(u, {}) : z ? /* @__PURE__ */ N(c, {
71
+ error: z,
72
+ onRetry: () => void B()
73
+ }) : !M || M.items.length === 0 ? /* @__PURE__ */ N(s, {
68
74
  title: "No invoices yet",
69
75
  description: "Raise an invoice for a client to start tracking receivables.",
70
- icon: /* @__PURE__ */ A(O, { className: "h-8 w-8" }),
71
- action: /* @__PURE__ */ j(M, {
72
- onClick: () => d(!0),
73
- children: [/* @__PURE__ */ A(D, { className: "mr-1.5 h-4 w-4" }), "New invoice"]
76
+ icon: /* @__PURE__ */ N(A, { className: "h-8 w-8" }),
77
+ action: /* @__PURE__ */ P(F, {
78
+ onClick: () => f(!0),
79
+ children: [/* @__PURE__ */ N(k, { className: "mr-1.5 h-4 w-4" }), "New invoice"]
74
80
  })
75
- }) : /* @__PURE__ */ A(m, {
81
+ }) : /* @__PURE__ */ N(h, {
76
82
  title: "Invoices",
77
- children: /* @__PURE__ */ j(g, { children: [/* @__PURE__ */ A("thead", { children: /* @__PURE__ */ j("tr", { children: [
78
- /* @__PURE__ */ A(b, { children: "Number" }),
79
- /* @__PURE__ */ A(b, { children: "Client" }),
80
- /* @__PURE__ */ A(b, { children: "Total" }),
81
- /* @__PURE__ */ A(b, { children: "Status" }),
82
- /* @__PURE__ */ A(b, { children: "Due" }),
83
- /* @__PURE__ */ A(b, {
83
+ children: /* @__PURE__ */ P(_, { children: [/* @__PURE__ */ N("thead", { children: /* @__PURE__ */ P("tr", { children: [
84
+ /* @__PURE__ */ N(x, { children: "Number" }),
85
+ /* @__PURE__ */ N(x, { children: "Client" }),
86
+ /* @__PURE__ */ N(x, { children: "Total" }),
87
+ /* @__PURE__ */ N(x, { children: "Status" }),
88
+ /* @__PURE__ */ N(x, { children: "Due" }),
89
+ /* @__PURE__ */ N(x, {
84
90
  className: "text-right",
85
91
  children: "Actions"
86
92
  })
87
- ] }) }), /* @__PURE__ */ A("tbody", { children: k.items.map((e) => /* @__PURE__ */ j("tr", {
88
- className: "hover:bg-bg-sunken/50",
93
+ ] }) }), /* @__PURE__ */ N("tbody", { children: M.items.map((e) => /* @__PURE__ */ P("tr", {
94
+ className: "transition-colors hover:bg-bg-sunken/60",
89
95
  children: [
90
- /* @__PURE__ */ A(_, { children: /* @__PURE__ */ A("span", {
96
+ /* @__PURE__ */ N(v, { children: /* @__PURE__ */ N("span", {
91
97
  className: "font-medium text-text-primary",
92
98
  children: e.number
93
99
  }) }),
94
- /* @__PURE__ */ A(_, { children: B.get(e.clientId) ?? "—" }),
95
- /* @__PURE__ */ A(_, { children: C(e.total, e.currency) }),
96
- /* @__PURE__ */ A(_, { children: /* @__PURE__ */ A(h, { status: e.status }) }),
97
- /* @__PURE__ */ A(_, { children: S(e.dueDate) }),
98
- /* @__PURE__ */ A(_, {
100
+ /* @__PURE__ */ N(v, {
101
+ className: "text-text-primary",
102
+ children: U.get(e.clientId) ?? "—"
103
+ }),
104
+ /* @__PURE__ */ N(v, {
105
+ className: "whitespace-nowrap font-semibold text-text-primary",
106
+ children: w(e.total, e.currency)
107
+ }),
108
+ /* @__PURE__ */ N(v, { children: /* @__PURE__ */ N(g, { status: e.status }) }),
109
+ /* @__PURE__ */ N(v, {
110
+ className: a("whitespace-nowrap", e.status === "OVERDUE" && "font-medium text-status-error-text"),
111
+ children: C(e.dueDate)
112
+ }),
113
+ /* @__PURE__ */ N(v, {
99
114
  className: "text-right",
100
- children: e.status !== "PAID" && e.status !== "CANCELLED" && /* @__PURE__ */ j(M, {
115
+ children: e.status !== "PAID" && e.status !== "CANCELLED" && /* @__PURE__ */ P(F, {
101
116
  variant: "ghost",
102
117
  size: "sm",
103
- disabled: R.isPending,
104
- onClick: () => R.mutate(e.id, {
105
- onSuccess: () => y({
118
+ disabled: V.isPending,
119
+ onClick: () => V.mutate(e.id, {
120
+ onSuccess: () => b({
106
121
  tone: "success",
107
122
  text: `${e.number} marked paid.`
108
123
  }),
109
- onError: (e) => y({
124
+ onError: (e) => b({
110
125
  tone: "danger",
111
126
  text: e instanceof Error ? e.message : "Failed."
112
127
  })
113
128
  }),
114
- children: [/* @__PURE__ */ A(E, { className: "mr-1 h-4 w-4" }), "Mark paid"]
129
+ children: [/* @__PURE__ */ N(O, { className: "mr-1 h-4 w-4" }), "Mark paid"]
115
130
  })
116
131
  })
117
132
  ]
118
133
  }, e.id)) })] })
119
134
  }),
120
- c && /* @__PURE__ */ A(F, {
121
- onClose: () => d(!1),
122
- onSaved: (e) => y({
135
+ l && /* @__PURE__ */ N(R, {
136
+ onClose: () => f(!1),
137
+ onSaved: (e) => b({
123
138
  tone: "success",
124
139
  text: `${e} created.`
125
140
  })
126
141
  })
127
142
  ]
128
143
  });
129
- }, F = ({ onClose: r, onSaved: i }) => {
130
- let o = t(), s = e({ pagination: { limit: 100 } }), [l, u] = T({
144
+ }, R = ({ onClose: r, onSaved: i }) => {
145
+ let a = t(), s = e({ pagination: { limit: 100 } }), [c, u] = E({
131
146
  clientId: "",
132
147
  engagementId: "",
133
148
  number: "",
@@ -137,159 +152,159 @@ var N = [
137
152
  issueDate: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
138
153
  dueDate: "",
139
154
  notes: ""
140
- }), [p, m] = T(null), h = n({
141
- clientId: l.clientId || void 0,
155
+ }), [d, m] = E(null), h = n({
156
+ clientId: c.clientId || void 0,
142
157
  pagination: { limit: 100 }
143
158
  }), g = (e) => (t) => u((n) => ({
144
159
  ...n,
145
160
  [e]: t.target.value
146
- })), _ = (Number(l.subtotal) || 0) + (Number(l.taxAmount) || 0);
147
- return /* @__PURE__ */ A(d, {
161
+ })), _ = (Number(c.subtotal) || 0) + (Number(c.taxAmount) || 0);
162
+ return /* @__PURE__ */ N(f, {
148
163
  open: !0,
149
164
  onClose: r,
150
165
  title: "New invoice",
151
- footer: /* @__PURE__ */ j(k, { children: [/* @__PURE__ */ A(M, {
166
+ footer: /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ N(F, {
152
167
  variant: "outline",
153
168
  onClick: r,
154
- disabled: o.isPending,
169
+ disabled: a.isPending,
155
170
  children: "Cancel"
156
- }), /* @__PURE__ */ A(M, {
171
+ }), /* @__PURE__ */ N(F, {
157
172
  onClick: () => {
158
- if (m(null), !l.clientId) return m("Select a client.");
159
- if (!l.number.trim()) return m("Invoice number is required.");
160
- o.mutate({
161
- clientId: l.clientId,
162
- engagementId: l.engagementId || null,
163
- number: l.number.trim(),
164
- currency: l.currency || "USD",
165
- subtotal: Number(l.subtotal) || 0,
166
- taxAmount: Number(l.taxAmount) || 0,
173
+ if (m(null), !c.clientId) return m("Select a client.");
174
+ if (!c.number.trim()) return m("Invoice number is required.");
175
+ a.mutate({
176
+ clientId: c.clientId,
177
+ engagementId: c.engagementId || null,
178
+ number: c.number.trim(),
179
+ currency: c.currency || "USD",
180
+ subtotal: Number(c.subtotal) || 0,
181
+ taxAmount: Number(c.taxAmount) || 0,
167
182
  total: _,
168
- issueDate: l.issueDate ? new Date(l.issueDate).toISOString() : null,
169
- dueDate: l.dueDate ? new Date(l.dueDate).toISOString() : null,
170
- notes: l.notes.trim() || null
183
+ issueDate: c.issueDate ? new Date(c.issueDate).toISOString() : null,
184
+ dueDate: c.dueDate ? new Date(c.dueDate).toISOString() : null,
185
+ notes: c.notes.trim() || null
171
186
  }, {
172
187
  onSuccess: () => {
173
- i(l.number.trim()), r();
188
+ i(c.number.trim()), r();
174
189
  },
175
190
  onError: (e) => m(e instanceof Error ? e.message : "Failed.")
176
191
  });
177
192
  },
178
- disabled: o.isPending,
179
- children: o.isPending ? "Creating…" : "Create invoice"
193
+ disabled: a.isPending,
194
+ children: a.isPending ? "Creating…" : "Create invoice"
180
195
  })] }),
181
- children: /* @__PURE__ */ j("div", {
196
+ children: /* @__PURE__ */ P("div", {
182
197
  className: "space-y-3",
183
198
  children: [
184
- p && /* @__PURE__ */ A(a, {
199
+ d && /* @__PURE__ */ N(o, {
185
200
  tone: "danger",
186
- children: p
201
+ children: d
187
202
  }),
188
- /* @__PURE__ */ j("div", {
203
+ /* @__PURE__ */ P("div", {
189
204
  className: "grid grid-cols-2 gap-3",
190
- children: [/* @__PURE__ */ A(c, {
205
+ children: [/* @__PURE__ */ N(l, {
191
206
  label: "Client",
192
207
  required: !0,
193
- children: /* @__PURE__ */ j(f, {
194
- value: l.clientId,
208
+ children: /* @__PURE__ */ P(p, {
209
+ value: c.clientId,
195
210
  onChange: g("clientId"),
196
- children: [/* @__PURE__ */ A("option", {
211
+ children: [/* @__PURE__ */ N("option", {
197
212
  value: "",
198
213
  children: "Select…"
199
- }), s.data?.items.map((e) => /* @__PURE__ */ A("option", {
214
+ }), s.data?.items.map((e) => /* @__PURE__ */ N("option", {
200
215
  value: e.id,
201
216
  children: e.name
202
217
  }, e.id))]
203
218
  })
204
- }), /* @__PURE__ */ A(c, {
219
+ }), /* @__PURE__ */ N(l, {
205
220
  label: "Number",
206
221
  required: !0,
207
- children: /* @__PURE__ */ A(y, {
208
- value: l.number,
222
+ children: /* @__PURE__ */ N(b, {
223
+ value: c.number,
209
224
  onChange: g("number"),
210
225
  placeholder: "INV-2026-014"
211
226
  })
212
227
  })]
213
228
  }),
214
- /* @__PURE__ */ A(c, {
229
+ /* @__PURE__ */ N(l, {
215
230
  label: "Engagement (optional)",
216
- children: /* @__PURE__ */ j(f, {
217
- value: l.engagementId,
231
+ children: /* @__PURE__ */ P(p, {
232
+ value: c.engagementId,
218
233
  onChange: g("engagementId"),
219
- disabled: !l.clientId,
220
- children: [/* @__PURE__ */ A("option", {
234
+ disabled: !c.clientId,
235
+ children: [/* @__PURE__ */ N("option", {
221
236
  value: "",
222
237
  children: "None"
223
- }), h.data?.items.map((e) => /* @__PURE__ */ A("option", {
238
+ }), h.data?.items.map((e) => /* @__PURE__ */ N("option", {
224
239
  value: e.id,
225
240
  children: e.name
226
241
  }, e.id))]
227
242
  })
228
243
  }),
229
- /* @__PURE__ */ j("div", {
244
+ /* @__PURE__ */ P("div", {
230
245
  className: "grid grid-cols-3 gap-3",
231
246
  children: [
232
- /* @__PURE__ */ A(c, {
247
+ /* @__PURE__ */ N(l, {
233
248
  label: "Subtotal",
234
- children: /* @__PURE__ */ A(y, {
249
+ children: /* @__PURE__ */ N(b, {
235
250
  type: "number",
236
251
  min: "0",
237
- value: l.subtotal,
252
+ value: c.subtotal,
238
253
  onChange: g("subtotal")
239
254
  })
240
255
  }),
241
- /* @__PURE__ */ A(c, {
256
+ /* @__PURE__ */ N(l, {
242
257
  label: "Tax",
243
- children: /* @__PURE__ */ A(y, {
258
+ children: /* @__PURE__ */ N(b, {
244
259
  type: "number",
245
260
  min: "0",
246
- value: l.taxAmount,
261
+ value: c.taxAmount,
247
262
  onChange: g("taxAmount")
248
263
  })
249
264
  }),
250
- /* @__PURE__ */ A(c, {
265
+ /* @__PURE__ */ N(l, {
251
266
  label: "Currency",
252
- children: /* @__PURE__ */ A(y, {
253
- value: l.currency,
267
+ children: /* @__PURE__ */ N(b, {
268
+ value: c.currency,
254
269
  onChange: g("currency"),
255
270
  maxLength: 3
256
271
  })
257
272
  })
258
273
  ]
259
274
  }),
260
- /* @__PURE__ */ j("div", {
275
+ /* @__PURE__ */ P("div", {
261
276
  className: "rounded-lg bg-bg-sunken px-3 py-2 text-sm text-text-secondary",
262
277
  children: [
263
278
  "Total:",
264
279
  " ",
265
- /* @__PURE__ */ A("span", {
280
+ /* @__PURE__ */ N("span", {
266
281
  className: "font-semibold text-text-primary",
267
- children: C(_, l.currency)
282
+ children: w(_, c.currency)
268
283
  })
269
284
  ]
270
285
  }),
271
- /* @__PURE__ */ j("div", {
286
+ /* @__PURE__ */ P("div", {
272
287
  className: "grid grid-cols-2 gap-3",
273
- children: [/* @__PURE__ */ A(c, {
288
+ children: [/* @__PURE__ */ N(l, {
274
289
  label: "Issue date",
275
- children: /* @__PURE__ */ A(y, {
290
+ children: /* @__PURE__ */ N(b, {
276
291
  type: "date",
277
- value: l.issueDate,
292
+ value: c.issueDate,
278
293
  onChange: g("issueDate")
279
294
  })
280
- }), /* @__PURE__ */ A(c, {
295
+ }), /* @__PURE__ */ N(l, {
281
296
  label: "Due date",
282
- children: /* @__PURE__ */ A(y, {
297
+ children: /* @__PURE__ */ N(b, {
283
298
  type: "date",
284
- value: l.dueDate,
299
+ value: c.dueDate,
285
300
  onChange: g("dueDate")
286
301
  })
287
302
  })]
288
303
  }),
289
- /* @__PURE__ */ A(c, {
304
+ /* @__PURE__ */ N(l, {
290
305
  label: "Notes",
291
- children: /* @__PURE__ */ A(v, {
292
- value: l.notes,
306
+ children: /* @__PURE__ */ N(y, {
307
+ value: c.notes,
293
308
  onChange: g("notes")
294
309
  })
295
310
  })
@@ -298,6 +313,6 @@ var N = [
298
313
  });
299
314
  };
300
315
  //#endregion
301
- export { P as InvoicesPage };
316
+ export { L as InvoicesPage };
302
317
 
303
318
  //# sourceMappingURL=InvoicesPage.js.map