diff --git a/src/app/(app)/giellie/page.test.tsx b/src/app/(app)/giellie/page.test.tsx new file mode 100644 index 0000000..fb91b8e --- /dev/null +++ b/src/app/(app)/giellie/page.test.tsx @@ -0,0 +1,61 @@ +import { describe, it, expect, vi } from "vitest"; +import { render, screen, fireEvent } from "@testing-library/react"; + +const newChat = vi.fn(); +const openChat = vi.fn(); + +vi.mock("@/components/giellie/use-giellie", () => ({ + useGielie: () => ({ + ready: { ready: true }, + chats: [ + { id: "a", title: "Chat A", updated: "" }, + { id: "b", title: "Chat B", updated: "" }, + ], + chat: { id: "a", title: "Chat A", updated: "", messages: [], pending_action: null, attachments: [] }, + liveText: "", + activity: [], + pending: null, + busy: false, + error: "", + openChat, + newChat, + send: vi.fn(), + decide: vi.fn(), + }), +})); + +import GielliePage from "./page"; + +const toggle = () => screen.getByRole("switch", { name: /trust this chat/i }); + +describe("GielliePage trust toggle", () => { + it("shows the email caveat as visible text", () => { + render(); + expect(screen.getByText(/emails always ask/i)).toBeTruthy(); + }); + + it("resets trust when another chat is opened", () => { + render(); + fireEvent.click(toggle()); + expect(toggle().getAttribute("aria-checked")).toBe("true"); + fireEvent.click(screen.getByText("Chat B")); + expect(openChat).toHaveBeenCalledWith("b"); + expect(toggle().getAttribute("aria-checked")).toBe("false"); + }); + + it("resets trust on New chat", () => { + render(); + fireEvent.click(toggle()); + fireEvent.click(screen.getByRole("button", { name: /new chat/i })); + expect(newChat).toHaveBeenCalled(); + expect(toggle().getAttribute("aria-checked")).toBe("false"); + }); + + it("closes the mobile chat list with the close button", () => { + render(); + fireEvent.click(screen.getByRole("button", { name: "Chats" })); + expect(screen.getByRole("button", { name: /close chats/i })).toBeTruthy(); + fireEvent.click(screen.getByRole("button", { name: /close chats/i })); + expect(screen.queryByRole("button", { name: /close chats/i })).toBeNull(); + }); +}); diff --git a/src/app/(app)/giellie/page.tsx b/src/app/(app)/giellie/page.tsx index 123bc31..bc98076 100644 --- a/src/app/(app)/giellie/page.tsx +++ b/src/app/(app)/giellie/page.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { useState } from "react"; -import { Bot, Menu } from "lucide-react"; +import { Bot, Menu, X } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Switch } from "@/components/ui/switch"; import { ChatList } from "@/components/giellie/chat-list"; @@ -18,24 +18,47 @@ export default function GielliePage() { const [showList, setShowList] = useState(false); const notReady = g.ready && !g.ready.ready; + const errorLine = g.error ?

{g.error}

: null; return ( -
+ // Height = viewport minus the (app) layout chrome around {children}: + // below lg: 2px brand stripe + 56px (pt-14 mobile top bar) + 20px + 20px (p-5) = 98px + // lg+: 2px brand stripe + 32px + 32px (p-8) = 66px + // dvh (not vh) so the iOS Safari toolbar doesn't push the composer off-screen. +
+ {showList && ( +
setShowList(false)} + /> + )}