diff --git a/client/src/components/Conversations/Conversation.jsx b/client/src/components/Conversations/Conversation.jsx index f4aaf392fa..c4d5a645c6 100644 --- a/client/src/components/Conversations/Conversation.jsx +++ b/client/src/components/Conversations/Conversation.jsx @@ -1,13 +1,16 @@ -import { useState, useRef, useEffect } from 'react'; +import { useState, useRef } from 'react'; import { useRecoilState, useSetRecoilState } from 'recoil'; import { useUpdateConversationMutation } from 'librechat-data-provider'; -import RenameButton from './RenameButton'; -import DeleteButton from './DeleteButton'; -import { MinimalIcon } from '~/components/Endpoints'; import { useConversations, useConversation } from '~/hooks'; +import { MinimalIcon } from '~/components/Endpoints'; +import { NotificationSeverity } from '~/common'; +import { useToastContext } from '~/Providers'; +import DeleteButton from './DeleteButton'; +import RenameButton from './RenameButton'; import store from '~/store'; export default function Conversation({ conversation, retainView }) { + const { showToast } = useToastContext(); const [currentConversation, setCurrentConversation] = useRecoilState(store.conversation); const setSubmission = useSetRecoilState(store.submission); @@ -63,7 +66,28 @@ export default function Conversation({ conversation, retainView }) { if (titleInput === title) { return; } - updateConvoMutation.mutate({ conversationId, title: titleInput }); + updateConvoMutation.mutate( + { conversationId, title: titleInput }, + { + onSuccess: () => { + refreshConversations(); + if (conversationId == currentConversation?.conversationId) { + setCurrentConversation((prevState) => ({ + ...prevState, + title: titleInput, + })); + } + }, + onError: () => { + setTitleInput(title); + showToast({ + message: 'Failed to rename conversation', + severity: NotificationSeverity.ERROR, + showIcon: true, + }); + }, + }, + ); }; const icon = MinimalIcon({ @@ -74,19 +98,6 @@ export default function Conversation({ conversation, retainView }) { className: 'mr-0', }); - useEffect(() => { - if (updateConvoMutation.isSuccess) { - refreshConversations(); - if (conversationId == currentConversation?.conversationId) { - setCurrentConversation((prevState) => ({ - ...prevState, - title: titleInput, - })); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [updateConvoMutation.isSuccess]); - const handleKeyDown = (e) => { if (e.key === 'Enter') { onRename(e); diff --git a/client/src/components/Conversations/DeleteButton.tsx b/client/src/components/Conversations/DeleteButton.tsx index 4d0545cd93..8ddb1e78ca 100644 --- a/client/src/components/Conversations/DeleteButton.tsx +++ b/client/src/components/Conversations/DeleteButton.tsx @@ -1,4 +1,3 @@ -import { useEffect } from 'react'; import TrashIcon from '../svg/TrashIcon'; import CrossIcon from '../svg/CrossIcon'; import { useRecoilValue } from 'recoil'; @@ -13,24 +12,25 @@ export default function DeleteButton({ conversationId, renaming, retainView, tit const currentConversation = useRecoilValue(store.conversation) || {}; const { newConversation } = useConversation(); const { refreshConversations } = useConversations(); - - const confirmDelete = () => { - deleteConvoMutation.mutate({ conversationId, source: 'button' }); - }; - const deleteConvoMutation = useDeleteConversationMutation(conversationId); - useEffect(() => { - if (deleteConvoMutation.isSuccess) { - if ((currentConversation as { conversationId?: string }).conversationId == conversationId) { - newConversation(); - } + const confirmDelete = () => { + deleteConvoMutation.mutate( + { conversationId, source: 'button' }, + { + onSuccess: () => { + if ( + (currentConversation as { conversationId?: string }).conversationId == conversationId + ) { + newConversation(); + } - refreshConversations(); - retainView(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [deleteConvoMutation.isSuccess]); + refreshConversations(); + retainView(); + }, + }, + ); + }; return ( diff --git a/client/src/components/Input/EndpointMenu/EndpointMenu.jsx b/client/src/components/Input/EndpointMenu/EndpointMenu.jsx index 5a333230ea..08b705ca78 100644 --- a/client/src/components/Input/EndpointMenu/EndpointMenu.jsx +++ b/client/src/components/Input/EndpointMenu/EndpointMenu.jsx @@ -100,7 +100,7 @@ export default function NewConversationMenu() { if (!newEndpoint) { return; } else { - newConversation({}, { endpoint: newEndpoint }); + newConversation(null, { endpoint: newEndpoint }); } }; diff --git a/client/src/components/Nav/ClearConvos.tsx b/client/src/components/Nav/ClearConvos.tsx index bdefb4c53d..96959234eb 100644 --- a/client/src/components/Nav/ClearConvos.tsx +++ b/client/src/components/Nav/ClearConvos.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react'; +import { useState } from 'react'; import { Dialog } from '~/components/ui/'; import DialogTemplate from '~/components/ui/DialogTemplate'; import { ClearChatsButton } from './SettingsTabs/'; @@ -13,23 +13,23 @@ const ClearConvos = ({ open, onOpenChange }) => { const localize = useLocalize(); // Clear all conversations - const clearConvos = useCallback(() => { + const clearConvos = () => { if (confirmClear) { console.log('Clearing conversations...'); - clearConvosMutation.mutate({}); + clearConvosMutation.mutate( + {}, + { + onSuccess: () => { + newConversation(); + refreshConversations(); + }, + }, + ); setConfirmClear(false); } else { setConfirmClear(true); } - }, [confirmClear, clearConvosMutation]); - - // Refresh conversations after clearing - useEffect(() => { - if (clearConvosMutation.isSuccess) { - refreshConversations(); - newConversation(); - } - }, [clearConvosMutation.isSuccess, newConversation, refreshConversations]); + }; return ( diff --git a/client/src/components/Nav/NavLinks.tsx b/client/src/components/Nav/NavLinks.tsx index 8ca9febb02..80ef94c2c0 100644 --- a/client/src/components/Nav/NavLinks.tsx +++ b/client/src/components/Nav/NavLinks.tsx @@ -5,7 +5,6 @@ import { useGetUserBalance, useGetStartupConfig } from 'librechat-data-provider' import type { TConversation } from 'librechat-data-provider'; import { Menu, Transition } from '@headlessui/react'; import { ExportModel } from './ExportConversation'; -import ClearConvos from './ClearConvos'; import Settings from './Settings'; import NavLink from './NavLink'; import Logout from './Logout'; @@ -23,7 +22,6 @@ export default function NavLinks() { enabled: !!isAuthenticated && startupConfig?.checkBalance, }); const [showExports, setShowExports] = useState(false); - const [showClearConvos, setShowClearConvos] = useState(false); const [showSettings, setShowSettings] = useState(false); const localize = useLocalize(); @@ -125,7 +123,6 @@ export default function NavLinks() { )} {showExports && } - {showClearConvos && } {showSettings && } ); diff --git a/client/src/components/Nav/SettingsTabs/General.tsx b/client/src/components/Nav/SettingsTabs/General.tsx index 94a923507d..4ab97632ab 100644 --- a/client/src/components/Nav/SettingsTabs/General.tsx +++ b/client/src/components/Nav/SettingsTabs/General.tsx @@ -1,6 +1,6 @@ import { useRecoilState } from 'recoil'; import * as Tabs from '@radix-ui/react-tabs'; -import React, { useState, useContext, useEffect, useCallback, useRef } from 'react'; +import React, { useState, useContext, useCallback, useRef } from 'react'; import { useClearConversationsMutation } from 'librechat-data-provider'; import { ThemeContext, @@ -116,22 +116,23 @@ function General() { const contentRef = useRef(null); useOnClickOutside(contentRef, () => confirmClear && setConfirmClear(false), []); - useEffect(() => { - if (clearConvosMutation.isSuccess) { - newConversation(); - refreshConversations(); - } - }, [clearConvosMutation.isSuccess, newConversation, refreshConversations]); - - const clearConvos = useCallback(() => { + const clearConvos = () => { if (confirmClear) { console.log('Clearing conversations...'); - clearConvosMutation.mutate({}); setConfirmClear(false); + clearConvosMutation.mutate( + {}, + { + onSuccess: () => { + newConversation(); + refreshConversations(); + }, + }, + ); } else { setConfirmClear(true); } - }, [confirmClear, clearConvosMutation]); + }; const changeTheme = useCallback( (value: string) => { diff --git a/client/src/hooks/useConversation.ts b/client/src/hooks/useConversation.ts index 4a1f643415..2ebde99326 100644 --- a/client/src/hooks/useConversation.ts +++ b/client/src/hooks/useConversation.ts @@ -1,4 +1,5 @@ import { useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; import { useSetRecoilState, useResetRecoilState, useRecoilCallback } from 'recoil'; import { useGetEndpointsQuery } from 'librechat-data-provider'; import type { @@ -12,6 +13,7 @@ import { buildDefaultConvo, getDefaultEndpoint } from '~/utils'; import store from '~/store'; const useConversation = () => { + const navigate = useNavigate(); const setConversation = useSetRecoilState(store.conversation); const setMessages = useSetRecoilState(store.messages); const setSubmission = useSetRecoilState(store.submission); @@ -48,6 +50,10 @@ const useConversation = () => { setMessages(messages); setSubmission({} as TSubmission); resetLatestMessage(); + + if (conversation.conversationId === 'new') { + navigate('/chat/new'); + } }, [endpointsConfig], );