diff --git a/www/app/Chat.tsx b/www/app/Chat.tsx index 0e6188e..e32d618 100644 --- a/www/app/Chat.tsx +++ b/www/app/Chat.tsx @@ -18,13 +18,14 @@ import { getFreeMessageCount, useFreeTrial } from '@/utils/supabase/actions'; import { getConversations, createConversation } from './actions/conversations'; import { getMessages, addOrRemoveReaction } from './actions/messages'; import { type Message } from '@/utils/types'; +import { localStorageProvider } from '@/utils/swrCache'; import useAutoScroll from '@/hooks/autoscroll'; const Thoughts = dynamic(() => import('@/components/thoughts'), { ssr: false, }); -// import Thoughts from '@/components/thoughts'; + const MessageBox = dynamic(() => import('@/components/messagebox'), { ssr: false, }); @@ -90,7 +91,6 @@ interface HonchoResponse { content: string; } -// Near the top of the file, add the default message constant const defaultMessage: Message = { content: `I'm your Aristotelian learning companion — here to help you follow your curiosity in whatever direction you like. My engineering makes me extremely receptive to your needs and interests. You can reply normally, and I'll always respond!\n\nIf I'm off track, just say so!\n\nNeed to leave or just done chatting? Let me know! I'm conversational by design so I'll say goodbye 😊.`, isUser: false, @@ -150,29 +150,20 @@ export default function Chat({ return getConversations(); }; - const { data: conversations, mutate: mutateConversations } = useSWR( - userId, - conversationsFetcher, - { - fallbackData: initialConversations, - onSuccess: async (conversations) => { - if (conversations.length) { - if ( - !conversationId || - !conversations.find((c) => c.conversationId === conversationId) - ) { - setConversationId(conversations[0].conversationId); - } - setCanSend(true); - } else { - const newConvo = await createConversation(); - setConversationId(newConvo?.conversationId); - await mutateConversations(); - } - }, - revalidateOnFocus: false, - } - ); + const conversationsKey = useMemo(() => userId, [userId]); + +const { data: conversations, mutate: mutateConversations } = useSWR( + conversationsKey, + conversationsFetcher, + { + fallbackData: initialConversations, + provider: localStorageProvider, + revalidateOnFocus: false, + dedupingInterval: 60000, + revalidateIfStale: false, + revalidateOnMount: false, + } +); const messagesFetcher = async (conversationId: string) => { if (!userId) return Promise.resolve([]); @@ -182,15 +173,21 @@ export default function Chat({ return getMessages(conversationId); }; + const messagesKey = useMemo(() => + conversationId ? ['messages', conversationId] : null, + [conversationId] + ); + const { data: messages, mutate: mutateMessages, isLoading: messagesLoading, } = useSWR( - conversationId ? ['messages', conversationId] : null, + messagesKey, () => messagesFetcher(conversationId!), { fallbackData: initialMessages, + provider: localStorageProvider, revalidateOnFocus: false, revalidateOnReconnect: false, dedupingInterval: 60000, @@ -198,7 +195,7 @@ export default function Chat({ if (conversationId?.startsWith('temp-')) { mutateMessages([], false); } - }, + } } ); diff --git a/www/app/layout.tsx b/www/app/layout.tsx index 2db0e35..ff662aa 100644 --- a/www/app/layout.tsx +++ b/www/app/layout.tsx @@ -2,7 +2,7 @@ import './globals.css'; import 'react-loading-skeleton/dist/skeleton.css'; import type { Metadata } from 'next'; import { Roboto_Mono } from 'next/font/google'; -import { PHProvider, PostHogPageview } from './providers'; +import { PHProvider, PostHogPageview, SWRProvider } from './providers'; import { Suspense } from 'react'; import { Header } from '@/components/header'; import { ThemeProvider } from 'next-themes'; @@ -64,10 +64,12 @@ export default function RootLayout({ -
-
-
{children}
-
+ +
+
+
{children}
+
+
diff --git a/www/app/providers.tsx b/www/app/providers.tsx index 2ce2c66..0e62794 100644 --- a/www/app/providers.tsx +++ b/www/app/providers.tsx @@ -1,9 +1,10 @@ -// app/providers.tsx 'use client'; import posthog from 'posthog-js'; import { PostHogProvider } from 'posthog-js/react'; import { usePathname, useSearchParams } from 'next/navigation'; import { useEffect } from 'react'; +import { SWRConfig } from 'swr'; +import { localStorageProvider } from '@/utils/swrCache'; const posthogKey: string = process.env.NEXT_PUBLIC_POSTHOG_KEY || ''; const posthogHost: string = process.env.NEXT_PUBLIC_POSTHOG_HOST || ''; @@ -40,3 +41,15 @@ export function PostHogPageview(): JSX.Element { export function PHProvider({ children }: { children: React.ReactNode }) { return {children}; } + +export function SWRProvider({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/www/components/sidebar.tsx b/www/components/sidebar.tsx index 3230a4a..26b959b 100644 --- a/www/components/sidebar.tsx +++ b/www/components/sidebar.tsx @@ -7,7 +7,7 @@ import { usePostHog } from 'posthog-js/react'; import Swal from 'sweetalert2'; import { ConversationTab } from './conversationtab'; import { useState } from 'react'; -import useSWR, { KeyedMutator } from 'swr'; +import useSWR, { KeyedMutator, useSWRConfig } from 'swr'; import { FaUser } from 'react-icons/fa'; import { createConversation, @@ -15,11 +15,13 @@ import { updateConversation, } from '@/app/actions/conversations'; import { type Conversation, type Message } from '@/utils/types'; +import { clearSWRCache } from '@/utils/swrCache'; const departureMono = localFont({ src: '../fonts/DepartureMono-Regular.woff2', }); + export default function Sidebar({ conversations, mutateConversations, @@ -41,6 +43,7 @@ export default function Sidebar({ const supabase = createClient(); const [isMenuOpen, setIsMenuOpen] = useState(false); const router = useRouter(); + const { mutate } = useSWRConfig(); async function editConversation(cur: Conversation) { const { value: newName } = await Swal.fire({ @@ -260,9 +263,11 @@ export default function Sidebar({