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) => (