diff --git a/surfsense_web/app/dashboard/[search_space_id]/chats/chats-client.tsx b/surfsense_web/app/dashboard/[search_space_id]/chats/chats-client.tsx index d7fc5e076..b007892c7 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/chats/chats-client.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/chats/chats-client.tsx @@ -15,7 +15,7 @@ import { AnimatePresence, motion, type Variants } from "motion/react"; import { useRouter, useSearchParams } from "next/navigation"; import { useEffect, useState } from "react"; import { deleteChatMutationAtom } from "@/atoms/chats/chat-mutation.atoms"; -import { activeSearchSpaceChatsAtom } from "@/atoms/chats/chat-querie.atoms"; +import { chatsAtom } from "@/atoms/chats/chat-querie.atoms"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; @@ -103,11 +103,7 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps) id: number; title: string; } | null>(null); - const { - isFetching: isFetchingChats, - data: chats, - error: fetchError, - } = useAtomValue(activeSearchSpaceChatsAtom); + const { isFetching: isFetchingChats, data: chats, error: fetchError } = useAtomValue(chatsAtom); const [{ isPending: isDeletingChat, mutateAsync: deleteChat, error: deleteError }] = useAtom(deleteChatMutationAtom); diff --git a/surfsense_web/atoms/chats/chat-mutation.atoms.ts b/surfsense_web/atoms/chats/chat-mutation.atoms.ts index 305528d2f..382ebb6d3 100644 --- a/surfsense_web/atoms/chats/chat-mutation.atoms.ts +++ b/surfsense_web/atoms/chats/chat-mutation.atoms.ts @@ -6,13 +6,15 @@ import { chatsApiService } from "@/lib/apis/chats-api.service"; import { cacheKeys } from "@/lib/query-client/cache-keys"; import { queryClient } from "@/lib/query-client/client"; import { activeSearchSpaceIdAtom } from "../seach-spaces/seach-space-queries.atom"; +import { globalChatsQueryParamsAtom } from "./ui.atoms"; export const deleteChatMutationAtom = atomWithMutation((get) => { const searchSpaceId = get(activeSearchSpaceIdAtom); const authToken = localStorage.getItem("surfsense_bearer_token"); + const chatsQueryParams = get(globalChatsQueryParamsAtom); return { - mutationKey: cacheKeys.activeSearchSpace.chats(searchSpaceId ?? ""), + mutationKey: cacheKeys.chats.globalQueryParams(chatsQueryParams), enabled: !!searchSpaceId && !!authToken, mutationFn: async (request: DeleteChatRequest) => { return chatsApiService.deleteChat(request); @@ -21,7 +23,7 @@ export const deleteChatMutationAtom = atomWithMutation((get) => { onSuccess: (_, request: DeleteChatRequest) => { toast.success("Chat deleted successfully"); queryClient.setQueryData( - cacheKeys.activeSearchSpace.chats(searchSpaceId!), + cacheKeys.chats.globalQueryParams(chatsQueryParams), (oldData: Chat[]) => { return oldData.filter((chat) => chat.id !== request.id); } diff --git a/surfsense_web/atoms/chats/chat-querie.atoms.ts b/surfsense_web/atoms/chats/chat-querie.atoms.ts index 98b3be55d..26b2b1057 100644 --- a/surfsense_web/atoms/chats/chat-querie.atoms.ts +++ b/surfsense_web/atoms/chats/chat-querie.atoms.ts @@ -3,14 +3,14 @@ import { activeSearchSpaceIdAtom } from "@/atoms/seach-spaces/seach-space-querie import { chatsApiService } from "@/lib/apis/chats-api.service"; import { podcastsApiService } from "@/lib/apis/podcasts-api.service"; import { cacheKeys } from "@/lib/query-client/cache-keys"; -import { activeChatIdAtom } from "./ui.atoms"; +import { activeChatIdAtom, globalChatsQueryParamsAtom } from "./ui.atoms"; export const activeChatAtom = atomWithQuery((get) => { const activeChatId = get(activeChatIdAtom); const authToken = localStorage.getItem("surfsense_bearer_token"); return { - queryKey: cacheKeys.activeSearchSpace.activeChat(activeChatId ?? ""), + queryKey: cacheKeys.chats.activeChat(activeChatId ?? ""), enabled: !!activeChatId && !!authToken, queryFn: async () => { if (!authToken) { @@ -30,16 +30,17 @@ export const activeChatAtom = atomWithQuery((get) => { }; }); -export const activeSearchSpaceChatsAtom = atomWithQuery((get) => { +export const chatsAtom = atomWithQuery((get) => { const searchSpaceId = get(activeSearchSpaceIdAtom); const authToken = localStorage.getItem("surfsense_bearer_token"); + const queryParams = get(globalChatsQueryParamsAtom); return { - queryKey: cacheKeys.activeSearchSpace.chats(searchSpaceId ?? ""), + queryKey: cacheKeys.chats.globalQueryParams(queryParams), enabled: !!searchSpaceId && !!authToken, queryFn: async () => { - return chatsApiService.getChatsBySearchSpace({ - queryParams: { search_space_id: searchSpaceId! }, + return chatsApiService.getChats({ + queryParams: queryParams, }); }, }; diff --git a/surfsense_web/atoms/chats/ui.atoms.ts b/surfsense_web/atoms/chats/ui.atoms.ts index deae59fe3..c92365aef 100644 --- a/surfsense_web/atoms/chats/ui.atoms.ts +++ b/surfsense_web/atoms/chats/ui.atoms.ts @@ -1,4 +1,5 @@ import { atom } from "jotai"; +import type { GetChatsRequest } from "@/contracts/types/chat.types"; type ActiveChathatUIState = { isChatPannelOpen: boolean; @@ -7,4 +8,10 @@ type ActiveChathatUIState = { export const activeChathatUIAtom = atom({ isChatPannelOpen: false, }); + export const activeChatIdAtom = atom(null); + +export const globalChatsQueryParamsAtom = atom({ + limit: 5, + skip: 0, +}); diff --git a/surfsense_web/components/sidebar/AppSidebarProvider.tsx b/surfsense_web/components/sidebar/AppSidebarProvider.tsx index cfccf45a7..2fc323587 100644 --- a/surfsense_web/components/sidebar/AppSidebarProvider.tsx +++ b/surfsense_web/components/sidebar/AppSidebarProvider.tsx @@ -1,8 +1,12 @@ "use client"; +import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { Trash2 } from "lucide-react"; import { useTranslations } from "next-intl"; import { useCallback, useEffect, useMemo, useState } from "react"; +import { deleteChatMutationAtom } from "@/atoms/chats/chat-mutation.atoms"; +import { chatsAtom } from "@/atoms/chats/chat-querie.atoms"; +import { globalChatsQueryParamsAtom } from "@/atoms/chats/ui.atoms"; import { AppSidebar } from "@/components/sidebar/app-sidebar"; import { Button } from "@/components/ui/button"; import { @@ -13,7 +17,7 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; -import { useChats, useSearchSpace, useUser } from "@/hooks"; +import { useSearchSpace, useUser } from "@/hooks"; interface AppSidebarProviderProps { searchSpaceId: string; @@ -41,15 +45,14 @@ export function AppSidebarProvider({ }: AppSidebarProviderProps) { const t = useTranslations("dashboard"); const tCommon = useTranslations("common"); + const setChatsQueryParams = useSetAtom(globalChatsQueryParamsAtom); + const { data: chats, error: chatError, isLoading: isLoadingChats } = useAtomValue(chatsAtom); + const [{ isPending: isDeletingChat, mutateAsync: deleteChat, error: deleteError }] = + useAtom(deleteChatMutationAtom); - // Use the new hooks - const { - chats, - loading: isLoadingChats, - error: chatError, - fetchChats: fetchRecentChats, - deleteChat, - } = useChats({ searchSpaceId, limit: 5, skip: 0 }); + useEffect(() => { + setChatsQueryParams((prev) => ({ ...prev, search_space_id: searchSpaceId, skip: 0, limit: 2 })); + }, [searchSpaceId]); const { searchSpace, @@ -62,7 +65,6 @@ export function AppSidebarProvider({ const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [chatToDelete, setChatToDelete] = useState<{ id: number; name: string } | null>(null); - const [isDeleting, setIsDeleting] = useState(false); const [isClient, setIsClient] = useState(false); // Set isClient to true when component mounts on the client @@ -72,29 +74,30 @@ export function AppSidebarProvider({ // Retry function const retryFetch = useCallback(() => { - fetchRecentChats(); fetchSearchSpace(); - }, [fetchRecentChats, fetchSearchSpace]); + }, [fetchSearchSpace]); // Transform API response to the format expected by AppSidebar const recentChats = useMemo(() => { - return chats.map((chat) => ({ - name: chat.title || `Chat ${chat.id}`, - url: `/dashboard/${chat.search_space_id}/researcher/${chat.id}`, - icon: "MessageCircleMore", - id: chat.id, - search_space_id: chat.search_space_id, - actions: [ - { - name: "Delete", - icon: "Trash2", - onClick: () => { - setChatToDelete({ id: chat.id, name: chat.title || `Chat ${chat.id}` }); - setShowDeleteDialog(true); - }, - }, - ], - })); + return chats + ? chats.map((chat) => ({ + name: chat.title || `Chat ${chat.id}`, + url: `/dashboard/${chat.search_space_id}/researcher/${chat.id}`, + icon: "MessageCircleMore", + id: chat.id, + search_space_id: chat.search_space_id, + actions: [ + { + name: "Delete", + icon: "Trash2", + onClick: () => { + setChatToDelete({ id: chat.id, name: chat.title || `Chat ${chat.id}` }); + setShowDeleteDialog(true); + }, + }, + ], + })) + : []; }, [chats]); // Handle delete chat with better error handling @@ -102,13 +105,11 @@ export function AppSidebarProvider({ if (!chatToDelete) return; try { - setIsDeleting(true); - await deleteChat(chatToDelete.id); + await deleteChat({ id: chatToDelete.id }); } catch (error) { console.error("Error deleting chat:", error); // You could show a toast notification here } finally { - setIsDeleting(false); setShowDeleteDialog(false); setChatToDelete(null); } @@ -226,17 +227,17 @@ export function AppSidebarProvider({