@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.
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +18199 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +43046 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -1
- package/dist/proserviceworld/ProServiceWorldRoot.d.ts +5 -0
- package/dist/proserviceworld/ProServiceWorldRoot.d.ts.map +1 -0
- package/dist/proserviceworld/ProServiceWorldRoutes.d.ts +2 -0
- package/dist/proserviceworld/ProServiceWorldRoutes.d.ts.map +1 -0
- package/dist/proserviceworld/components/DiscussionThread.d.ts +12 -0
- package/dist/proserviceworld/components/DiscussionThread.d.ts.map +1 -0
- package/dist/proserviceworld/components/DiscussionThread.js +1 -1
- package/dist/proserviceworld/components/DiscussionThread.js.map +1 -1
- package/dist/proserviceworld/components/ui.d.ts +82 -0
- package/dist/proserviceworld/components/ui.d.ts.map +1 -0
- package/dist/proserviceworld/components/ui.js +18 -18
- package/dist/proserviceworld/components/ui.js.map +1 -1
- package/dist/proserviceworld/hooks/useAnalytics.d.ts +18 -0
- package/dist/proserviceworld/hooks/useAnalytics.d.ts.map +1 -0
- package/dist/proserviceworld/hooks/useAnalytics.js +21 -0
- package/dist/proserviceworld/hooks/useAnalytics.js.map +1 -0
- package/dist/proserviceworld/hooks/useEntityComments.d.ts +27 -0
- package/dist/proserviceworld/hooks/useEntityComments.d.ts.map +1 -0
- package/dist/proserviceworld/hooks/useEntityComments.js.map +1 -1
- package/dist/proserviceworld/hooks/useFiles.d.ts +23 -0
- package/dist/proserviceworld/hooks/useFiles.d.ts.map +1 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +351 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -0
- package/dist/proserviceworld/index.d.ts +5 -0
- package/dist/proserviceworld/index.d.ts.map +1 -0
- package/dist/proserviceworld/index.js +1 -0
- package/dist/proserviceworld/pages/AnalyticsPage.d.ts +4 -0
- package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/AnalyticsPage.js +277 -111
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientDetailPage.d.ts +4 -0
- package/dist/proserviceworld/pages/ClientDetailPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/ClientDetailPage.js +219 -151
- package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientsPage.d.ts +9 -0
- package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/ClientsPage.js +180 -148
- package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.d.ts +4 -0
- package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/CompliancePage.js +140 -96
- package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
- package/dist/proserviceworld/pages/ConflictsPage.d.ts +4 -0
- package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/DashboardPage.d.ts +4 -0
- package/dist/proserviceworld/pages/DashboardPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/DashboardPage.js +221 -104
- package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.d.ts +4 -0
- package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/EngagementDetailPage.d.ts +4 -0
- package/dist/proserviceworld/pages/EngagementDetailPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/EngagementDetailPage.js +233 -197
- package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementsPage.d.ts +4 -0
- package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/EngagementsPage.js +187 -136
- package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.d.ts +4 -0
- package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/InvoicesPage.js +144 -129
- package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
- package/dist/proserviceworld/pages/MattersPage.d.ts +4 -0
- package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/MattersPage.js +198 -142
- package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.d.ts +4 -0
- package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/TimePage.d.ts +4 -0
- package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/TimePage.js +112 -92
- package/dist/proserviceworld/pages/TimePage.js.map +1 -1
- package/dist/proserviceworld/providers/ProServiceWorldProvider.d.ts +6 -0
- package/dist/proserviceworld/providers/ProServiceWorldProvider.d.ts.map +1 -0
- package/dist/proserviceworld/services/assistantApi.d.ts +74 -0
- package/dist/proserviceworld/services/assistantApi.d.ts.map +1 -0
- package/dist/proserviceworld/services/assistantApi.js +203 -0
- package/dist/proserviceworld/services/assistantApi.js.map +1 -0
- package/dist/proserviceworld/services/createSandboxAssistantTransport.d.ts +28 -0
- package/dist/proserviceworld/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/proserviceworld/services/createSandboxAssistantTransport.js +120 -0
- package/dist/proserviceworld/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/proserviceworld/types/index.d.ts +57 -0
- package/dist/proserviceworld/types/index.d.ts.map +1 -0
- package/dist/proserviceworld/utils/cn.d.ts +4 -0
- package/dist/proserviceworld/utils/cn.d.ts.map +1 -0
- package/dist/proserviceworld/utils/nav.d.ts +6 -0
- package/dist/proserviceworld/utils/nav.d.ts.map +1 -0
- package/dist/proserviceworld/utils/navigation.d.ts +2 -0
- package/dist/proserviceworld/utils/navigation.d.ts.map +1 -0
- package/dist/proserviceworld/utils/pageContext.d.ts +12 -0
- package/dist/proserviceworld/utils/pageContext.d.ts.map +1 -0
- package/dist/proserviceworld/utils/pageContext.js +74 -0
- package/dist/proserviceworld/utils/pageContext.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EngagementsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/EngagementsPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Plus, Search, Briefcase } 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 @@
|
|
|
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 {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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
|
|
9
|
+
var I = [
|
|
9
10
|
"DRAFT",
|
|
10
11
|
"SENT",
|
|
11
12
|
"PAID",
|
|
12
13
|
"OVERDUE",
|
|
13
14
|
"CANCELLED"
|
|
14
|
-
],
|
|
15
|
-
let [t, n] =
|
|
16
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
23
|
-
actions: /* @__PURE__ */
|
|
24
|
-
onClick: () =>
|
|
25
|
-
children: [/* @__PURE__ */
|
|
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
|
-
|
|
29
|
-
tone:
|
|
30
|
-
onClose: () =>
|
|
31
|
-
children:
|
|
29
|
+
y && /* @__PURE__ */ N(o, {
|
|
30
|
+
tone: y.tone,
|
|
31
|
+
onClose: () => b(null),
|
|
32
|
+
children: y.text
|
|
32
33
|
}),
|
|
33
|
-
/* @__PURE__ */
|
|
34
|
-
className: "grid grid-cols-
|
|
34
|
+
/* @__PURE__ */ P("div", {
|
|
35
|
+
className: "grid grid-cols-1 gap-3 sm:grid-cols-3",
|
|
35
36
|
children: [
|
|
36
|
-
/* @__PURE__ */
|
|
37
|
+
/* @__PURE__ */ N(d, {
|
|
37
38
|
label: "Invoices",
|
|
38
|
-
value:
|
|
39
|
+
value: M?.totalCount ?? 0,
|
|
40
|
+
icon: /* @__PURE__ */ N(A, { className: "h-4 w-4" })
|
|
39
41
|
}),
|
|
40
|
-
/* @__PURE__ */
|
|
42
|
+
/* @__PURE__ */ N(d, {
|
|
41
43
|
label: "Outstanding",
|
|
42
|
-
value:
|
|
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__ */
|
|
49
|
+
/* @__PURE__ */ N(d, {
|
|
46
50
|
label: "Collected",
|
|
47
|
-
value:
|
|
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__ */
|
|
58
|
+
/* @__PURE__ */ N("div", {
|
|
53
59
|
className: "flex justify-end",
|
|
54
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
64
|
+
children: [/* @__PURE__ */ N("option", {
|
|
59
65
|
value: "",
|
|
60
66
|
children: "All statuses"
|
|
61
|
-
}),
|
|
67
|
+
}), S(I)]
|
|
62
68
|
})
|
|
63
69
|
}),
|
|
64
|
-
|
|
65
|
-
error:
|
|
66
|
-
onRetry: () => void
|
|
67
|
-
}) : !
|
|
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
|
|
71
|
-
action: /* @__PURE__ */
|
|
72
|
-
onClick: () =>
|
|
73
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
81
|
+
}) : /* @__PURE__ */ N(h, {
|
|
76
82
|
title: "Invoices",
|
|
77
|
-
children: /* @__PURE__ */
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
/* @__PURE__ */
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
/* @__PURE__ */
|
|
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__ */
|
|
88
|
-
className: "hover:bg-bg-sunken/
|
|
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__ */
|
|
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__ */
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
/* @__PURE__ */
|
|
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__ */
|
|
115
|
+
children: e.status !== "PAID" && e.status !== "CANCELLED" && /* @__PURE__ */ P(F, {
|
|
101
116
|
variant: "ghost",
|
|
102
117
|
size: "sm",
|
|
103
|
-
disabled:
|
|
104
|
-
onClick: () =>
|
|
105
|
-
onSuccess: () =>
|
|
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) =>
|
|
124
|
+
onError: (e) => b({
|
|
110
125
|
tone: "danger",
|
|
111
126
|
text: e instanceof Error ? e.message : "Failed."
|
|
112
127
|
})
|
|
113
128
|
}),
|
|
114
|
-
children: [/* @__PURE__ */
|
|
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
|
-
|
|
121
|
-
onClose: () =>
|
|
122
|
-
onSaved: (e) =>
|
|
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
|
-
},
|
|
130
|
-
let
|
|
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
|
-
}), [
|
|
141
|
-
clientId:
|
|
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(
|
|
147
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
166
|
+
footer: /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ N(F, {
|
|
152
167
|
variant: "outline",
|
|
153
168
|
onClick: r,
|
|
154
|
-
disabled:
|
|
169
|
+
disabled: a.isPending,
|
|
155
170
|
children: "Cancel"
|
|
156
|
-
}), /* @__PURE__ */
|
|
171
|
+
}), /* @__PURE__ */ N(F, {
|
|
157
172
|
onClick: () => {
|
|
158
|
-
if (m(null), !
|
|
159
|
-
if (!
|
|
160
|
-
|
|
161
|
-
clientId:
|
|
162
|
-
engagementId:
|
|
163
|
-
number:
|
|
164
|
-
currency:
|
|
165
|
-
subtotal: Number(
|
|
166
|
-
taxAmount: Number(
|
|
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:
|
|
169
|
-
dueDate:
|
|
170
|
-
notes:
|
|
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(
|
|
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:
|
|
179
|
-
children:
|
|
193
|
+
disabled: a.isPending,
|
|
194
|
+
children: a.isPending ? "Creating…" : "Create invoice"
|
|
180
195
|
})] }),
|
|
181
|
-
children: /* @__PURE__ */
|
|
196
|
+
children: /* @__PURE__ */ P("div", {
|
|
182
197
|
className: "space-y-3",
|
|
183
198
|
children: [
|
|
184
|
-
|
|
199
|
+
d && /* @__PURE__ */ N(o, {
|
|
185
200
|
tone: "danger",
|
|
186
|
-
children:
|
|
201
|
+
children: d
|
|
187
202
|
}),
|
|
188
|
-
/* @__PURE__ */
|
|
203
|
+
/* @__PURE__ */ P("div", {
|
|
189
204
|
className: "grid grid-cols-2 gap-3",
|
|
190
|
-
children: [/* @__PURE__ */
|
|
205
|
+
children: [/* @__PURE__ */ N(l, {
|
|
191
206
|
label: "Client",
|
|
192
207
|
required: !0,
|
|
193
|
-
children: /* @__PURE__ */
|
|
194
|
-
value:
|
|
208
|
+
children: /* @__PURE__ */ P(p, {
|
|
209
|
+
value: c.clientId,
|
|
195
210
|
onChange: g("clientId"),
|
|
196
|
-
children: [/* @__PURE__ */
|
|
211
|
+
children: [/* @__PURE__ */ N("option", {
|
|
197
212
|
value: "",
|
|
198
213
|
children: "Select…"
|
|
199
|
-
}), s.data?.items.map((e) => /* @__PURE__ */
|
|
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__ */
|
|
219
|
+
}), /* @__PURE__ */ N(l, {
|
|
205
220
|
label: "Number",
|
|
206
221
|
required: !0,
|
|
207
|
-
children: /* @__PURE__ */
|
|
208
|
-
value:
|
|
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__ */
|
|
229
|
+
/* @__PURE__ */ N(l, {
|
|
215
230
|
label: "Engagement (optional)",
|
|
216
|
-
children: /* @__PURE__ */
|
|
217
|
-
value:
|
|
231
|
+
children: /* @__PURE__ */ P(p, {
|
|
232
|
+
value: c.engagementId,
|
|
218
233
|
onChange: g("engagementId"),
|
|
219
|
-
disabled: !
|
|
220
|
-
children: [/* @__PURE__ */
|
|
234
|
+
disabled: !c.clientId,
|
|
235
|
+
children: [/* @__PURE__ */ N("option", {
|
|
221
236
|
value: "",
|
|
222
237
|
children: "None"
|
|
223
|
-
}), h.data?.items.map((e) => /* @__PURE__ */
|
|
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__ */
|
|
244
|
+
/* @__PURE__ */ P("div", {
|
|
230
245
|
className: "grid grid-cols-3 gap-3",
|
|
231
246
|
children: [
|
|
232
|
-
/* @__PURE__ */
|
|
247
|
+
/* @__PURE__ */ N(l, {
|
|
233
248
|
label: "Subtotal",
|
|
234
|
-
children: /* @__PURE__ */
|
|
249
|
+
children: /* @__PURE__ */ N(b, {
|
|
235
250
|
type: "number",
|
|
236
251
|
min: "0",
|
|
237
|
-
value:
|
|
252
|
+
value: c.subtotal,
|
|
238
253
|
onChange: g("subtotal")
|
|
239
254
|
})
|
|
240
255
|
}),
|
|
241
|
-
/* @__PURE__ */
|
|
256
|
+
/* @__PURE__ */ N(l, {
|
|
242
257
|
label: "Tax",
|
|
243
|
-
children: /* @__PURE__ */
|
|
258
|
+
children: /* @__PURE__ */ N(b, {
|
|
244
259
|
type: "number",
|
|
245
260
|
min: "0",
|
|
246
|
-
value:
|
|
261
|
+
value: c.taxAmount,
|
|
247
262
|
onChange: g("taxAmount")
|
|
248
263
|
})
|
|
249
264
|
}),
|
|
250
|
-
/* @__PURE__ */
|
|
265
|
+
/* @__PURE__ */ N(l, {
|
|
251
266
|
label: "Currency",
|
|
252
|
-
children: /* @__PURE__ */
|
|
253
|
-
value:
|
|
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__ */
|
|
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__ */
|
|
280
|
+
/* @__PURE__ */ N("span", {
|
|
266
281
|
className: "font-semibold text-text-primary",
|
|
267
|
-
children:
|
|
282
|
+
children: w(_, c.currency)
|
|
268
283
|
})
|
|
269
284
|
]
|
|
270
285
|
}),
|
|
271
|
-
/* @__PURE__ */
|
|
286
|
+
/* @__PURE__ */ P("div", {
|
|
272
287
|
className: "grid grid-cols-2 gap-3",
|
|
273
|
-
children: [/* @__PURE__ */
|
|
288
|
+
children: [/* @__PURE__ */ N(l, {
|
|
274
289
|
label: "Issue date",
|
|
275
|
-
children: /* @__PURE__ */
|
|
290
|
+
children: /* @__PURE__ */ N(b, {
|
|
276
291
|
type: "date",
|
|
277
|
-
value:
|
|
292
|
+
value: c.issueDate,
|
|
278
293
|
onChange: g("issueDate")
|
|
279
294
|
})
|
|
280
|
-
}), /* @__PURE__ */
|
|
295
|
+
}), /* @__PURE__ */ N(l, {
|
|
281
296
|
label: "Due date",
|
|
282
|
-
children: /* @__PURE__ */
|
|
297
|
+
children: /* @__PURE__ */ N(b, {
|
|
283
298
|
type: "date",
|
|
284
|
-
value:
|
|
299
|
+
value: c.dueDate,
|
|
285
300
|
onChange: g("dueDate")
|
|
286
301
|
})
|
|
287
302
|
})]
|
|
288
303
|
}),
|
|
289
|
-
/* @__PURE__ */
|
|
304
|
+
/* @__PURE__ */ N(l, {
|
|
290
305
|
label: "Notes",
|
|
291
|
-
children: /* @__PURE__ */
|
|
292
|
-
value:
|
|
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 {
|
|
316
|
+
export { L as InvoicesPage };
|
|
302
317
|
|
|
303
318
|
//# sourceMappingURL=InvoicesPage.js.map
|