diff --git a/src/app/@modal/(.)assistant/_components/ChatModal.tsx b/src/app/@modal/(.)assistant/_components/ChatModal.tsx
index 088911b..eb19864 100644
--- a/src/app/@modal/(.)assistant/_components/ChatModal.tsx
+++ b/src/app/@modal/(.)assistant/_components/ChatModal.tsx
@@ -2,6 +2,8 @@
import { useRouter } from 'next/navigation'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '~/components/ui/dialog'
import ChatInterface from '~/app/chat/_components/ChatInterface'
+import { useMessages } from '~/app/_providers/MessagesProvider';
+import { Spinner } from '~/components/ui/spinner';
type DBMessage = {
id: string
@@ -9,14 +11,9 @@ type DBMessage = {
content: string
}
-interface ChatModalProps {
- sessionId?: string
- // initialMessages: DBMessage[]
-}
-
-export default function ChatModal({ sessionId }: ChatModalProps) {
+export default function ChatModal() {
const router = useRouter()
-
+ const {messages,session,clearChat,clearingChat,isLoading,error,refetchMessages} = useMessages()
return (
diff --git a/src/app/@modal/(.)assistant/page.tsx b/src/app/@modal/(.)assistant/page.tsx
index 8fd4f7d..6dc86fe 100644
--- a/src/app/@modal/(.)assistant/page.tsx
+++ b/src/app/@modal/(.)assistant/page.tsx
@@ -8,7 +8,7 @@ export default function AssistantModalPage() {
const { data: session, error, isLoading } = trpc.chat.getSession.useQuery();
return (
<>
-
+
{error &&
{error.message}
}
{isLoading && }
>
diff --git a/src/app/_providers/MessagesProvider.tsx b/src/app/_providers/MessagesProvider.tsx
new file mode 100644
index 0000000..e179dfe
--- /dev/null
+++ b/src/app/_providers/MessagesProvider.tsx
@@ -0,0 +1,69 @@
+'use client'
+import type { inferRouterOutputs } from '@trpc/server';
+import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'
+import { trpc } from '~/app/_trpc/Client'
+import { type ChatRouter } from '~/server/routers/chat'
+const MessageContext = createContext<{
+ session?: inferRouterOutputs['getSession']
+ messages?: inferRouterOutputs['getMessages']
+ refetchMessages: () => void
+ clearChat: (callback?: () => void) => void
+ error: string|null
+ isLoading: boolean
+ clearingChat: boolean
+ clearedChat: boolean
+}>({
+ session: undefined,
+ messages: undefined,
+ refetchMessages: () => undefined,
+ clearChat: () => undefined,
+ error: null,
+ isLoading: true,
+ clearingChat: false,
+ clearedChat: false
+})
+export const useMessages = () => useContext(MessageContext)
+export const MessagesProvider = ({children}:{children:ReactNode}) => {
+ const [error,setError] = useState(null)
+ const [isLoading,setIsLoading] = useState(true)
+ const { data: session,error:sessionError,isLoading:sessionLoading} = trpc.chat.getSession.useQuery()
+ const { data: messages, refetch, error:messageError, isLoading:messagesLoading } = trpc.chat.getMessages.useQuery(session?.id ? session.id : "")
+ const { mutate ,isPending:clearingChat,isSuccess:clearedChat } = trpc.chat.clearChat.useMutation()
+ const utils = trpc.useUtils()
+ const refetchMessages = () => {
+ utils.chat.getMessages.invalidate()
+ refetch()
+ }
+ const clearChat = (callback?: () => void) => {
+ mutate(undefined,{onSuccess: () => {
+ if (callback) {
+ callback()
+ }
+ utils.chat.getMessages.invalidate()
+ }})
+ }
+ useEffect(() => {
+ messageError && setError(messageError.message)
+ sessionError && setError(sessionError.message)
+ },[messageError,sessionError])
+ useEffect(() => {
+ !sessionLoading && !messagesLoading && setIsLoading(false)
+ sessionLoading || messagesLoading && setIsLoading(true)
+ },[sessionLoading,messagesLoading])
+ return (
+
+ {children}
+
+ )
+}
diff --git a/src/app/chat/_components/AssistantMessage.tsx b/src/app/chat/_components/AssistantMessage.tsx
index 9c24c68..98d10ec 100644
--- a/src/app/chat/_components/AssistantMessage.tsx
+++ b/src/app/chat/_components/AssistantMessage.tsx
@@ -16,7 +16,7 @@ export const AssistantMessage = (props: { message: UIMessage }) => {
{message.parts.map((part, i) => {
if (part.type === 'text') {
return (
-
+
{part.text}
)
diff --git a/src/app/chat/_components/ChatInterface.tsx b/src/app/chat/_components/ChatInterface.tsx
index 66736ef..b28465e 100644
--- a/src/app/chat/_components/ChatInterface.tsx
+++ b/src/app/chat/_components/ChatInterface.tsx
@@ -9,9 +9,8 @@ import {
} from '~/app/_providers/GsapProvicer';
import Messages from './Messages'
import { DeleteIcon } from 'lucide-react';
-import { trpc } from '~/app/_trpc/Client'
import { Spinner } from '~/components/ui/spinner';
-import { Skeleton } from '~/components/ui/skeleton';
+import { useMessages } from '~/app/_providers/MessagesProvider';
interface DBMessage {
id: string
role: 'user' | 'assistant'
@@ -19,8 +18,8 @@ interface DBMessage {
}
interface ChatInterfaceProps {
- sessionId?: string
- // initialMessages: DBMessage[]
+ sessionId: string,
+ dbMessages: DBMessage[],
}
function toUIMessages(dbMessages: DBMessage[]): UIMessage[] {
@@ -30,28 +29,10 @@ function toUIMessages(dbMessages: DBMessage[]): UIMessage[] {
parts: [{ type: 'text' as const, text: m.content }],
}))
}
-export default function ChatInterface({ sessionId }: ChatInterfaceProps) {
- if (!sessionId) {
- return (
-
-
-
-
-
- )
- }
- const utils = trpc.useUtils();
- const { data: dbMessages, refetch: refetchMessages } = trpc.chat.getMessages.useQuery(sessionId)
- const [messages, setMessages] = useState([]);
- function addMessage(newMessage: UIMessage) {
- setMessages(prev => [...prev, newMessage]);
- }
- useEffect(() => {
- setMessages(toUIMessages(dbMessages ?? []));
- }, [dbMessages]);
- if (messages.at(0)?.id != 'init') {
- messages.unshift({
+function addInitMessage(messageArray: UIMessage[]) {
+ if (messageArray.at(0)?.id != 'init') {
+ messageArray.unshift({
id: "init",
role: 'assistant',
parts: [{
@@ -60,46 +41,31 @@ export default function ChatInterface({ sessionId }: ChatInterfaceProps) {
}],
})
}
+}
+
+export default function ChatInterface({ dbMessages, sessionId }: ChatInterfaceProps) {
const [input, setInput] = useState('')
- const { sendMessage, status, error, clearError } = useChat({
+ const { clearingChat, clearChat, refetchMessages } = useMessages();
+ const initialMessages = toUIMessages(dbMessages)
+ addInitMessage(initialMessages)
+ const { messages, sendMessage, status, error, clearError, setMessages } = useChat({
transport: new DefaultChatTransport({
api: '/api/chat', body: { sessionId },
}),
- messages: messages,
+ messages: initialMessages,
})
- const handleSend = () => {
- const text = input.trim()
- if (!text || status != 'ready' || sessionId == undefined) return
- setInput('')
- sendMessage({ text })
- addMessage({
- id: "", role: "user", parts: [
- { type: 'text', text }
- ]
- })
- addMessage({
- id: "", role: "assistant", parts: [
- { type: 'text', text: "Thinking..." }
- ]
- })
- }
- const clearChatMutation = trpc.chat.clearChat.useMutation()
- const handleClear = () => {
- clearChatMutation.mutate(undefined, {
- onSuccess: () => {
- utils.chat.getMessages.invalidate()
- refetchMessages()
- }
- })
- }
- const gsapContext = useGsapContext()
useEffect(() => {
- console.log(status)
- if (status == 'ready') {
- utils.chat.getMessages.invalidate();
+ return () => {
refetchMessages()
}
- }, [status])
+ }, [])
+ const handleSend = () => {
+ const text = input.trim()
+ if (!text || status != 'ready' || clearingChat) return
+ setInput('')
+ sendMessage({ text })
+ }
+ const gsapContext = useGsapContext()
useEffect(() => {
let scroller = gsapContext?.getScroller()
if (scroller instanceof Window) {
@@ -111,9 +77,8 @@ export default function ChatInterface({ sessionId }: ChatInterfaceProps) {
return (
{messages &&
-
+
}
-
{error && (
@@ -156,10 +121,16 @@ export default function ChatInterface({ sessionId }: ChatInterfaceProps) {