import { useState } from "react";
import type { UiHint, UiHintField } from "../types";
type Props = {
uiHint: UiHint | null;
candidates?: string[];
availableJourneys?: string[];
onSubmit(text: string): void;
};
/**
* SmartControl renders the right interactive widget under the latest assistant bubble
* based on the agent's ui_hint. We always offer the text composer below, so this is
* a *shortcut* for the user, not a forced channel.
*
* - multi_slot_form -> full form with dropdowns / number / date inputs
* - dropdown -> chip grid of vocabulary values
* - date -> native date input
* - confirm -> Yes / Not yet
* - candidates -> journey-choice cards (ambiguity)
* - text -> nothing (composer handles it)
*/
export function SmartControl({ uiHint, candidates = [], availableJourneys = [], onSubmit }: Props) {
// Ambiguity / journey-choice always wins if present.
if (candidates.length > 0) {
return (
{
if (e.target.value) onSubmit(e.target.value);
}}
/>
);
}
// ============================================================================
// Multi-slot form — beautiful in-theme card with dropdowns / number / date
// ============================================================================
function MultiSlotForm({ uiHint, onSubmit }: { uiHint: UiHint; onSubmit(text: string): void }) {
const fields = uiHint.fields ?? [];
const [values, setValues] = useState>({});
const filledCount = Object.values(values).filter((v) => v && v.trim()).length;
function buildMessage(): string {
// Compose a natural-sounding sentence the slot extractor can parse. We use a templated
// phrasing that maps slot → English fragment (the labels come from the form fields).
const parts: string[] = [];
for (const f of fields) {
const v = (values[f.slot] || "").trim();
if (!v) continue;
parts.push(`${f.label} ${v}`);
}
return parts.join(", ") + ".";
}
function handleSubmit() {
if (filledCount === 0) return;
onSubmit(buildMessage());
}
return (
{uiHint.title &&
{uiHint.title}
}
Fill in what you can — leave the rest blank. You can also just type your answer in
the chat box below if you prefer.