diff --git a/apps/app/src/components/generative-ui/meeting-time-picker.test.tsx b/apps/app/src/components/generative-ui/meeting-time-picker.test.tsx new file mode 100644 index 0000000..acfa92a --- /dev/null +++ b/apps/app/src/components/generative-ui/meeting-time-picker.test.tsx @@ -0,0 +1,31 @@ +import { afterEach, expect, it, vi } from "vitest"; +import { cleanup, fireEvent, render, screen } from "@testing-library/react"; +import "@testing-library/jest-dom/vitest"; +import { MeetingTimePicker } from "./meeting-time-picker"; +afterEach(cleanup); +it("does not confirm or decline a meeting without a response channel", () => { + render(); + const options = screen.getAllByRole("button"); + for (const option of options) expect(option).toBeDisabled(); + fireEvent.click(options[0]); + expect(screen.queryByText("Meeting Scheduled")).not.toBeInTheDocument(); + fireEvent.click(screen.getByText("None of these work")); + expect(screen.queryByText("No Time Selected")).not.toBeInTheDocument(); +}); +it("enables selection when a response channel becomes available", () => { + const respond = vi.fn(); + const view = render(); + view.rerender(); + const option = screen.getByRole("button", { name: /Tomorrow/ }); + expect(option).toBeEnabled(); + fireEvent.click(option); + expect(respond).toHaveBeenCalledExactlyOnceWith("Meeting scheduled for Tomorrow at 2:00 PM (45 min)."); + expect(screen.getByText("Meeting Scheduled")).toBeInTheDocument(); +}); +it("submits an available decline response once", () => { + const respond = vi.fn(); + render(); + fireEvent.click(screen.getByText("None of these work")); + expect(respond).toHaveBeenCalledTimes(1); + expect(screen.getByText("No Time Selected")).toBeInTheDocument(); +}); diff --git a/apps/app/src/components/generative-ui/meeting-time-picker.tsx b/apps/app/src/components/generative-ui/meeting-time-picker.tsx index 0d01c82..ce24908 100644 --- a/apps/app/src/components/generative-ui/meeting-time-picker.tsx +++ b/apps/app/src/components/generative-ui/meeting-time-picker.tsx @@ -35,11 +35,13 @@ export function MeetingTimePicker({ const [declined, setDeclined] = useState(false); const handleSelectSlot = (slot: TimeSlot) => { + if (!respond) return; setSelectedSlot(slot); respond?.(`Meeting scheduled for ${slot.date} at ${slot.time}${slot.duration ? ` (${slot.duration})` : ''}.`); }; const handleDecline = () => { + if (!respond) return; setDeclined(true); respond?.("The user declined all proposed meeting times. Please suggest alternative times or ask for their availability."); }; @@ -91,6 +93,7 @@ export function MeetingTimePicker({ {slots.map((slot, index) => (