@@ -0,0 +1,67 @@
|
||||
"use client"
|
||||
|
||||
import { useDataClient } from "@conusai-kit/ui/data"
|
||||
import { type ResourceColumn, ResourceList } from "@conusai-kit/ui/patterns"
|
||||
import { Button } from "@conusai-kit/ui/primitives"
|
||||
import { useState } from "react"
|
||||
import type { LedgerLabels } from "./labels.js"
|
||||
|
||||
/** Cursor reads happen only on user action; no local financial persistence. */
|
||||
export function LedgerList<T extends object>({
|
||||
seed,
|
||||
procedure,
|
||||
input,
|
||||
columns,
|
||||
rowId,
|
||||
href,
|
||||
labels,
|
||||
title,
|
||||
}: {
|
||||
seed: { rows: T[]; after?: string | undefined }
|
||||
procedure: string
|
||||
input: Record<string, unknown>
|
||||
columns: ResourceColumn<T>[]
|
||||
rowId: (row: T) => string
|
||||
href?: ((row: T) => string) | undefined
|
||||
labels: LedgerLabels
|
||||
title: string
|
||||
}) {
|
||||
const client = useDataClient()
|
||||
const [page, setPage] = useState(seed)
|
||||
const [busy, setBusy] = useState(false)
|
||||
const [failed, setFailed] = useState(false)
|
||||
return (
|
||||
<>
|
||||
<ResourceList
|
||||
label={title}
|
||||
data={page.rows}
|
||||
columns={columns}
|
||||
rowId={rowId}
|
||||
rowHref={href}
|
||||
rowLabel={rowId}
|
||||
rowLinkLabel={() => labels.open}
|
||||
empty={{ title: labels.empty }}
|
||||
/>
|
||||
{failed ? <p role="alert">{labels.unavailable}</p> : null}
|
||||
{page.after ? (
|
||||
<Button
|
||||
disabled={busy}
|
||||
onClick={async () => {
|
||||
setBusy(true)
|
||||
setFailed(false)
|
||||
try {
|
||||
const next = (await client.call<typeof seed>(procedure, { ...input, after: page.after })).value
|
||||
setPage({ ...next, rows: [...page.rows, ...next.rows] })
|
||||
} catch {
|
||||
setFailed(true)
|
||||
} finally {
|
||||
setBusy(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{labels.more}
|
||||
</Button>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user