diff --git a/client/index.js b/client/index.js
index 6e1b2c1620..f4cf5cb234 100644
--- a/client/index.js
+++ b/client/index.js
@@ -1,19 +1,21 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
-import { Provider } from 'react-redux';
-import { store } from './src/store';
+// import { Provider } from 'react-redux';
+// import { store } from './src/store';
+import { RecoilRoot } from 'recoil';
+
import { ThemeProvider } from './src/hooks/ThemeContext';
import App from './src/App';
import './src/style.css';
-import './src/mobile.css'
+import './src/mobile.css';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
-
+
-
-);
\ No newline at end of file
+
+);
diff --git a/client/package.json b/client/package.json
index 1357b72066..6bd5b4fdd6 100644
--- a/client/package.json
+++ b/client/package.json
@@ -36,9 +36,11 @@
"react-lazy-load": "^4.0.1",
"react-markdown": "^8.0.5",
"react-redux": "^8.0.5",
+ "react-router-dom": "^6.9.0",
"react-string-replace": "^1.1.0",
"react-textarea-autosize": "^8.4.0",
"react-transition-group": "^4.4.5",
+ "recoil": "^0.7.7",
"rehype-highlight": "^6.0.0",
"rehype-katex": "^6.0.2",
"rehype-raw": "^6.1.1",
diff --git a/client/src/App.jsx b/client/src/App.jsx
index 6ee3be2a6b..07b8df49b8 100644
--- a/client/src/App.jsx
+++ b/client/src/App.jsx
@@ -1,53 +1,52 @@
import React, { useEffect, useState } from 'react';
-import Messages from './components/Messages';
-import Landing from './components/Main/Landing';
-import TextChat from './components/Main/TextChat';
-import Nav from './components/Nav';
-import MobileNav from './components/Nav/MobileNav';
-import useDocumentTitle from '~/hooks/useDocumentTitle';
-import { useSelector, useDispatch } from 'react-redux';
+import { createBrowserRouter, RouterProvider, Navigate } from 'react-router-dom';
+import Root from './routes/Root';
+// import Chat from './routes/Chat';
+import store from './store';
import userAuth from './utils/userAuth';
-import { setUser } from './store/userReducer';
-import { setSearchState } from './store/searchSlice';
+import { useRecoilState, useSetRecoilState } from 'recoil';
+
import axios from 'axios';
-const App = () => {
- const dispatch = useDispatch();
+const router = createBrowserRouter([
+ {
+ path: '/',
+ element: ,
+ children: [
+ {
+ index: true,
+ element: (
+
+ )
+ },
+ {
+ path: 'chat/:conversationId',
+ element: null //
+ }
+ ]
+ }
+]);
- const { messages, messageTree } = useSelector((state) => state.messages);
- const { user } = useSelector((state) => state.user);
- const { title } = useSelector((state) => state.convo);
- const [navVisible, setNavVisible] = useState(false);
- useDocumentTitle(title);
+const App = () => {
+ const [user, setUser] = useRecoilState(store.user);
+ const setIsSearchEnabled = useSetRecoilState(store.isSearchEnabled);
useEffect(() => {
- axios.get('/api/search/enable').then((res) => { console.log(res.data); dispatch(setSearchState(res.data))});
+ axios.get('/api/search/enable').then(res => {
+ setIsSearchEnabled(res.data);
+ });
userAuth()
- .then((user) => dispatch(setUser(user)))
- .catch((err) => console.log(err));
+ .then(user => setUser(user))
+ .catch(err => console.log(err));
}, []);
if (user)
return (
-
-
-
-
-
- {messages.length === 0 && title.toLowerCase() === 'chatgpt clone' ? (
-
- ) : (
-
- )}
-
-
-
+
+
);
else return
;
diff --git a/client/src/components/Conversations/Conversation.jsx b/client/src/components/Conversations/Conversation.jsx
index c0ae103d33..da2d45780a 100644
--- a/client/src/components/Conversations/Conversation.jsx
+++ b/client/src/components/Conversations/Conversation.jsx
@@ -1,99 +1,125 @@
import React, { useState, useRef } from 'react';
+import { useRecoilState, useResetRecoilState, useSetRecoilState } from 'recoil';
+
import RenameButton from './RenameButton';
import DeleteButton from './DeleteButton';
-import { useSelector, useDispatch } from 'react-redux';
-import { setConversation } from '~/store/convoSlice';
-import { setSubmission, setStopStream, setCustomGpt, setModel, setCustomModel } from '~/store/submitSlice';
-import { setMessages, setEmptyMessage } from '~/store/messageSlice';
-import { setText } from '~/store/textSlice';
-import manualSWR from '~/utils/fetchers';
import ConvoIcon from '../svg/ConvoIcon';
-import { refreshConversation } from '../../store/convoSlice';
+import manualSWR from '~/utils/fetchers';
+
+import store from '~/store';
+
+export default function Conversation({ conversation, retainView }) {
+ const [currentConversation, setCurrentConversation] = useRecoilState(store.conversation);
+ const setMessages = useSetRecoilState(store.messages);
+ const setSubmission = useSetRecoilState(store.submission);
+ const resetLatestMessage = useResetRecoilState(store.latestMessage);
+
+ const { refreshConversations } = store.useConversations();
-export default function Conversation({
- id,
- model,
- parentMessageId,
- conversationId,
- title,
- chatGptLabel = null,
- promptPrefix = null,
- bingData,
- retainView,
-}) {
const [renaming, setRenaming] = useState(false);
const [titleInput, setTitleInput] = useState(title);
- const { stopStream } = useSelector((state) => state.submit);
const inputRef = useRef(null);
- const dispatch = useDispatch();
- const { trigger } = manualSWR(`/api/messages/${id}`, 'get');
+
+ const {
+ model,
+ parentMessageId,
+ conversationId,
+ title,
+ chatGptLabel = null,
+ promptPrefix = null,
+ jailbreakConversationId,
+ conversationSignature,
+ clientId,
+ invocationId,
+ toneStyle
+ } = conversation;
+
const rename = manualSWR(`/api/convos/update`, 'post');
+ const bingData = conversationSignature
+ ? {
+ jailbreakConversationId: jailbreakConversationId,
+ conversationSignature: conversationSignature,
+ parentMessageId: parentMessageId || null,
+ clientId: clientId,
+ invocationId: invocationId,
+ toneStyle: toneStyle
+ }
+ : null;
+
const clickHandler = async () => {
- if (conversationId === id) {
+ if (currentConversation?.conversationId === conversationId) {
return;
}
- if (!stopStream) {
- dispatch(setStopStream(true));
- dispatch(setSubmission({}));
- }
- dispatch(setEmptyMessage());
+ // stop existing submission
+ setSubmission(null);
- const convo = { title, error: false, conversationId: id, chatGptLabel, promptPrefix };
+ // set conversation to the new conversation
+ setCurrentConversation(conversation);
+ setMessages(null);
+ resetLatestMessage();
- if (bingData) {
- const {
- parentMessageId,
- conversationSignature,
- jailbreakConversationId,
- clientId,
- invocationId,
- toneStyle,
- } = bingData;
- dispatch(
- setConversation({
- ...convo,
- parentMessageId,
- jailbreakConversationId,
- conversationSignature,
- clientId,
- invocationId,
- toneStyle,
- latestMessage: null
- })
- );
- } else {
- dispatch(
- setConversation({
- ...convo,
- parentMessageId,
- jailbreakConversationId: null,
- conversationSignature: null,
- clientId: null,
- invocationId: null,
- toneStyle: null,
- latestMessage: null
- })
- );
- }
- const data = await trigger();
+ // if (!stopStream) {
+ // dispatch(setStopStream(true));
+ // dispatch(setSubmission({}));
+ // }
+ // dispatch(setEmptyMessage());
- if (chatGptLabel) {
- dispatch(setModel('chatgptCustom'));
- dispatch(setCustomModel(chatGptLabel.toLowerCase()));
- } else {
- dispatch(setModel(model));
- dispatch(setCustomModel(null));
- }
+ // const convo = { title, error: false, conversationId: id, chatGptLabel, promptPrefix };
- dispatch(setMessages(data));
- dispatch(setCustomGpt(convo));
- dispatch(setText(''));
- dispatch(setStopStream(false));
+ // if (bingData) {
+ // const {
+ // parentMessageId,
+ // conversationSignature,
+ // jailbreakConversationId,
+ // clientId,
+ // invocationId,
+ // toneStyle
+ // } = bingData;
+ // dispatch(
+ // setConversation({
+ // ...convo,
+ // parentMessageId,
+ // jailbreakConversationId,
+ // conversationSignature,
+ // clientId,
+ // invocationId,
+ // toneStyle,
+ // latestMessage: null
+ // })
+ // );
+ // } else {
+ // dispatch(
+ // setConversation({
+ // ...convo,
+ // parentMessageId,
+ // jailbreakConversationId: null,
+ // conversationSignature: null,
+ // clientId: null,
+ // invocationId: null,
+ // toneStyle: null,
+ // latestMessage: null
+ // })
+ // );
+ // }
+ // const data = await trigger();
+
+ // if (chatGptLabel) {
+ // dispatch(setModel('chatgptCustom'));
+ // dispatch(setCustomModel(chatGptLabel.toLowerCase()));
+ // } else {
+ // dispatch(setModel(model));
+ // dispatch(setCustomModel(null));
+ // }
+
+ // dispatch(setMessages(data));
+ // dispatch(setCustomGpt(convo));
+ // dispatch(setText(''));
+ // dispatch(setStopStream(false));
};
- const renameHandler = (e) => {
+ const renameHandler = e => {
e.preventDefault();
setTitleInput(title);
setRenaming(true);
@@ -102,24 +128,28 @@ export default function Conversation({
}, 25);
};
- const cancelHandler = (e) => {
+ const cancelHandler = e => {
e.preventDefault();
setRenaming(false);
};
- const onRename = (e) => {
+ const onRename = e => {
e.preventDefault();
setRenaming(false);
if (titleInput === title) {
return;
}
- rename.trigger({ conversationId, title: titleInput })
- .then(() => {
- dispatch(refreshConversation())
- });
+ rename.trigger({ conversationId, title: titleInput }).then(() => {
+ refreshConversations();
+ if (conversationId == currentConversation?.conversationId)
+ setCurrentConversation(prevState => ({
+ ...prevState,
+ title: titleInput
+ }));
+ });
};
- const handleKeyDown = (e) => {
+ const handleKeyDown = e => {
if (e.key === 'Enter') {
onRename(e);
}
@@ -130,7 +160,7 @@ export default function Conversation({
'animate-flash group relative flex cursor-pointer items-center gap-3 break-all rounded-md bg-gray-800 py-3 px-3 pr-14 hover:bg-gray-800'
};
- if (conversationId !== id) {
+ if (currentConversation?.conversationId !== conversationId) {
aProps.className =
'group relative flex cursor-pointer items-center gap-3 break-all rounded-md py-3 px-3 hover:bg-[#2A2B32] hover:pr-4';
}
@@ -148,7 +178,7 @@ export default function Conversation({
type="text"
className="m-0 mr-0 w-full border border-blue-500 bg-transparent p-0 text-sm leading-tight outline-none"
value={titleInput}
- onChange={(e) => setTitleInput(e.target.value)}
+ onChange={e => setTitleInput(e.target.value)}
onBlur={onRename}
onKeyDown={handleKeyDown}
/>
@@ -156,16 +186,16 @@ export default function Conversation({
title
)}
- {conversationId === id ? (
+ {currentConversation?.conversationId === conversationId ? (