Screens
Booking Assistant
An assistant that acts — compares options, picks a time, fills a form and confirms before it books.
2 variantsMIT
Preview
Design team offsite
0/5 decided
November 3
Ana Ribeiro
Plan a two-day offsite for our design team of 8 in Copenhagen, mid-March. Keep it under €5k.
files · / commands
Installation
Copies the screen into components/ and installs every component it uses, with their dependencies and theme tokens.
pnpm dlx shadcn@latest add https://tuffui.com/r/booking-assistant.jsonUsage
Pass your own data and wire the callbacks to your agent runtime.
import { BookingAssistant } from "@/components/booking-assistant";
import { AgentQuestion } from "@/components/ui/agent-question";
import { ConfirmationCard } from "@/components/ui/confirmation-card";
import { SlotPicker } from "@/components/ui/slot-picker";
export function TripPlanner({ trip, run }: { trip: Trip; run: AgentRun }) {
return (
<BookingAssistant
status={run.streaming ? "streaming" : "idle"}
onSend={(text) => run.send(text)}
onStop={() => run.stop()}
data={{
title: trip.name,
model: run.model,
user: { name: trip.owner.name },
// Each answer can be an interactive component the agent asked for.
messages: run.turns.map((turn) => ({
id: turn.id,
role: turn.role,
at: turn.createdAt,
content: renderTurn(turn), // AgentQuestion, SlotPicker, FormCard, ConfirmationCard…
})),
summary: {
title: "Trip summary",
estimate: trip.estimate,
items: [
{ id: "venue", label: "Venue", value: trip.venue?.name },
{ id: "call", label: "Kickoff call", value: trip.call?.label },
{ id: "booking", label: "Booking", value: trip.bookingRef },
],
},
}}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| data* | BookingAssistantData | — | Title, model, user, thread messages (any React content) and the summary panel rows. A row with no value shows as not decided yet. |
| status | "idle" | "streaming" | "idle" | While streaming, the composer queues messages and shows Stop. |
| onSend | (text: string) => void | — | Called with the composer text. |
| onStop | () => void | — | Stops the running answer. |
| summaryOpen | boolean | — | Controls the side panel (from 64rem wide). Uncontrolled and open by default; below 64rem the same button opens a drawer. |
| onSummaryOpenChange | (open: boolean) => void | — | Called when the side panel is shown or hidden. |
| className | string | — | Extra classes for the root. |
type BookingAssistantData = {
title: string;
model: string;
messages: ThreadMessage[]; // { id, role, at, content: ReactNode }
summary: { title: string; items: SummaryItem[]; estimate?: string };
user: { name: string; avatar?: string };
};
type SummaryItem = {
id: string;
label: string;
value?: string; // empty until decided
icon?: Icon;
};