66 lines
2.0 KiB
TypeScript
66 lines
2.0 KiB
TypeScript
"use client"
|
|
|
|
// The organization's items, 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 { ItemView } from "../contract/index.js"
|
|
|
|
export interface ItemListLabels {
|
|
readonly caption: string
|
|
readonly empty: string
|
|
readonly sku: string
|
|
readonly name: string
|
|
readonly unit: string
|
|
readonly active: string
|
|
readonly archived: string
|
|
/** `Stock of {name}`: the link's accessible name. */
|
|
readonly open: string
|
|
readonly search: string
|
|
}
|
|
|
|
type Page = { rows: ItemView[]; after?: string | undefined }
|
|
|
|
export function ItemList({
|
|
slugs,
|
|
seed,
|
|
listHref,
|
|
labels,
|
|
}: {
|
|
slugs: ProjectSlugs
|
|
seed: Page
|
|
listHref: string
|
|
labels: ItemListLabels
|
|
}): ReactElement {
|
|
const client = useDataClient()
|
|
const { list } = useResourceList<ItemView>({
|
|
seed,
|
|
rowId: (item) => item.itemId,
|
|
searchLabel: labels.search,
|
|
read: async ({ q, after }) => {
|
|
const input = { ...slugs, ...(q ? { q } : {}), ...(after ? { after } : {}) }
|
|
return (await client.call<Page>("inventory.item.list", input)).value
|
|
},
|
|
})
|
|
const columns: ResourceColumn<ItemView>[] = [
|
|
{ id: "sku", header: labels.sku },
|
|
{ id: "name", header: labels.name, wrap: true, minWidth: "10rem" },
|
|
{ id: "unit", header: labels.unit },
|
|
{ id: "active", header: labels.active, cell: (item) => (item.active ? labels.active : labels.archived) },
|
|
]
|
|
return (
|
|
<ResourceList
|
|
{...list}
|
|
label={labels.caption}
|
|
columns={columns}
|
|
rowHref={(item) => `${listHref}/${item.itemId}`}
|
|
rowLinkLabel={(item) => labels.open.replace("{name}", item.sku)}
|
|
rowLabel={(item) => item.sku}
|
|
empty={{ title: labels.empty }}
|
|
/>
|
|
)
|
|
}
|