Files
template-app/modules/inventory/ui/stock.tsx
T
2026-11-14 09:56:45 +00:00

60 lines
2.0 KiB
TypeScript

// An item's stock: the totals and one row per location that holds any. Part of a page's view (F10): it
// holds no state, and every string is passed in.
import { FactList, PageSection, type ResourceColumn, ResourceList } from "@conusai-kit/ui/patterns"
import type { ReactElement } from "react"
import type { AvailabilityView } from "../contract/index.js"
export interface StockLabels {
/** `Counted in {unit}`, already filled. */
readonly unit: string
/** How many locations hold stock, already filled with the plural form. */
readonly locations: string
readonly onHand: string
readonly reserved: string
readonly available: string
readonly caption: string
readonly location: string
readonly none: string
}
type Level = AvailabilityView["locations"][number]
export function Stock({
availability,
locationName,
labels,
}: {
availability: AvailabilityView
/** The location's name for a person; the service knows locations by id. */
locationName: (locationId: string) => string
labels: StockLabels
}): ReactElement {
const columns: ResourceColumn<Level>[] = [
{ id: "locationId", header: labels.location, cell: (level) => locationName(level.locationId) },
{ id: "onHand", header: labels.onHand, align: "end" },
{ id: "reserved", header: labels.reserved, align: "end" },
{ id: "available", header: labels.available, align: "end" },
]
return (
<PageSection title={labels.caption} description={labels.unit}>
<FactList
facts={[
{ label: labels.onHand, value: availability.onHand },
{ label: labels.reserved, value: availability.reserved },
{ label: labels.available, value: availability.available },
]}
/>
<ResourceList
label={labels.caption}
columns={columns}
data={availability.locations}
rowId={(level) => level.locationId}
count={labels.locations}
rowLabel={(level) => locationName(level.locationId)}
empty={{ title: labels.none }}
/>
</PageSection>
)
}