diff --git a/src/app/notes/NavBar.tsx b/src/app/notes/NavBar.tsx index 16719ac..1b92e71 100644 --- a/src/app/notes/NavBar.tsx +++ b/src/app/notes/NavBar.tsx @@ -1,6 +1,7 @@ "use client"; import logo from "@/assets/logo.png"; +import AIChatButton from "@/components/AIChatButton"; import AddEditNoteDialog from "@/components/AddEditNoteDialog"; import ThemeToggleButton from "@/components/ThemeToggleButton"; import { Button } from "@/components/ui/button"; @@ -38,6 +39,7 @@ export default function NavBar() { Add Note + diff --git a/src/components/AIChatBox.tsx b/src/components/AIChatBox.tsx new file mode 100644 index 0000000..4dd1680 --- /dev/null +++ b/src/components/AIChatBox.tsx @@ -0,0 +1,142 @@ +import { cn } from "@/lib/utils"; +import { useUser } from "@clerk/nextjs"; +import { Message } from "ai"; +import { useChat } from "ai/react"; +import { Bot, Trash, XCircle } from "lucide-react"; +import Image from "next/image"; +import { useEffect, useRef } from "react"; +import { Button } from "./ui/button"; +import { Input } from "./ui/input"; + +interface AIChatBoxProps { + open: boolean; + onClose: () => void; +} + +export default function AIChatBox({ open, onClose }: AIChatBoxProps) { + const { + messages, + input, + handleInputChange, + handleSubmit, + setMessages, + isLoading, + error, + } = useChat(); + + const inputRef = useRef(null); + const scrollRef = useRef(null); + + useEffect(() => { + if (scrollRef.current) { + scrollRef.current.scrollTop = scrollRef.current.scrollHeight; + } + }, [messages]); + + useEffect(() => { + if (open) { + inputRef.current?.focus(); + } + }, [open]); + + const lastMessageIsUser = messages[messages.length - 1]?.role === "user"; + + return ( +
+ +
+
+ {messages.map((message) => ( + + ))} + {isLoading && lastMessageIsUser && ( + + )} + {error && ( + + )} + {!error && messages.length === 0 && ( +
+ + Ask the AI a question about your notes +
+ )} +
+
+ + + +
+
+
+ ); +} + +function ChatMessage({ + message: { role, content }, +}: { + message: Pick; +}) { + const { user } = useUser(); + + const isAiMessage = role === "assistant"; + + return ( +
+ {isAiMessage && } +

+ {content} +

+ {!isAiMessage && user?.imageUrl && ( + User image + )} +
+ ); +} diff --git a/src/components/AIChatButton.tsx b/src/components/AIChatButton.tsx new file mode 100644 index 0000000..683ae39 --- /dev/null +++ b/src/components/AIChatButton.tsx @@ -0,0 +1,18 @@ +import { Bot } from "lucide-react"; +import { useState } from "react"; +import AIChatBox from "./AIChatBox"; +import { Button } from "./ui/button"; + +export default function AIChatButton() { + const [chatBoxOpen, setChatBoxOpen] = useState(false); + + return ( + <> + + setChatBoxOpen(false)} /> + + ); +}