import { IconSpan } from './icon-span';
import { departmentIcon } from './icons';
import type { BookingPrefill, ChatToolPart, ToolOutputs } from './types';
type WidgetProps = {
part: ChatToolPart;
onDepartmentClick: (department: string) => void;
onShowDoctorSlots: (doctorName: string) => void;
onSuggestBooking: () => void;
onPickSlot: (prefill: BookingPrefill) => void;
onPickBranch: (branch: string) => void;
};
// Dispatcher — renders the right widget for a tool part based on its name and state.
export const ChatToolWidget = ({
part,
onDepartmentClick,
onShowDoctorSlots,
onSuggestBooking,
onPickSlot,
onPickBranch,
}: WidgetProps) => {
if (part.state === 'input-streaming' || part.state === 'input-available') {
return ;
}
if (part.state === 'output-error') {
return
Couldn't load: {part.errorText ?? 'unknown error'}
;
}
switch (part.toolName) {
case 'pick_branch': {
const out = part.output as ToolOutputs['pick_branch'] | undefined;
if (!out?.branches?.length) return null;
return ;
}
case 'list_departments': {
const out = part.output as ToolOutputs['list_departments'] | undefined;
if (!out?.departments?.length) return null;
return ;
}
case 'show_clinic_timings': {
const out = part.output as ToolOutputs['show_clinic_timings'] | undefined;
if (!out?.departments?.length) return null;
return ;
}
case 'show_doctors': {
const out = part.output as ToolOutputs['show_doctors'] | undefined;
if (!out?.doctors?.length) {
return (
No doctors found in {out?.department ?? 'this department'}.
);
}
return (
);
}
case 'show_doctor_slots': {
const out = part.output as ToolOutputs['show_doctor_slots'] | undefined;
if (!out) return null;
if (out.error || !out.doctor) {
return {out.error ?? 'Doctor not found.'}
;
}
return ;
}
case 'suggest_booking': {
const out = part.output as ToolOutputs['suggest_booking'] | undefined;
return (
);
}
default:
return null;
}
};
const TOOL_LABELS: Record = {
pick_branch: 'Fetching branches…',
list_departments: 'Looking up departments…',
show_clinic_timings: 'Fetching clinic hours…',
show_doctors: 'Looking up doctors…',
show_doctor_slots: 'Checking availability…',
suggest_booking: 'Thinking about booking options…',
};
const ToolLoadingRow = ({ toolName }: { toolName: string }) => (
{TOOL_LABELS[toolName] ?? 'Working…'}
);
type BranchPickerProps = {
branches: ToolOutputs['pick_branch']['branches'];
onPick: (branch: string) => void;
};
const BranchPickerWidget = ({ branches, onPick }: BranchPickerProps) => (
);
type DepartmentListProps = {
departments: string[];
onPick: (department: string) => void;
};
const DepartmentListWidget = ({ departments, onPick }: DepartmentListProps) => (
);
type ClinicTimingsProps = {
departments: ToolOutputs['show_clinic_timings']['departments'];
};
const ClinicTimingsWidget = ({ departments }: ClinicTimingsProps) => (
);
type DoctorsListProps = {
department: string;
doctors: ToolOutputs['show_doctors']['doctors'];
onPickDoctor: (doctorName: string) => void;
};
const DoctorsListWidget = ({ department, doctors, onPickDoctor }: DoctorsListProps) => (
);
type DoctorSlotsProps = {
data: ToolOutputs['show_doctor_slots'];
onPickSlot: (prefill: BookingPrefill) => void;
};
const DoctorSlotsWidget = ({ data, onPickSlot }: DoctorSlotsProps) => {
if (!data.doctor) return null;
const doctor = data.doctor;
const available = data.slots.filter(s => s.available);
const hasAny = available.length > 0;
return (
);
};
const formatDate = (iso: string): string => {
// iso is YYYY-MM-DD from the backend. Render as e.g. "Mon, 6 Apr".
const d = new Date(iso + 'T00:00:00');
if (isNaN(d.getTime())) return iso;
return d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' });
};
type BookingSuggestionProps = {
reason: string;
department: string | null;
onBook: () => void;
};
const BookingSuggestionWidget = ({ reason, department, onBook }: BookingSuggestionProps) => (
);