mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-20 17:26:12 +01:00
feat: add sample multi-user support
feat: update README
This commit is contained in:
parent
41f351786f
commit
62d88380e0
19 changed files with 314 additions and 49 deletions
|
|
@ -5,34 +5,67 @@ import TextChat from './components/Main/TextChat';
|
|||
import Nav from './components/Nav';
|
||||
import MobileNav from './components/Nav/MobileNav';
|
||||
import useDocumentTitle from '~/hooks/useDocumentTitle';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { setUser } from './store/userReducer';
|
||||
import axios from 'axios'
|
||||
|
||||
const App = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { messages, messageTree } = useSelector((state) => state.messages);
|
||||
const { user } = useSelector((state) => state.user);
|
||||
const { title } = useSelector((state) => state.convo);
|
||||
const { conversationId } = useSelector((state) => state.convo);
|
||||
const [ navVisible, setNavVisible ]= useState(false)
|
||||
useDocumentTitle(title);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<Nav navVisible={navVisible} setNavVisible={setNavVisible} />
|
||||
<div className="flex h-full w-full flex-1 flex-col bg-gray-50 md:pl-[260px]">
|
||||
<div className="transition-width relative flex h-full w-full flex-1 flex-col items-stretch overflow-hidden bg-white dark:bg-gray-800">
|
||||
<MobileNav setNavVisible={setNavVisible} />
|
||||
{messages.length === 0 ? (
|
||||
<Landing title={title} />
|
||||
) : (
|
||||
<Messages
|
||||
messages={messages}
|
||||
messageTree={messageTree}
|
||||
/>
|
||||
)}
|
||||
<TextChat messages={messages} />
|
||||
useEffect(() => {
|
||||
axios.get('/api/me', {
|
||||
timeout: 1000,
|
||||
withCredentials: true
|
||||
}).then((res) => {
|
||||
return res.data
|
||||
}).then((user) => {
|
||||
if (user)
|
||||
dispatch(setUser(user))
|
||||
else {
|
||||
console.log('Not login!')
|
||||
window.location.href = "/auth/login";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
console.log('Not login!')
|
||||
window.location.href = "/auth/login";
|
||||
})
|
||||
// setUser
|
||||
}, [])
|
||||
|
||||
if (user)
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<Nav navVisible={navVisible} setNavVisible={setNavVisible} />
|
||||
<div className="flex h-full w-full flex-1 flex-col bg-gray-50 md:pl-[260px]">
|
||||
<div className="transition-width relative flex h-full w-full flex-1 flex-col items-stretch overflow-hidden bg-white dark:bg-gray-800">
|
||||
<MobileNav setNavVisible={setNavVisible} />
|
||||
{messages.length === 0 ? (
|
||||
<Landing title={title} />
|
||||
) : (
|
||||
<Messages
|
||||
messages={messages}
|
||||
messageTree={messageTree}
|
||||
/>
|
||||
)}
|
||||
<TextChat messages={messages} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
else
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export default function TextChat({ messages }) {
|
|||
const inputRef = useRef(null)
|
||||
const isComposing = useRef(false);
|
||||
const dispatch = useDispatch();
|
||||
const { user } = useSelector((state) => state.user);
|
||||
const convo = useSelector((state) => state.convo);
|
||||
const { initial } = useSelector((state) => state.models);
|
||||
const { isSubmitting, stopStream, submission, disabled, model, chatGptLabel, promptPrefix } =
|
||||
|
|
|
|||
23
client/src/components/Nav/Logout.jsx
Normal file
23
client/src/components/Nav/Logout.jsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import React, { useState, useContext } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import LogOutIcon from '../svg/LogOutIcon';
|
||||
|
||||
|
||||
export default function Logout() {
|
||||
const { user } = useSelector((state) => state.user);
|
||||
|
||||
const clickHandler = () => {
|
||||
window.location.href = "/auth/logout";
|
||||
};
|
||||
|
||||
return (
|
||||
<a
|
||||
className="flex cursor-pointer items-center gap-3 rounded-md py-3 px-3 text-sm text-white transition-colors duration-200 hover:bg-gray-500/10"
|
||||
onClick={clickHandler}
|
||||
>
|
||||
<LogOutIcon />
|
||||
{user?.display || user?.username || 'USER'}
|
||||
<small>Log out</small>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
|
@ -3,16 +3,18 @@ import NavLink from './NavLink';
|
|||
import LogOutIcon from '../svg/LogOutIcon';
|
||||
import ClearConvos from './ClearConvos';
|
||||
import DarkMode from './DarkMode';
|
||||
import Logout from './Logout';
|
||||
|
||||
export default function NavLinks() {
|
||||
return (
|
||||
<>
|
||||
<ClearConvos />
|
||||
<DarkMode />
|
||||
<NavLink
|
||||
<Logout />
|
||||
{/* <NavLink
|
||||
svg={LogOutIcon}
|
||||
text="Log out"
|
||||
/>
|
||||
/> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import messageReducer from './messageSlice.js'
|
|||
import modelReducer from './modelSlice.js'
|
||||
import submitReducer from './submitSlice.js'
|
||||
import textReducer from './textSlice.js'
|
||||
import userReducer from './userReducer.js'
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
|
|
@ -13,6 +14,7 @@ export const store = configureStore({
|
|||
models: modelReducer,
|
||||
text: textReducer,
|
||||
submit: submitReducer,
|
||||
user: userReducer,
|
||||
},
|
||||
devTools: true,
|
||||
});
|
||||
19
client/src/store/userReducer.js
Normal file
19
client/src/store/userReducer.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
const initialState = {
|
||||
user: null,
|
||||
};
|
||||
|
||||
const currentSlice = createSlice({
|
||||
name: 'user',
|
||||
initialState,
|
||||
reducers: {
|
||||
setUser: (state, action) => {
|
||||
state.user = action.payload;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export const { setUser } = currentSlice.actions;
|
||||
|
||||
export default currentSlice.reducer;
|
||||
|
|
@ -3,10 +3,10 @@ import axios from 'axios';
|
|||
import useSWR from 'swr';
|
||||
import useSWRMutation from 'swr/mutation';
|
||||
|
||||
const fetcher = (url) => fetch(url).then((res) => res.json());
|
||||
const fetcher = (url) => fetch(url, {credentials: 'include'}).then((res) => res.json());
|
||||
|
||||
const postRequest = async (url, { arg }) => {
|
||||
return await axios.post(url, { arg });
|
||||
return await axios.post(url, { withCredentials: true, arg });
|
||||
};
|
||||
|
||||
export const swr = (path, successCallback, options) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue