mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-09 07:42:39 +02:00
add delete chat mutation
This commit is contained in:
parent
bd4e5d627d
commit
b866170e6a
11 changed files with 486 additions and 445 deletions
|
|
@ -13,10 +13,15 @@ import {
|
||||||
import { AnimatePresence, motion, type Variants } from "motion/react";
|
import { AnimatePresence, motion, type Variants } from "motion/react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
import {
|
||||||
|
Card,
|
||||||
|
CardDescription,
|
||||||
|
CardFooter,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
|
@ -49,9 +54,9 @@ import {
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { cn } from "@/lib/utils";
|
import { useAtom, useAtomValue } from "jotai";
|
||||||
import { useAtomValue } from "jotai";
|
import { activeSearchSpaceChatsAtom } from "@/atoms/chats/queries/active-search-space-chats.query.atom";
|
||||||
import { activeSearchSpaceChatsAtom } from "@/atoms/chats/queries/active-search-space-chats.atom";
|
import { deleteChatMutationAtom } from "@/atoms/chats/mutations/delete-chat.mutation.atom";
|
||||||
|
|
||||||
export interface Chat {
|
export interface Chat {
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
|
@ -91,7 +96,9 @@ const chatCardVariants: Variants = {
|
||||||
|
|
||||||
const MotionCard = motion(Card);
|
const MotionCard = motion(Card);
|
||||||
|
|
||||||
export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps) {
|
export default function ChatsPageClient({
|
||||||
|
searchSpaceId,
|
||||||
|
}: ChatsPageClientProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [filteredChats, setFilteredChats] = useState<Chat[]>([]);
|
const [filteredChats, setFilteredChats] = useState<Chat[]>([]);
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
|
@ -100,9 +107,18 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
const [selectedType, setSelectedType] = useState<string>("all");
|
const [selectedType, setSelectedType] = useState<string>("all");
|
||||||
const [sortOrder, setSortOrder] = useState<string>("newest");
|
const [sortOrder, setSortOrder] = useState<string>("newest");
|
||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
const [chatToDelete, setChatToDelete] = useState<{ id: number; title: string } | null>(null);
|
const [chatToDelete, setChatToDelete] = useState<{
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
id: number;
|
||||||
const {isFetching , data : chats, error} = useAtomValue(activeSearchSpaceChatsAtom);
|
title: string;
|
||||||
|
} | null>(null);
|
||||||
|
const {
|
||||||
|
isFetching: isFetchingChats,
|
||||||
|
data: chats,
|
||||||
|
error: fetchError,
|
||||||
|
} = useAtomValue(activeSearchSpaceChatsAtom);
|
||||||
|
const [
|
||||||
|
{ isPending: isDeletingChat, mutateAsync: deleteChat, error: deleteError }
|
||||||
|
] = useAtom(deleteChatMutationAtom);
|
||||||
|
|
||||||
const chatsPerPage = 9;
|
const chatsPerPage = 9;
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
@ -118,12 +134,17 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
}
|
}
|
||||||
}, [searchParams]);
|
}, [searchParams]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (fetchError) {
|
||||||
|
console.error("Error fetching chats:", fetchError);
|
||||||
|
}
|
||||||
|
}, [fetchError]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (error) {
|
if (deleteError) {
|
||||||
console.error("Error fetching chats:", error);
|
console.error("Error deleting chat:", deleteError);
|
||||||
}
|
}
|
||||||
}, [error]);
|
}, [deleteError]);
|
||||||
|
|
||||||
// Filter and sort chats based on search query, type, and sort order
|
// Filter and sort chats based on search query, type, and sort order
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -132,7 +153,9 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
// Filter by search term
|
// Filter by search term
|
||||||
if (searchQuery) {
|
if (searchQuery) {
|
||||||
const query = searchQuery.toLowerCase();
|
const query = searchQuery.toLowerCase();
|
||||||
result = result.filter((chat) => chat.title.toLowerCase().includes(query));
|
result = result.filter((chat) =>
|
||||||
|
chat.title.toLowerCase().includes(query)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter by type
|
// Filter by type
|
||||||
|
|
@ -152,49 +175,22 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
setTotalPages(Math.max(1, Math.ceil(result.length / chatsPerPage)));
|
setTotalPages(Math.max(1, Math.ceil(result.length / chatsPerPage)));
|
||||||
|
|
||||||
// Reset to first page when filters change
|
// Reset to first page when filters change
|
||||||
if (currentPage !== 1 && (searchQuery || selectedType !== "all" || sortOrder !== "newest")) {
|
if (
|
||||||
|
currentPage !== 1 &&
|
||||||
|
(searchQuery || selectedType !== "all" || sortOrder !== "newest")
|
||||||
|
) {
|
||||||
setCurrentPage(1);
|
setCurrentPage(1);
|
||||||
}
|
}
|
||||||
}, [chats, searchQuery, selectedType, sortOrder, currentPage]);
|
}, [chats, searchQuery, selectedType, sortOrder, currentPage]);
|
||||||
|
|
||||||
// Function to handle chat deletion
|
// Function to handle chat deletion
|
||||||
const handleDeleteChat = async () => {
|
const handleDeleteChat = async () => {
|
||||||
// if (!chatToDelete) return;
|
if (!chatToDelete) return;
|
||||||
|
|
||||||
// setIsDeleting(true);
|
await deleteChat(chatToDelete.id);
|
||||||
// try {
|
|
||||||
// const token = localStorage.getItem("surfsense_bearer_token");
|
|
||||||
// if (!token) {
|
|
||||||
// setIsDeleting(false);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const response = await fetch(
|
setDeleteDialogOpen(false);
|
||||||
// `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/chats/${chatToDelete.id}`,
|
setChatToDelete(null);
|
||||||
// {
|
|
||||||
// method: "DELETE",
|
|
||||||
// headers: {
|
|
||||||
// Authorization: `Bearer ${token}`,
|
|
||||||
// "Content-Type": "application/json",
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (!response.ok) {
|
|
||||||
// throw new Error(`Failed to delete chat: ${response.statusText}`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Close dialog and refresh chats
|
|
||||||
// setDeleteDialogOpen(false);
|
|
||||||
// setChatToDelete(null);
|
|
||||||
|
|
||||||
// // Update local state by removing the deleted chat
|
|
||||||
// setChats((prevChats) => prevChats.filter((chat) => chat.id !== chatToDelete.id));
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Error deleting chat:", error);
|
|
||||||
// } finally {
|
|
||||||
// setIsDeleting(false);
|
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate pagination
|
// Calculate pagination
|
||||||
|
|
@ -203,7 +199,9 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
const currentChats = filteredChats.slice(indexOfFirstChat, indexOfLastChat);
|
const currentChats = filteredChats.slice(indexOfFirstChat, indexOfLastChat);
|
||||||
|
|
||||||
// Get unique chat types for filter dropdown
|
// Get unique chat types for filter dropdown
|
||||||
const chatTypes = chats ? ["all", ...Array.from(new Set(chats.map((chat) => chat.type)))] : [];
|
const chatTypes = chats
|
||||||
|
? ["all", ...Array.from(new Set(chats.map((chat) => chat.type)))]
|
||||||
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
|
|
@ -216,7 +214,9 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
<div className="flex flex-col space-y-4 md:space-y-6">
|
<div className="flex flex-col space-y-4 md:space-y-6">
|
||||||
<div className="flex flex-col space-y-2">
|
<div className="flex flex-col space-y-2">
|
||||||
<h1 className="text-3xl font-bold tracking-tight">All Chats</h1>
|
<h1 className="text-3xl font-bold tracking-tight">All Chats</h1>
|
||||||
<p className="text-muted-foreground">View, search, and manage all your chats.</p>
|
<p className="text-muted-foreground">
|
||||||
|
View, search, and manage all your chats.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Filter and Search Bar */}
|
{/* Filter and Search Bar */}
|
||||||
|
|
@ -241,7 +241,9 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
{chatTypes.map((type) => (
|
{chatTypes.map((type) => (
|
||||||
<SelectItem key={type} value={type}>
|
<SelectItem key={type} value={type}>
|
||||||
{type === "all" ? "All Types" : type.charAt(0).toUpperCase() + type.slice(1)}
|
{type === "all"
|
||||||
|
? "All Types"
|
||||||
|
: type.charAt(0).toUpperCase() + type.slice(1)}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
|
|
@ -265,7 +267,7 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Status Messages */}
|
{/* Status Messages */}
|
||||||
{isFetching && (
|
{isFetchingChats && (
|
||||||
<div className="flex items-center justify-center h-40">
|
<div className="flex items-center justify-center h-40">
|
||||||
<div className="flex flex-col items-center gap-2">
|
<div className="flex flex-col items-center gap-2">
|
||||||
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent"></div>
|
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent"></div>
|
||||||
|
|
@ -274,14 +276,14 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{error && !isFetching && (
|
{fetchError && !isFetchingChats && (
|
||||||
<div className="border border-destructive/50 text-destructive p-4 rounded-md">
|
<div className="border border-destructive/50 text-destructive p-4 rounded-md">
|
||||||
<h3 className="font-medium">Error loading chats</h3>
|
<h3 className="font-medium">Error loading chats</h3>
|
||||||
<p className="text-sm">{error.message}</p>
|
<p className="text-sm">{fetchError.message}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isFetching && !error && filteredChats.length === 0 && (
|
{!isFetchingChats && !fetchError && filteredChats.length === 0 && (
|
||||||
<div className="flex flex-col items-center justify-center h-40 gap-2 text-center">
|
<div className="flex flex-col items-center justify-center h-40 gap-2 text-center">
|
||||||
<MessageCircleMore className="h-8 w-8 text-muted-foreground" />
|
<MessageCircleMore className="h-8 w-8 text-muted-foreground" />
|
||||||
<h3 className="font-medium">No chats found</h3>
|
<h3 className="font-medium">No chats found</h3>
|
||||||
|
|
@ -294,7 +296,7 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Chat Grid */}
|
{/* Chat Grid */}
|
||||||
{!isFetching && !error && filteredChats.length > 0 && (
|
{!isFetchingChats && !fetchError && filteredChats.length > 0 && (
|
||||||
<AnimatePresence mode="wait">
|
<AnimatePresence mode="wait">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
{currentChats.map((chat, index) => (
|
{currentChats.map((chat, index) => (
|
||||||
|
|
@ -316,13 +318,19 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
<span className="flex items-center gap-1">
|
<span className="flex items-center gap-1">
|
||||||
<Calendar className="h-3.5 w-3.5" />
|
<Calendar className="h-3.5 w-3.5" />
|
||||||
<span>{format(new Date(chat.created_at), "MMM d, yyyy")}</span>
|
<span>
|
||||||
|
{format(new Date(chat.created_at), "MMM d, yyyy")}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant="ghost" size="icon" className="h-8 w-8">
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="h-8 w-8"
|
||||||
|
>
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
<span className="sr-only">Open menu</span>
|
<span className="sr-only">Open menu</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -366,7 +374,9 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
router.push(`/dashboard/${chat.search_space_id}/researcher/${chat.id}`)
|
router.push(
|
||||||
|
`/dashboard/${chat.search_space_id}/researcher/${chat.id}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<MessageCircleMore className="h-4 w-4" />
|
<MessageCircleMore className="h-4 w-4" />
|
||||||
|
|
@ -380,7 +390,7 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Pagination */}
|
{/* Pagination */}
|
||||||
{!isFetching && !error && totalPages > 1 && (
|
{!isFetchingChats && !fetchError && totalPages > 1 && (
|
||||||
<Pagination className="mt-8">
|
<Pagination className="mt-8">
|
||||||
<PaginationContent>
|
<PaginationContent>
|
||||||
<PaginationItem>
|
<PaginationItem>
|
||||||
|
|
@ -390,7 +400,9 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (currentPage > 1) setCurrentPage(currentPage - 1);
|
if (currentPage > 1) setCurrentPage(currentPage - 1);
|
||||||
}}
|
}}
|
||||||
className={currentPage <= 1 ? "pointer-events-none opacity-50" : ""}
|
className={
|
||||||
|
currentPage <= 1 ? "pointer-events-none opacity-50" : ""
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
|
|
||||||
|
|
@ -399,14 +411,17 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
const isVisible =
|
const isVisible =
|
||||||
pageNumber === 1 ||
|
pageNumber === 1 ||
|
||||||
pageNumber === totalPages ||
|
pageNumber === totalPages ||
|
||||||
(pageNumber >= currentPage - 1 && pageNumber <= currentPage + 1);
|
(pageNumber >= currentPage - 1 &&
|
||||||
|
pageNumber <= currentPage + 1);
|
||||||
|
|
||||||
if (!isVisible) {
|
if (!isVisible) {
|
||||||
// Show ellipsis at appropriate positions
|
// Show ellipsis at appropriate positions
|
||||||
if (pageNumber === 2 || pageNumber === totalPages - 1) {
|
if (pageNumber === 2 || pageNumber === totalPages - 1) {
|
||||||
return (
|
return (
|
||||||
<PaginationItem key={pageNumber}>
|
<PaginationItem key={pageNumber}>
|
||||||
<span className="flex h-9 w-9 items-center justify-center">...</span>
|
<span className="flex h-9 w-9 items-center justify-center">
|
||||||
|
...
|
||||||
|
</span>
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -434,9 +449,14 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
href={`?page=${Math.min(totalPages, currentPage + 1)}`}
|
href={`?page=${Math.min(totalPages, currentPage + 1)}`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (currentPage < totalPages) setCurrentPage(currentPage + 1);
|
if (currentPage < totalPages)
|
||||||
|
setCurrentPage(currentPage + 1);
|
||||||
}}
|
}}
|
||||||
className={currentPage >= totalPages ? "pointer-events-none opacity-50" : ""}
|
className={
|
||||||
|
currentPage >= totalPages
|
||||||
|
? "pointer-events-none opacity-50"
|
||||||
|
: ""
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
</PaginationContent>
|
</PaginationContent>
|
||||||
|
|
@ -454,25 +474,25 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Are you sure you want to delete{" "}
|
Are you sure you want to delete{" "}
|
||||||
<span className="font-medium">{chatToDelete?.title}</span>? This action cannot be
|
<span className="font-medium">{chatToDelete?.title}</span>? This
|
||||||
undone.
|
action cannot be undone.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogFooter className="flex gap-2 sm:justify-end">
|
<DialogFooter className="flex gap-2 sm:justify-end">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => setDeleteDialogOpen(false)}
|
onClick={() => setDeleteDialogOpen(false)}
|
||||||
disabled={isDeleting}
|
disabled={isDeletingChat}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
onClick={handleDeleteChat}
|
onClick={handleDeleteChat}
|
||||||
disabled={isDeleting}
|
disabled={isDeletingChat}
|
||||||
className="gap-2"
|
className="gap-2"
|
||||||
>
|
>
|
||||||
{isDeleting ? (
|
{isDeletingChat ? (
|
||||||
<>
|
<>
|
||||||
<span className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
|
<span className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
|
||||||
Deleting...
|
Deleting...
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ import {
|
||||||
} from "@/components/ui/sidebar";
|
} from "@/components/ui/sidebar";
|
||||||
import { useLLMPreferences } from "@/hooks/use-llm-configs";
|
import { useLLMPreferences } from "@/hooks/use-llm-configs";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { activeChatIdAtom } from "@/atoms/chats/queries/active-chat.atom";
|
import { activeChatIdAtom } from "@/atoms/chats/queries/active-chat.query.atom";
|
||||||
import { chatUIAtom } from "@/atoms/chats/active-chat-ui.atom";
|
import { chatUIAtom } from "@/atoms/chats/active-chat.atom";
|
||||||
import { activeSearchSpaceIdAtom } from "@/atoms/seach-spaces/active-seach-space.atom";
|
import { activeSearchSpaceIdAtom } from "@/atoms/seach-spaces/active-seach-space.atom";
|
||||||
|
|
||||||
export function DashboardClientLayout({
|
export function DashboardClientLayout({
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { atomWithMutation } from "jotai-tanstack-query";
|
||||||
|
import { deleteChat } from "@/lib/apis/chat-apis";
|
||||||
|
import { activeSearchSpaceIdAtom } from "../../seach-spaces/active-seach-space.atom";
|
||||||
|
import { queryClient } from "@/lib/query-client/client";
|
||||||
|
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export const deleteChatMutationAtom = atomWithMutation((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
const authToken = localStorage.getItem("surfsense_bearer_token");
|
||||||
|
|
||||||
|
return {
|
||||||
|
mutationKey: cacheKeys.activeSearchSpace.chats(searchSpaceId ?? ""),
|
||||||
|
enabled: !!searchSpaceId && !!authToken,
|
||||||
|
mutationFn: async (chatId: number) => {
|
||||||
|
if (!authToken) {
|
||||||
|
throw new Error("No authentication token found");
|
||||||
|
}
|
||||||
|
if (!searchSpaceId) {
|
||||||
|
throw new Error("No search space id found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return deleteChat(chatId, authToken);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success("Chat deleted successfully");
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.activeSearchSpace.chats(searchSpaceId!),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
@ -18,18 +18,8 @@ export const activeChatAtom = atomWithQuery<ActiveChatState>((get) => {
|
||||||
const activeChatId = get(activeChatIdAtom);
|
const activeChatId = get(activeChatIdAtom);
|
||||||
const authToken = localStorage.getItem("surfsense_bearer_token");
|
const authToken = localStorage.getItem("surfsense_bearer_token");
|
||||||
|
|
||||||
if (!activeChatId) {
|
|
||||||
return {
|
return {
|
||||||
queryKey: [],
|
queryKey: cacheKeys.activeSearchSpace.activeChat(activeChatId ?? ""),
|
||||||
enabled: false,
|
|
||||||
queryFn: async () => {
|
|
||||||
return { chatId: null, chatDetails: null, podcast: null };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
queryKey: cacheKeys.activeSearchSpace.activeChat(activeChatId),
|
|
||||||
enabled: !!activeChatId && !!authToken,
|
enabled: !!activeChatId && !!authToken,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (!authToken) {
|
if (!authToken) {
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import { atomWithQuery } from "jotai-tanstack-query";
|
import { atomWithQuery } from "jotai-tanstack-query";
|
||||||
import { fetchChatsBySearchSpace } from "@/lib/apis/chat-apis";
|
import { fetchChatsBySearchSpace } from "@/lib/apis/chat-apis";
|
||||||
import { activeSearchSpaceIdAtom } from "../../seach-spaces/active-seach-space.atom";
|
import { activeSearchSpaceIdAtom } from "../../seach-spaces/active-seach-space.atom";
|
||||||
|
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||||
|
|
||||||
export const activeSearchSpaceChatsAtom = atomWithQuery((get) => {
|
export const activeSearchSpaceChatsAtom = atomWithQuery((get) => {
|
||||||
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
const authToken = localStorage.getItem("surfsense_bearer_token");
|
const authToken = localStorage.getItem("surfsense_bearer_token");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
queryKey: ["chatsBySearchSpace", searchSpaceId],
|
queryKey: cacheKeys.activeSearchSpace.chats(searchSpaceId ?? ""),
|
||||||
enabled: !!searchSpaceId && !!authToken,
|
enabled: !!searchSpaceId && !!authToken,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (!authToken) {
|
if (!authToken) {
|
||||||
|
|
@ -4,8 +4,8 @@ import { LoaderIcon, PanelRight, TriangleAlert } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { generatePodcast } from "@/lib/apis/podcast-apis";
|
import { generatePodcast } from "@/lib/apis/podcast-apis";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { activeChatAtom, activeChatIdAtom } from "@/atoms/chats/queries/active-chat.atom";
|
import { activeChatAtom, activeChatIdAtom } from "@/atoms/chats/queries/active-chat.query.atom";
|
||||||
import { chatUIAtom } from "@/atoms/chats/active-chat-ui.atom";
|
import { chatUIAtom } from "@/atoms/chats/active-chat.atom";
|
||||||
import { ChatPanelView } from "./ChatPanelView";
|
import { ChatPanelView } from "./ChatPanelView";
|
||||||
|
|
||||||
export interface GeneratePodcastRequest {
|
export interface GeneratePodcastRequest {
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import { AlertCircle, Play, RefreshCw, Sparkles } from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { activeChatAtom } from "@/atoms/chats/queries/active-chat.atom";
|
import { activeChatAtom } from "@/atoms/chats/queries/active-chat.query.atom";
|
||||||
import { chatUIAtom } from "@/atoms/chats/active-chat-ui.atom";
|
import { chatUIAtom } from "@/atoms/chats/active-chat.atom";
|
||||||
import { getPodcastStalenessMessage, isPodcastStale } from "../PodcastUtils";
|
import { getPodcastStalenessMessage, isPodcastStale } from "../PodcastUtils";
|
||||||
import type { GeneratePodcastRequest } from "./ChatPanelContainer";
|
import type { GeneratePodcastRequest } from "./ChatPanelContainer";
|
||||||
import { ConfigModal } from "./ConfigModal";
|
import { ConfigModal } from "./ConfigModal";
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { useAtomValue } from "jotai";
|
||||||
import { Pencil } from "lucide-react";
|
import { Pencil } from "lucide-react";
|
||||||
import { useCallback, useContext, useState } from "react";
|
import { useCallback, useContext, useState } from "react";
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||||
import { activeChatAtom } from "@/atoms/chats/queries/active-chat.atom";
|
import { activeChatAtom } from "@/atoms/chats/queries/active-chat.query.atom";
|
||||||
import type { GeneratePodcastRequest } from "./ChatPanelContainer";
|
import type { GeneratePodcastRequest } from "./ChatPanelContainer";
|
||||||
|
|
||||||
interface ConfigModalProps {
|
interface ConfigModalProps {
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,7 @@ export const deleteChat = async (chatId: number, authToken: string) => {
|
||||||
throw new Error(`Failed to delete chat: ${response.statusText}`);
|
throw new Error(`Failed to delete chat: ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error deleting chat:", err);
|
console.error("Error deleting chat:", err);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,5 @@ export const cacheKeys = {
|
||||||
activeSearchSpace: {
|
activeSearchSpace: {
|
||||||
chats : (searchSpaceId: string) => ["active-search-space", "chats", searchSpaceId] as const,
|
chats : (searchSpaceId: string) => ["active-search-space", "chats", searchSpaceId] as const,
|
||||||
activeChat : (chatId: string) => ["active-search-space", "active-chat", chatId] as const,
|
activeChat : (chatId: string) => ["active-search-space", "active-chat", chatId] as const,
|
||||||
deleteChat : ( searchSpaceId: string, chatId: string) => ["active-search-space", "chats", searchSpaceId, "delete", chatId] as const,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue