diff --git a/app/(chat)/api/history/route.ts b/app/(chat)/api/history/route.ts index 412f10f..2525a9a 100644 --- a/app/(chat)/api/history/route.ts +++ b/app/(chat)/api/history/route.ts @@ -1,6 +1,6 @@ import type { NextRequest } from "next/server"; import { auth } from "@/app/(auth)/auth"; -import { getChatsByUserId } from "@/lib/db/queries"; +import { getChatsByUserId, deleteAllChatsByUserId } from "@/lib/db/queries"; import { ChatSDKError } from "@/lib/errors"; export async function GET(request: NextRequest) { @@ -32,3 +32,15 @@ export async function GET(request: NextRequest) { return Response.json(chats); } + +export async function DELETE() { + const session = await auth(); + + if (!session?.user) { + return new ChatSDKError("unauthorized:chat").toResponse(); + } + + const result = await deleteAllChatsByUserId({ userId: session.user.id }); + + return Response.json(result, { status: 200 }); +} diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index 7e9b344..5210804 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -3,8 +3,12 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; import type { User } from "next-auth"; -import { PlusIcon } from "@/components/icons"; -import { SidebarHistory } from "@/components/sidebar-history"; +import { useState } from "react"; +import { toast } from "sonner"; +import { useSWRConfig } from "swr"; +import { unstable_serialize } from "swr/infinite"; +import { PlusIcon, TrashIcon } from "@/components/icons"; +import { SidebarHistory, getChatHistoryPaginationKey } from "@/components/sidebar-history"; import { SidebarUserNav } from "@/components/sidebar-user-nav"; import { Button } from "@/components/ui/button"; import { @@ -16,53 +20,121 @@ import { useSidebar, } from "@/components/ui/sidebar"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "./ui/alert-dialog"; export function AppSidebar({ user }: { user: User | undefined }) { const router = useRouter(); const { setOpenMobile } = useSidebar(); + const { mutate } = useSWRConfig(); + const [showDeleteAllDialog, setShowDeleteAllDialog] = useState(false); + + const handleDeleteAll = () => { + const deletePromise = fetch("/api/history", { + method: "DELETE", + }); + + toast.promise(deletePromise, { + loading: "Deleting all chats...", + success: () => { + mutate(unstable_serialize(getChatHistoryPaginationKey)); + router.push("/"); + setShowDeleteAllDialog(false); + return "All chats deleted successfully"; + }, + error: "Failed to delete all chats", + }); + }; return ( - - - -
- { - setOpenMobile(false); - }} - > - - Chatbot - - - - - - - - New Chat - - -
-
-
- - - - {user && } -
+ <> + + + +
+ { + setOpenMobile(false); + }} + > + + Chatbot + + +
+ {user && ( + + + + + + Delete All Chats + + + )} + + + + + + New Chat + + +
+
+
+
+ + + + {user && } +
+ + + + + Delete all chats? + + This action cannot be undone. This will permanently delete all your + chats and remove them from our servers. + + + + Cancel + + Delete All + + + + + ); } diff --git a/lib/db/queries.ts b/lib/db/queries.ts index 7772160..d691a88 100644 --- a/lib/db/queries.ts +++ b/lib/db/queries.ts @@ -123,6 +123,37 @@ export async function deleteChatById({ id }: { id: string }) { } } +export async function deleteAllChatsByUserId({ userId }: { userId: string }) { + try { + const userChats = await db + .select({ id: chat.id }) + .from(chat) + .where(eq(chat.userId, userId)); + + if (userChats.length === 0) { + return { deletedCount: 0 }; + } + + const chatIds = userChats.map(c => c.id); + + await db.delete(vote).where(inArray(vote.chatId, chatIds)); + await db.delete(message).where(inArray(message.chatId, chatIds)); + await db.delete(stream).where(inArray(stream.chatId, chatIds)); + + const deletedChats = await db + .delete(chat) + .where(eq(chat.userId, userId)) + .returning(); + + return { deletedCount: deletedChats.length }; + } catch (_error) { + throw new ChatSDKError( + "bad_request:database", + "Failed to delete all chats by user id" + ); + } +} + export async function getChatsByUserId({ id, limit,