import { businessServiceNotices } from "@conusai-kit/business/refusals" import { type Container, notFound, type TransportCaller } from "@conusai-kit/core" import type { I18n } from "@conusai-kit/i18n" import { type ProjectPage, projectPage } from "@conusai-kit/ui" import { Can } from "@conusai-kit/ui/data" import { FactList, Page, PageHeader, PageSection, type ResourceColumn, type ServiceNotice, ServiceStatePage, serviceNotice, } from "@conusai-kit/ui/patterns" import * as c from "../contract/index.js" import { AccountForm, RecordForm, Transition } from "./forms.js" import { type LedgerLabels, ledgerLabels } from "./labels.js" import { LedgerList } from "./resource.js" type Loaded = { labels: LedgerLabels; verification: c.VerificationView } & ( | { kind: "list" accounts: { rows: c.AccountView[]; after?: string | undefined } transactions: { rows: c.TransactionView[]; after?: string | undefined } } | { kind: "account" account: c.AccountView balances: { rows: c.BalanceView[]; after?: string | undefined } entries: { rows: c.EntryView[]; after?: string | undefined } } | { kind: "transaction"; transaction: c.TransactionView } ) type Data = Loaded | { kind: "state"; labels: LedgerLabels; notice: ServiceNotice } export type LedgerPage = ProjectPage export const ledgerPage: LedgerPage = projectPage({ async load({ caller, slugs, segments, i18n }): Promise { const labels = ledgerLabels((key) => i18n.message(`ledger.${key}`), i18n.locale) const input = { org: slugs.org } const [kind, id, ...rest] = segments if (rest.length || (kind !== undefined && ((kind !== "accounts" && kind !== "transactions") || !id))) throw notFound() try { const verification = await caller.call(c.verify, input) if (kind === "accounts" && id) { const [account, balances, entries] = await Promise.all([ caller.call(c.account, { ...input, accountId: id }), caller.call(c.balances, { ...input, accountId: id }), caller.call(c.entries, { ...input, accountId: id }), ]) return { kind: "account", labels, verification, account, balances, entries } } if (kind === "transactions" && id) return { kind: "transaction", labels, verification, transaction: await caller.call(c.transaction, { ...input, transactionId: id }), } const [accounts, transactions] = await Promise.all([ caller.call(c.accounts, input), caller.call(c.transactions, input), ]) return { kind: "list", labels, verification, accounts, transactions } } catch (error) { const notice = serviceNotice(error, businessServiceNotices(i18n.locale)) if (!notice) throw error return { kind: "state", labels, notice } } }, View({ slugs, data }) { if (data.kind === "state") return const { labels: l, verification } = data const base = `/${slugs.org}/${slugs.workspace}/${slugs.project}/ledger` const org = slugs.org const fenced = verification.drift.length > 0 const entryColumns: ResourceColumn[] = [ { id: "accountId", header: l.account }, { id: "direction", header: l.normalBalance, cell: (row: c.EntryView) => l[row.direction] }, { id: "amountMinor", header: l.amountMinor }, { id: "currency", header: l.currency }, { id: "transactionId", header: l.transaction }, ] return ( {l.back}} /> {data.kind === "list" ? ( <> row.accountId} href={(row) => `${base}/accounts/${row.accountId}`} labels={l} title={l.accounts} columns={[ { id: "code", header: l.code }, { id: "name", header: l.name }, { id: "currency", header: l.currency }, { id: "status", header: l.status, cell: (row) => l[row.status] }, ]} /> row.transactionId} href={(row) => `${base}/transactions/${row.transactionId}`} labels={l} title={l.transactions} columns={[ { id: "transactionId", header: l.transaction }, { id: "description", header: l.description }, { id: "status", header: l.status, cell: (row) => l[row.status] }, { id: "effectiveAt", header: l.effectiveAt }, ]} /> ) : data.kind === "account" ? ( <> row.accountId} labels={l} title={l.balances} columns={[ { id: "currency", header: l.currency }, { id: "posted", header: l.postedBalance }, { id: "pending", header: l.pendingBalance }, { id: "available", header: l.availableBalance }, ]} /> row.entryId} href={(row) => `${base}/transactions/${row.transactionId}`} labels={l} title={l.entries} columns={entryColumns} /> ) : ( <> row.entryId} labels={l} title={l.entries} columns={entryColumns} /> {data.transaction.status === "pending" ? ( {(["post", "void"] as const).map((action) => ( ))} ) : data.transaction.status === "posted" ? ( ) : null} )} ) }, })