60 lines
2.0 KiB
TypeScript
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>
|
|
)
|
|
}
|