From 3f3d341559946862a1e7f49aca38c3a956069b98 Mon Sep 17 00:00:00 2001 From: Arpit Gupta Date: Mon, 30 Mar 2026 23:35:51 +0530 Subject: [PATCH 1/3] feat: migrate chat delete flow to dedicated api --- app/api/room/delete/route.ts | 62 ------------------- .../Modals/DeleteConfirmationModal.tsx | 26 ++++++-- 2 files changed, 20 insertions(+), 68 deletions(-) delete mode 100644 app/api/room/delete/route.ts diff --git a/app/api/room/delete/route.ts b/app/api/room/delete/route.ts deleted file mode 100644 index aa22e167c..000000000 --- a/app/api/room/delete/route.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { NextRequest } from "next/server"; -import supabase from "@/lib/supabase/serverClient"; - -export async function POST(req: NextRequest) { - try { - const { roomId } = await req.json(); - - if (!roomId) { - return Response.json( - { message: "Missing required parameter: roomId" }, - { status: 400 } - ); - } - - // First delete any related data - // Delete messages in this room - const { error: messagesError } = await supabase - .from("messages") - .delete() - .eq("room_id", roomId); - - if (messagesError) { - console.error("Error deleting messages:", messagesError); - // Continue with the deletion process even if this fails - } - - // Delete room_reports associations - const { error: reportError } = await supabase - .from("room_reports") - .delete() - .eq("room_id", roomId); - - if (reportError) { - console.error("Error deleting room reports:", reportError); - // Continue with the deletion process even if this fails - } - - // Finally delete the room itself - const { error } = await supabase - .from("rooms") - .delete() - .eq("id", roomId); - - if (error) { - console.error("Error deleting room:", error); - return Response.json( - { message: "Failed to delete room", error: error.message }, - { status: 500 } - ); - } - - return Response.json({ message: "Room deleted successfully" }, { status: 200 }); - } catch (error) { - console.error("Error in /api/room/delete:", error); - const message = error instanceof Error ? error.message : "Server error"; - return Response.json({ message }, { status: 500 }); - } -} - -export const dynamic = "force-dynamic"; -export const fetchCache = "force-no-store"; -export const revalidate = 0; \ No newline at end of file diff --git a/components/Sidebar/Modals/DeleteConfirmationModal.tsx b/components/Sidebar/Modals/DeleteConfirmationModal.tsx index 33abc4bc0..0429702a0 100644 --- a/components/Sidebar/Modals/DeleteConfirmationModal.tsx +++ b/components/Sidebar/Modals/DeleteConfirmationModal.tsx @@ -2,6 +2,9 @@ import { useState, useEffect } from "react"; import Modal from "@/components/Modal"; import type { Conversation } from "@/types/Chat"; import type { ArtistAgent } from "@/lib/supabase/getArtistAgents"; +import { useAccessToken } from "@/hooks/useAccessToken"; +import { useApiOverride } from "@/hooks/useApiOverride"; +import { NEW_API_BASE_URL } from "@/lib/consts"; interface DeleteConfirmationModalProps { isOpen: boolean; @@ -20,6 +23,9 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet const [isDeleting, setIsDeleting] = useState(false); const [error, setError] = useState(""); const [deletingProgress, setDeletingProgress] = useState<{ current: number; total: number } | null>(null); + const accessToken = useAccessToken(); + const apiOverride = useApiOverride(); + const baseUrl = apiOverride || NEW_API_BASE_URL; // Reset state when modal opens/closes useEffect(() => { @@ -48,6 +54,11 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet : 'Delete'; const handleDelete = async () => { + if (!accessToken) { + setError("Authentication token is missing. Please refresh and try again."); + return; + } + setIsDeleting(true); setError(""); setDeletingProgress({ current: 0, total: chatCount }); @@ -62,16 +73,19 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet try { const roomId = getChatId(chat); - const response = await fetch('/api/room/delete', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ roomId }), + const response = await fetch(`${baseUrl}/api/chats`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + }, + body: JSON.stringify({ id: roomId }), }); const result = await response.json(); if (!response.ok) { - throw new Error(result.message || 'Failed to delete chat'); + throw new Error(result.message || result.error || "Failed to delete chat"); } } catch (chatError) { console.error(`Error deleting chat ${getChatName(chat)}:`, chatError); @@ -151,4 +165,4 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet ); }; -export default DeleteConfirmationModal; \ No newline at end of file +export default DeleteConfirmationModal; From 6e4a20f4cf205effc9cdb239da9509f50dd61e59 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 30 Mar 2026 21:53:59 -0500 Subject: [PATCH 2/3] refactor: extract useDeleteChat hook for SRP - Move API call logic (auth, fetch, error handling) into hooks/useDeleteChat.ts - DeleteConfirmationModal now delegates to the hook - Remove dead result.message check (API returns result.error) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Modals/DeleteConfirmationModal.tsx | 58 +++++++------------ hooks/useDeleteChat.ts | 36 ++++++++++++ 2 files changed, 56 insertions(+), 38 deletions(-) create mode 100644 hooks/useDeleteChat.ts diff --git a/components/Sidebar/Modals/DeleteConfirmationModal.tsx b/components/Sidebar/Modals/DeleteConfirmationModal.tsx index 0429702a0..d10ceee6b 100644 --- a/components/Sidebar/Modals/DeleteConfirmationModal.tsx +++ b/components/Sidebar/Modals/DeleteConfirmationModal.tsx @@ -2,9 +2,7 @@ import { useState, useEffect } from "react"; import Modal from "@/components/Modal"; import type { Conversation } from "@/types/Chat"; import type { ArtistAgent } from "@/lib/supabase/getArtistAgents"; -import { useAccessToken } from "@/hooks/useAccessToken"; -import { useApiOverride } from "@/hooks/useApiOverride"; -import { NEW_API_BASE_URL } from "@/lib/consts"; +import { useDeleteChat } from "@/hooks/useDeleteChat"; interface DeleteConfirmationModalProps { isOpen: boolean; @@ -23,10 +21,8 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet const [isDeleting, setIsDeleting] = useState(false); const [error, setError] = useState(""); const [deletingProgress, setDeletingProgress] = useState<{ current: number; total: number } | null>(null); - const accessToken = useAccessToken(); - const apiOverride = useApiOverride(); - const baseUrl = apiOverride || NEW_API_BASE_URL; - + const { deleteChat, isAuthenticated } = useDeleteChat(); + // Reset state when modal opens/closes useEffect(() => { if (!isOpen) { @@ -39,22 +35,22 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet return () => clearTimeout(timer); } }, [isOpen]); - + // Determine if this is bulk delete or single delete const isBulkDelete = chatRooms && chatRooms.length > 0; const chatsToDelete = isBulkDelete ? chatRooms : (chatRoom ? [chatRoom] : []); - + if (!isOpen || chatsToDelete.length === 0) return null; - + const chatCount = chatsToDelete.length; const isSingleDelete = chatCount === 1; const chatName = isSingleDelete ? getChatName(chatsToDelete[0]) : `${chatCount} chats`; - const buttonText = isDeleting - ? (deletingProgress ? `Deleting ${deletingProgress.current}/${deletingProgress.total}...` : 'Deleting...') + const buttonText = isDeleting + ? (deletingProgress ? `Deleting ${deletingProgress.current}/${deletingProgress.total}...` : 'Deleting...') : 'Delete'; - + const handleDelete = async () => { - if (!accessToken) { + if (!isAuthenticated) { setError("Authentication token is missing. Please refresh and try again."); return; } @@ -62,37 +58,23 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet setIsDeleting(true); setError(""); setDeletingProgress({ current: 0, total: chatCount }); - + try { const failedChats: string[] = []; - + // Delete each chat sequentially for (let i = 0; i < chatsToDelete.length; i++) { const chat = chatsToDelete[i]; setDeletingProgress({ current: i + 1, total: chatCount }); - + try { - const roomId = getChatId(chat); - const response = await fetch(`${baseUrl}/api/chats`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }, - body: JSON.stringify({ id: roomId }), - }); - - const result = await response.json(); - - if (!response.ok) { - throw new Error(result.message || result.error || "Failed to delete chat"); - } + await deleteChat(getChatId(chat)); } catch (chatError) { console.error(`Error deleting chat ${getChatName(chat)}:`, chatError); failedChats.push(getChatName(chat)); } } - + // If some deletions failed, show error if (failedChats.length > 0) { setError(`Failed to delete: ${failedChats.join(', ')}`); @@ -102,10 +84,10 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet await onDelete(); return; } - + // Call the onDelete callback to update the UI and wait for it to complete await onDelete(); - + // Only close the modal after deletion and UI refresh are complete onClose(); } catch (error) { @@ -132,13 +114,13 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet

Are you sure you want to delete {isSingleDelete ? `"${chatName}"` : chatName}? This action cannot be undone.

- + {error && (
{error}
)} - +