ConusAI vendor v0.1.0-beta.114
ci / gate (push) Waiting to run

This commit is contained in:
ConusAI vendor v0.1.0-beta.114
2026-11-14 09:56:45 +00:00
commit 1ce8d23c35
867 changed files with 122104 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
"use client"
// Reserves stock of one item for this project, from one location that has some available. The request
// id is minted once per submission, so a retried request reserves once; the service answers a
// quantity it cannot hold as `insufficient_stock`, shown here in the kit's words for that refusal.
import type { ProjectSlugs } from "@conusai-kit/ui"
import { describeError, useWrite } from "@conusai-kit/ui/data"
import {
FormLayout,
type FormValues,
PageSection,
SelectField,
serviceNotice,
TextField,
usePageNavigation,
} from "@conusai-kit/ui/patterns"
import { type ReactElement, useState } from "react"
export interface ReserveFormLabels {
readonly heading: string
readonly location: string
readonly quantity: string
readonly submit: string
readonly busy: string
readonly nothing: string
/** The text of each business refusal by problem code (`businessRefusalNotices` of `@conusai-kit/business/refusals`). */
readonly refusals: Readonly<Record<string, string>>
}
export interface ReserveOption {
readonly locationId: string
/** What a person reads for the location, with what is available there. */
readonly label: string
readonly available: number
}
export function ReserveForm({
slugs,
itemId,
options,
labels,
}: {
slugs: ProjectSlugs
itemId: string
options: readonly ReserveOption[]
labels: ReserveFormLabels
}): ReactElement {
const navigation = usePageNavigation()
const reserve = useWrite<Record<string, unknown>, unknown>("inventory.stock.reserve")
const [requestId, setRequestId] = useState(() => crypto.randomUUID())
const open = options.filter((option) => option.available > 0)
const submit = async ({ locationId, quantity }: FormValues): Promise<void> => {
await reserve.mutate({ ...slugs, itemId, locationId, quantity: Number(quantity), requestId })
setRequestId(crypto.randomUUID())
// The page is rendered on the server: a reload shows the new balance and the reservation.
await navigation.refresh()
}
return (
<PageSection title={labels.heading} variant="card">
{open.length === 0 ? (
<p>{labels.nothing}</p>
) : (
<FormLayout
submitLabel={labels.submit}
busyLabel={labels.busy}
onSubmit={submit}
describeError={(error) => serviceNotice(error, labels.refusals)?.text ?? describeError(error)}
>
<SelectField
name="locationId"
label={labels.location}
required
defaultValue={open[0]?.locationId}
options={open.map((option) => ({ value: option.locationId, label: option.label }))}
/>
<TextField name="quantity" label={labels.quantity} type="number" required min={1} step={1} defaultValue={1} />
</FormLayout>
)}
</PageSection>
)
}