diff --git a/frontend/src/pages/GeneralSettings/Chats/index.jsx b/frontend/src/pages/GeneralSettings/Chats/index.jsx index d5b3d50932d0823b42434fa98edc8e2775ec5ee1..52a3c43404d799053ccb1b1bbde1472f9a0ed673 100644 --- a/frontend/src/pages/GeneralSettings/Chats/index.jsx +++ b/frontend/src/pages/GeneralSettings/Chats/index.jsx @@ -7,7 +7,7 @@ import useQuery from "@/hooks/useQuery"; import ChatRow from "./ChatRow"; import showToast from "@/utils/toast"; import System from "@/models/system"; -import { CaretDown, Download } from "@phosphor-icons/react"; +import { CaretDown, Download, Trash } from "@phosphor-icons/react"; import { saveAs } from "file-saver"; const exportOptions = { @@ -49,6 +49,12 @@ export default function WorkspaceChats() { const [showMenu, setShowMenu] = useState(false); const menuRef = useRef(); const openMenuButton = useRef(); + const query = useQuery(); + const [loading, setLoading] = useState(true); + const [chats, setChats] = useState([]); + const [offset, setOffset] = useState(Number(query.get("offset") || 0)); + const [canNext, setCanNext] = useState(false); + const handleDumpChats = async (exportType) => { const chats = await System.exportChats(exportType); if (!!chats) { @@ -62,6 +68,18 @@ export default function WorkspaceChats() { } }; + const handleClearAllChats = async () => { + if ( + !window.confirm( + `Are you sure you want to clear all chats?\n\nThis action is irreversible.` + ) + ) + return false; + await System.deleteChat(-1); + setChats([]); + showToast("Cleared all chats.", "success"); + }; + const toggleMenu = () => { setShowMenu(!showMenu); }; @@ -83,6 +101,16 @@ export default function WorkspaceChats() { }; }, []); + useEffect(() => { + async function fetchChats() { + const { chats: _chats, hasPages = false } = await System.chats(offset); + setChats(_chats); + setCanNext(hasPages); + setLoading(false); + } + fetchChats(); + }, [offset]); + return ( <div className="w-screen h-screen overflow-hidden bg-sidebar flex"> <Sidebar /> @@ -100,7 +128,7 @@ export default function WorkspaceChats() { <button ref={openMenuButton} onClick={toggleMenu} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" + className="flex items-center gap-x-2 px-4 py-1 rounded-lg bg-[#46C8FF] hover:text-white text-xs font-semibold hover:bg-[#2C2F36] shadow-[0_4px_14px_rgba(0,0,0,0.25)] h-[34px] w-fit" > <Download size={18} weight="bold" /> Export @@ -128,26 +156,43 @@ export default function WorkspaceChats() { </div> </div> </div> + {chats.length > 0 && ( + <button + onClick={handleClearAllChats} + className="flex items-center gap-x-2 px-4 py-1 border hover:border-transparent border-white/40 text-white/40 rounded-lg bg-transparent hover:text-white text-xs font-semibold hover:bg-red-500 shadow-[0_4px_14px_rgba(0,0,0,0.25)] h-[34px] w-fit" + > + <Trash size={18} weight="bold" /> + Clear Chats + </button> + )} </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> These are all the recorded chats and messages that have been sent by users ordered by their creation date. </p> </div> - <ChatsContainer /> + <ChatsContainer + loading={loading} + chats={chats} + setChats={setChats} + offset={offset} + setOffset={setOffset} + canNext={canNext} + /> </div> </div> </div> ); } -function ChatsContainer() { - const query = useQuery(); - const [loading, setLoading] = useState(true); - const [chats, setChats] = useState([]); - const [offset, setOffset] = useState(Number(query.get("offset") || 0)); - const [canNext, setCanNext] = useState(false); - +function ChatsContainer({ + loading, + chats, + setChats, + offset, + setOffset, + canNext, +}) { const handlePrevious = () => { setOffset(Math.max(offset - 1, 0)); }; @@ -155,20 +200,11 @@ function ChatsContainer() { setOffset(offset + 1); }; - const handleDeleteChat = (chatId) => { + const handleDeleteChat = async (chatId) => { + await System.deleteChat(chatId); setChats((prevChats) => prevChats.filter((chat) => chat.id !== chatId)); }; - useEffect(() => { - async function fetchChats() { - const { chats: _chats, hasPages = false } = await System.chats(offset); - setChats(_chats); - setCanNext(hasPages); - setLoading(false); - } - fetchChats(); - }, [offset]); - if (loading) { return ( <Skeleton.default diff --git a/server/endpoints/system.js b/server/endpoints/system.js index 6c941b1cc23d74d18cac2a8f833365489fdf40ec..f87eb7baaf0868b9780d9f7c97d97536b65f35e1 100644 --- a/server/endpoints/system.js +++ b/server/endpoints/system.js @@ -976,7 +976,9 @@ function systemEndpoints(app) { async (request, response) => { try { const { id } = request.params; - await WorkspaceChats.delete({ id: Number(id) }); + Number(id) === -1 + ? await WorkspaceChats.delete({}, true) + : await WorkspaceChats.delete({ id: Number(id) }); response.json({ success: true, error: null }); } catch (e) { console.error(e);