Files
2026-11-14 09:56:45 +00:00

69 lines
2.1 KiB
TypeScript

"use client"
// The organization's parties, a page at a time. The server renders the first page (`seed`); a search
// and "Show more" are reads made on a person's action, through the page's data client.
import type { ProjectSlugs } from "@conusai-kit/ui"
import { useDataClient } from "@conusai-kit/ui/data"
import { type ResourceColumn, ResourceList, useResourceList } from "@conusai-kit/ui/patterns"
import type { ReactElement } from "react"
import type { PartyView } from "../contract/index.js"
export interface PartyListLabels {
readonly caption: string
readonly empty: string
readonly name: string
readonly kind: string
readonly country: string
readonly person: string
readonly organization: string
/** `Open {name}`: the link's accessible name. */
readonly open: string
readonly search: string
}
type Page = { rows: PartyView[]; after?: string | undefined }
export function PartyList({
slugs,
seed,
listHref,
labels,
}: {
slugs: ProjectSlugs
seed: Page
listHref: string
labels: PartyListLabels
}): ReactElement {
const client = useDataClient()
const { list } = useResourceList<PartyView>({
seed,
rowId: (party) => party.partyId,
searchLabel: labels.search,
read: async ({ q, after }) => {
const input = { ...slugs, ...(q ? { q } : {}), ...(after ? { after } : {}) }
return (await client.call<Page>("crm.party.list", input)).value
},
})
const columns: ResourceColumn<PartyView>[] = [
{ id: "displayName", header: labels.name, wrap: true, minWidth: "10rem" },
{
id: "kind",
header: labels.kind,
cell: (party) => (party.kind === "person" ? labels.person : labels.organization),
},
{ id: "country", header: labels.country },
]
return (
<ResourceList
{...list}
label={labels.caption}
columns={columns}
rowHref={(party) => `${listHref}/${encodeURIComponent(party.partyId)}`}
rowLinkLabel={(party) => labels.open.replace("{name}", party.displayName)}
rowLabel={(party) => party.displayName}
empty={{ title: labels.empty }}
/>
)
}