import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { NavLink, useNavigate } from 'react-router-dom'; import { Agent } from './agents/types'; import conversationService from './api/services/conversationService'; import userService from './api/services/userService'; import Add from './assets/add.svg'; import DocsGPT3 from './assets/cute_docsgpt3.svg'; import Discord from './assets/discord.svg'; import Expand from './assets/expand.svg'; import Github from './assets/github.svg'; import Hamburger from './assets/hamburger.svg'; import openNewChat from './assets/openNewChat.svg'; import Robot from './assets/robot.svg'; import SettingGear from './assets/settingGear.svg'; import Spark from './assets/spark.svg'; import SpinnerDark from './assets/spinner-dark.svg'; import Spinner from './assets/spinner.svg'; import Twitter from './assets/TwitterX.svg'; import Help from './components/Help'; import { handleAbort, selectQueries, setConversation, updateConversationId, } from './conversation/conversationSlice'; import ConversationTile from './conversation/ConversationTile'; import { useDarkTheme, useMediaQuery } from './hooks'; import useDefaultDocument from './hooks/useDefaultDocument'; import useTokenAuth from './hooks/useTokenAuth'; import DeleteConvModal from './modals/DeleteConvModal'; import JWTModal from './modals/JWTModal'; import { ActiveState } from './models/misc'; import { getConversations } from './preferences/preferenceApi'; import { selectConversationId, selectConversations, selectModalStateDeleteConv, selectSelectedAgent, selectToken, setConversations, setModalStateDeleteConv, setSelectedAgent, } from './preferences/preferenceSlice'; import Upload from './upload/Upload'; interface NavigationProps { navOpen: boolean; setNavOpen: React.Dispatch>; } export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { const dispatch = useDispatch(); const navigate = useNavigate(); const { t } = useTranslation(); const token = useSelector(selectToken); const queries = useSelector(selectQueries); const conversations = useSelector(selectConversations); const conversationId = useSelector(selectConversationId); const modalStateDeleteConv = useSelector(selectModalStateDeleteConv); const selectedAgent = useSelector(selectSelectedAgent); const { isMobile } = useMediaQuery(); const [isDarkTheme] = useDarkTheme(); const { showTokenModal, handleTokenSubmit } = useTokenAuth(); const [isDeletingConversation, setIsDeletingConversation] = useState(false); const [uploadModalState, setUploadModalState] = useState('INACTIVE'); const [recentAgents, setRecentAgents] = useState([]); const navRef = useRef(null); async function fetchConversations() { dispatch(setConversations({ ...conversations, loading: true })); return await getConversations(token) .then((fetchedConversations) => { dispatch(setConversations(fetchedConversations)); }) .catch((error) => { console.error('Failed to fetch conversations: ', error); dispatch(setConversations({ data: null, loading: false })); }); } async function getAgents() { const response = await userService.getAgents(token); if (!response.ok) throw new Error('Failed to fetch agents'); const data = await response.json(); setRecentAgents( data.filter((agent: Agent) => agent.status === 'published'), ); } useEffect(() => { if (recentAgents.length === 0) getAgents(); if (!conversations?.data) fetchConversations(); if (queries.length === 0) resetConversation(); }, [conversations?.data, dispatch]); const handleDeleteAllConversations = () => { setIsDeletingConversation(true); conversationService .deleteAll(token) .then(() => { fetchConversations(); }) .catch((error) => console.error(error)); }; const handleDeleteConversation = (id: string) => { setIsDeletingConversation(true); conversationService .delete(id, {}, token) .then(() => { fetchConversations(); resetConversation(); }) .catch((error) => console.error(error)); }; const handleAgentClick = (agent: Agent) => { resetConversation(); dispatch(setSelectedAgent(agent)); if (isMobile) setNavOpen(!navOpen); navigate('/'); }; const handleConversationClick = (index: string) => { conversationService .getConversation(index, token) .then((response) => response.json()) .then((data) => { navigate('/'); dispatch(setConversation(data.queries)); dispatch( updateConversationId({ query: { conversationId: index }, }), ); if (data.agent_id) { userService.getAgent(data.agent_id, token).then((response) => { if (response.ok) { response.json().then((agent: Agent) => { dispatch(setSelectedAgent(agent)); }); } }); } else dispatch(setSelectedAgent(null)); }); }; const resetConversation = () => { handleAbort(); dispatch(setConversation([])); dispatch( updateConversationId({ query: { conversationId: null }, }), ); dispatch(setSelectedAgent(null)); }; const newChat = () => { if (queries && queries?.length > 0) { resetConversation(); } }; async function updateConversationName(updatedConversation: { name: string; id: string; }) { await conversationService .update(updatedConversation, token) .then((response) => response.json()) .then((data) => { if (data) { navigate('/'); fetchConversations(); } }) .catch((err) => { console.error(err); }); } useEffect(() => { setNavOpen(!isMobile); }, [isMobile]); useDefaultDocument(); return ( <> {!navOpen && (
{queries?.length > 0 && ( )}
DocsGPT
)}
{ if (isMobile) { setNavOpen(!navOpen); } }} > DocsGPT Logo

DocsGPT

{ if (isMobile) { setNavOpen(!navOpen); } resetConversation(); }} className={({ isActive }) => `${ isActive ? 'bg-transparent' : '' } group sticky mx-4 mt-4 flex cursor-pointer gap-2.5 rounded-3xl border border-silver p-3 hover:border-rainy-gray hover:bg-transparent dark:border-purple-taupe dark:text-white` } > Create new chat

{t('newChat')}

{conversations?.loading && !isDeletingConversation && (
Loading conversations
)} {recentAgents?.length > 0 ? (

Agents

{recentAgents.map((agent, idx) => (
handleAgentClick(agent)} >
agent-logo

{agent.name}

))}
{ dispatch(setSelectedAgent(null)); navigate('/agents'); }} >
manage-agents

Manage Agents

) : (
navigate('/agents')} >
manage-agents

Manage Agents

)} {conversations?.data && conversations.data.length > 0 ? (

{t('chats')}

{conversations.data?.map((conversation) => ( handleConversationClick(id)} onConversationClick={() => { if (isMobile) { setNavOpen(false); } }} onDeleteConversation={(id) => handleDeleteConversation(id)} onSave={(conversation) => updateConversationName(conversation) } /> ))}
) : ( <> )}
{ if (isMobile) { setNavOpen(!navOpen); } resetConversation(); }} to="/settings" className={({ isActive }) => `mx-4 my-auto flex h-9 cursor-pointer gap-4 rounded-3xl hover:bg-gray-100 dark:hover:bg-[#28292E] ${ isActive ? 'bg-gray-3000 dark:bg-transparent' : '' }` } > Settings

{t('settings.label')}

Join Discord community Follow us on Twitter View on GitHub
DocsGPT
{uploadModalState === 'ACTIVE' && ( setUploadModalState('INACTIVE')} > )} ); }