11"use client" ;
22import React , { useState , useRef , useEffect , useCallback } from "react" ;
3- import { useSession } from "next-auth/react" ;
43import { Textarea } from "@/components/ui/textarea" ;
54import { Button } from "@/components/ui/button" ;
65import {
@@ -28,9 +27,8 @@ import SpeechRecognition, {
2827import { useSpeechSynthesis } from "react-speech-kit" ;
2928import { toast } from "sonner" ;
3029import { useTheme } from "next-themes" ;
31- import { WrapText } from "lucide-react" ;
30+ import { Globe , Loader2Icon , Paperclip , WrapText } from "lucide-react" ;
3231import { atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs" ;
33- import { useParams } from "next/navigation" ;
3432import { api } from "@/trpc/react" ;
3533
3634const geistMono = Geist_Mono ( {
@@ -52,25 +50,43 @@ interface Message {
5250 content : string ;
5351}
5452
55- const Chat = ( ) => {
56- const { data : sessionData } = useSession ( ) ;
53+ const Chat = ( { chatId : initialChatId } : { chatId : string } ) => {
5754 const [ model , setModel ] = useState < string > ( DEFAULT_MODEL_ID ) ;
5855 const [ messages , setMessages ] = useState < ChatMessage [ ] > ( [ ] ) ;
56+ const [ search , setSearch ] = useState < boolean > ( false ) ;
5957 const [ input , setInput ] = useState ( "" ) ;
6058 const [ isLoading , setIsLoading ] = useState ( false ) ;
61- const params = useParams ( ) ;
6259 const [ modeOfChatting , setModeOfChatting ] = useState < "text" | "voice" > (
6360 "text" ,
6461 ) ;
6562 const [ showWelcome , setShowWelcome ] = useState ( true ) ;
6663 const [ copied , setCopied ] = useState ( false ) ;
67- const chatId = params ?. chatId as string | undefined ;
6864 const messagesEndRef = useRef < HTMLDivElement > ( null ) ;
6965 const abortControllerRef = useRef < AbortController | null > ( null ) ;
7066 const welcomeSpokenRef = useRef ( false ) ;
7167 const [ isWrapped , setIsWrapped ] = useState ( false ) ;
7268 const { resolvedTheme } = useTheme ( ) ;
7369 const [ query , setQuery ] = useState < string > ( "" ) ;
70+ const [ attachments , setAttachments ] = useState < File [ ] > ( [ ] ) ;
71+ const [ chatId , setChatId ] = useState < string > ( initialChatId ) ;
72+
73+ const { data : chatMessages } = api . chat . getChatMessages . useQuery ( {
74+ chatId : chatId ,
75+ } ) ;
76+
77+ useEffect ( ( ) => {
78+ setChatId ( initialChatId ) ;
79+ } , [ initialChatId ] ) ;
80+
81+ useEffect ( ( ) => {
82+ if ( chatMessages ) {
83+ setMessages ( chatMessages . messages . map ( ( message ) => ( {
84+ id : message . id ,
85+ role : message . role === "USER" ? "user" : "assistant" ,
86+ content : message . content ,
87+ } ) ) ) ;
88+ }
89+ } , [ chatMessages ] ) ;
7490
7591 const toggleWrap = useCallback ( ( ) => {
7692 setIsWrapped ( ( prev ) => ! prev ) ;
@@ -156,12 +172,12 @@ const Chat = () => {
156172 const { done, value } = await reader . read ( ) ;
157173
158174 if ( done ) {
159- console . log ( "Stream complete" ) ;
175+ // console.log("Stream complete");
160176 break ;
161177 }
162178
163179 const chunk = new TextDecoder ( ) . decode ( value ) ;
164- console . log ( "Received chunk:" , chunk ) ;
180+ // console.log("Received chunk:", chunk);
165181
166182 buffer += chunk ;
167183
@@ -180,7 +196,7 @@ const Chat = () => {
180196 }
181197
182198 try {
183- console . log ( "Parsing JSON:" , data ) ;
199+ // console.log("Parsing JSON:", data);
184200 const parsedData = JSON . parse ( data ) as {
185201 choices ?: Array < {
186202 delta ?: {
@@ -191,7 +207,7 @@ const Chat = () => {
191207
192208 const content = parsedData . choices ?. [ 0 ] ?. delta ?. content ;
193209 if ( content ) {
194- console . log ( "Received content:" , content ) ;
210+ // console.log("Received content:", content);
195211 accumulatedContent += content ;
196212
197213 setMessages ( ( prev ) =>
@@ -209,7 +225,7 @@ const Chat = () => {
209225 }
210226 }
211227
212- console . log ( "Saving chat to database:" , userMessage , accumulatedContent ) ;
228+ // console.log("Saving chat to database:", userMessage, accumulatedContent);
213229 } catch ( error ) {
214230 console . error ( "Error processing stream:" , error ) ;
215231 } finally {
@@ -218,12 +234,6 @@ const Chat = () => {
218234 }
219235 } ;
220236
221- const createChat = api . chat . createChat . useMutation ( {
222- onError : ( error ) => {
223- console . error ( "Error saving chat:" , error ) ;
224- } ,
225- } ) ;
226-
227237 const handleCreateChat = async ( e : React . FormEvent ) => {
228238 e . preventDefault ( ) ;
229239 if ( ! query . trim ( ) || isLoading ) return ;
@@ -249,7 +259,6 @@ const Chat = () => {
249259 abortControllerRef . current = new AbortController ( ) ;
250260
251261 try {
252- const { chatId } = await createChat . mutateAsync ( ) ;
253262 setTimeout ( ( ) => {
254263 void ( async ( ) => {
255264 try {
@@ -339,6 +348,7 @@ const Chat = () => {
339348 body : JSON . stringify ( {
340349 messages : [ { role : "user" , content : currentMessage } ] ,
341350 model : model ,
351+ chatId : chatId ,
342352 } ) ,
343353 signal : abortControllerRef . current . signal ,
344354 } ) ;
@@ -393,14 +403,28 @@ const Chat = () => {
393403 }
394404 } ;
395405
406+
407+ const handleFileInput = ( ) => {
408+ const fileInput = document . createElement ( "input" ) ;
409+ fileInput . type = "file" ;
410+ fileInput . accept = "image/*" ;
411+ fileInput . onchange = ( e ) => {
412+ const file = ( e . target as HTMLInputElement ) . files ?. [ 0 ] ;
413+ if ( file ) {
414+ setAttachments ( ( prev ) => [ ...prev , file ] ) ;
415+ }
416+ } ;
417+ fileInput . click ( ) ;
418+ } ;
419+
396420 return (
397421 < div className = "h-[96vh] w-full" >
398422 < div className = "relative flex h-full w-full flex-col" >
399- < div className = "flex flex-1 flex-col overflow-y-auto px-4 pb-40 md:px-4" >
423+ < div className = "no-scrollbar flex flex-1 flex-col overflow-y-auto px-4 pb-40 md:px-4" >
400424 < div className = "mx-auto w-full max-w-4xl py-4" >
401425 { messages . length === 0 ? (
402426 < div className = "text-muted-foreground flex h-[50vh] items-center justify-center" >
403- Start a conversation by typing a message below
427+ < Loader2Icon className = "animate-spin" />
404428 </ div >
405429 ) : (
406430 < div className = "no-scrollbar mt-6 flex h-full w-full flex-1 flex-col gap-4 overflow-y-auto px-4 pt-4 pb-10 md:px-8" >
@@ -690,6 +714,17 @@ const Chat = () => {
690714 onValueChange = { setModel }
691715 disabled = { isLoading }
692716 />
717+
718+ { /* Search */ }
719+ < Button variant = "ghost" size = "sm" className = { `text-xs ${ search ? "bg-primary/60 hover:bg-primary/70" : "" } ` } onClick = { ( ) => setSearch ( ! search ) } >
720+ < Globe className = "size-4" />
721+ Search
722+ </ Button >
723+
724+ { /* Attachments */ }
725+ < Button variant = "ghost" size = "sm" className = "text-xs" onClick = { handleFileInput } >
726+ < Paperclip className = "size-4" />
727+ </ Button >
693728 </ div >
694729 < Button
695730 type = "submit"
0 commit comments