feat: Improve route handling and dynamic chat navigation in SiderBar
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { lazy, Suspense, useContext, useEffect } from 'react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import { Route, Routes, useLocation } from 'react-router-dom';
|
||||
import Loading from './components/Loading';
|
||||
import User from './pages/User';
|
||||
import { PrivateRoute } from './components/PrivateRoute';
|
||||
@@ -8,10 +8,8 @@ import LoginForm from './components/LoginForm';
|
||||
import NotFound from './pages/NotFound';
|
||||
import Setting from './pages/Setting';
|
||||
import EditUser from './pages/User/EditUser';
|
||||
import { getLogo, getSystemName } from './helpers';
|
||||
import PasswordResetForm from './components/PasswordResetForm';
|
||||
import PasswordResetConfirm from './components/PasswordResetConfirm';
|
||||
import { UserContext } from './context/User';
|
||||
import Channel from './pages/Channel';
|
||||
import Token from './pages/Token';
|
||||
import EditChannel from './pages/Channel/EditChannel';
|
||||
@@ -26,10 +24,6 @@ import Pricing from './pages/Pricing/index.js';
|
||||
import Task from "./pages/Task/index.js";
|
||||
import Playground from './pages/Playground/Playground.js';
|
||||
import OAuth2Callback from "./components/OAuth2Callback.js";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StatusContext } from './context/Status';
|
||||
import { setStatusData } from './helpers/data.js';
|
||||
import { API, showError } from './helpers';
|
||||
import PersonalSetting from './components/PersonalSetting.js';
|
||||
|
||||
const Home = lazy(() => import('./pages/Home'));
|
||||
@@ -37,13 +31,15 @@ const Detail = lazy(() => import('./pages/Detail'));
|
||||
const About = lazy(() => import('./pages/About'));
|
||||
|
||||
function App() {
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Routes>
|
||||
<Route
|
||||
path='/'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<Home />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -59,7 +55,7 @@ function App() {
|
||||
<Route
|
||||
path='/channel/edit/:id'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<EditChannel />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -67,7 +63,7 @@ function App() {
|
||||
<Route
|
||||
path='/channel/add'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<EditChannel />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -107,7 +103,7 @@ function App() {
|
||||
<Route
|
||||
path='/user/edit/:id'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<EditUser />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -115,7 +111,7 @@ function App() {
|
||||
<Route
|
||||
path='/user/edit'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<EditUser />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -123,7 +119,7 @@ function App() {
|
||||
<Route
|
||||
path='/user/reset'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<PasswordResetConfirm />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -131,7 +127,7 @@ function App() {
|
||||
<Route
|
||||
path='/login'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<LoginForm />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -139,7 +135,7 @@ function App() {
|
||||
<Route
|
||||
path='/register'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<RegisterForm />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -147,7 +143,7 @@ function App() {
|
||||
<Route
|
||||
path='/reset'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<PasswordResetForm />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -155,7 +151,7 @@ function App() {
|
||||
<Route
|
||||
path='/oauth/github'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<OAuth2Callback type='github'></OAuth2Callback>
|
||||
</Suspense>
|
||||
}
|
||||
@@ -163,7 +159,7 @@ function App() {
|
||||
<Route
|
||||
path='/oauth/linuxdo'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<OAuth2Callback type='linuxdo'></OAuth2Callback>
|
||||
</Suspense>
|
||||
}
|
||||
@@ -172,7 +168,7 @@ function App() {
|
||||
path='/setting'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<Setting />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
@@ -182,7 +178,7 @@ function App() {
|
||||
path='/personal'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<PersonalSetting />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
@@ -192,7 +188,7 @@ function App() {
|
||||
path='/topup'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<TopUp />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
@@ -210,7 +206,7 @@ function App() {
|
||||
path='/detail'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<Detail />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
@@ -220,7 +216,7 @@ function App() {
|
||||
path='/midjourney'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<Midjourney />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
@@ -230,7 +226,7 @@ function App() {
|
||||
path='/task'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<Task />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
@@ -239,7 +235,7 @@ function App() {
|
||||
<Route
|
||||
path='/pricing'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<Pricing />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -247,7 +243,7 @@ function App() {
|
||||
<Route
|
||||
path='/about'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<About />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -255,7 +251,7 @@ function App() {
|
||||
<Route
|
||||
path='/chat/:id?'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<Chat />
|
||||
</Suspense>
|
||||
}
|
||||
@@ -265,7 +261,7 @@ function App() {
|
||||
path='/chat2link'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||
<Chat2Link />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
|
||||
@@ -62,6 +62,25 @@ const iconStyle = (itemKey, selectedKeys) => {
|
||||
};
|
||||
};
|
||||
|
||||
// Define routerMap as a constant outside the component
|
||||
const routerMap = {
|
||||
home: '/',
|
||||
channel: '/channel',
|
||||
token: '/token',
|
||||
redemption: '/redemption',
|
||||
topup: '/topup',
|
||||
user: '/user',
|
||||
log: '/log',
|
||||
midjourney: '/midjourney',
|
||||
setting: '/setting',
|
||||
about: '/about',
|
||||
detail: '/detail',
|
||||
pricing: '/pricing',
|
||||
task: '/task',
|
||||
playground: '/playground',
|
||||
personal: '/personal',
|
||||
};
|
||||
|
||||
const SiderBar = () => {
|
||||
const { t } = useTranslation();
|
||||
const [styleState, styleDispatch] = useContext(StyleContext);
|
||||
@@ -76,6 +95,7 @@ const SiderBar = () => {
|
||||
const theme = useTheme();
|
||||
const setTheme = useSetTheme();
|
||||
const location = useLocation();
|
||||
const [routerMapState, setRouterMapState] = useState(routerMap);
|
||||
|
||||
// 预先计算所有可能的图标样式
|
||||
const allItemKeys = useMemo(() => {
|
||||
@@ -97,25 +117,6 @@ const SiderBar = () => {
|
||||
return styles;
|
||||
}, [allItemKeys, selectedKeys]);
|
||||
|
||||
const routerMap = {
|
||||
home: '/',
|
||||
channel: '/channel',
|
||||
token: '/token',
|
||||
redemption: '/redemption',
|
||||
topup: '/topup',
|
||||
user: '/user',
|
||||
log: '/log',
|
||||
midjourney: '/midjourney',
|
||||
setting: '/setting',
|
||||
about: '/about',
|
||||
chat: '/chat',
|
||||
detail: '/detail',
|
||||
pricing: '/pricing',
|
||||
task: '/task',
|
||||
playground: '/playground',
|
||||
personal: '/personal',
|
||||
};
|
||||
|
||||
const workspaceItems = useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -237,21 +238,24 @@ const SiderBar = () => {
|
||||
[chatItems, t],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const currentPath = location.pathname;
|
||||
const matchingKey = Object.keys(routerMap).find(key => routerMap[key] === currentPath);
|
||||
|
||||
if (matchingKey) {
|
||||
setSelectedKeys([matchingKey]);
|
||||
} else if (currentPath.startsWith('/chat/')) {
|
||||
setSelectedKeys(['chat']);
|
||||
// Function to update router map with chat routes
|
||||
const updateRouterMapWithChats = (chats) => {
|
||||
const newRouterMap = { ...routerMap };
|
||||
|
||||
if (Array.isArray(chats) && chats.length > 0) {
|
||||
for (let i = 0; i < chats.length; i++) {
|
||||
newRouterMap['chat' + i] = '/chat/' + i;
|
||||
}
|
||||
}
|
||||
}, [location.pathname]);
|
||||
|
||||
setRouterMapState(newRouterMap);
|
||||
return newRouterMap;
|
||||
};
|
||||
|
||||
// Update the useEffect for chat items
|
||||
useEffect(() => {
|
||||
let chats = localStorage.getItem('chats');
|
||||
if (chats) {
|
||||
// console.log(chats);
|
||||
try {
|
||||
chats = JSON.parse(chats);
|
||||
if (Array.isArray(chats)) {
|
||||
@@ -263,19 +267,44 @@ const SiderBar = () => {
|
||||
chat.itemKey = 'chat' + i;
|
||||
chat.to = '/chat/' + i;
|
||||
}
|
||||
// setRouterMap({ ...routerMap, chat: '/chat/' + i })
|
||||
chatItems.push(chat);
|
||||
}
|
||||
setChatItems(chatItems);
|
||||
|
||||
// Update router map with chat routes
|
||||
updateRouterMapWithChats(chats);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
showError('聊天数据解析失败')
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Update the useEffect for route selection
|
||||
useEffect(() => {
|
||||
const currentPath = location.pathname;
|
||||
let matchingKey = Object.keys(routerMapState).find(key => routerMapState[key] === currentPath);
|
||||
|
||||
// Handle chat routes
|
||||
if (!matchingKey && currentPath.startsWith('/chat/')) {
|
||||
const chatIndex = currentPath.split('/').pop();
|
||||
if (!isNaN(chatIndex)) {
|
||||
matchingKey = 'chat' + chatIndex;
|
||||
} else {
|
||||
matchingKey = 'chat';
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a matching key, update the selected keys
|
||||
if (matchingKey) {
|
||||
setSelectedKeys([matchingKey]);
|
||||
}
|
||||
}, [location.pathname, routerMapState]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsCollapsed(styleState.siderCollapsed);
|
||||
})
|
||||
}, [styleState.siderCollapsed]);
|
||||
|
||||
// Custom divider style
|
||||
const dividerStyle = {
|
||||
@@ -322,14 +351,14 @@ const SiderBar = () => {
|
||||
// 确保在收起侧边栏时有选中的项目,避免不必要的计算
|
||||
if (selectedKeys.length === 0) {
|
||||
const currentPath = location.pathname;
|
||||
const matchingKey = Object.keys(routerMap).find(key => routerMap[key] === currentPath);
|
||||
const matchingKey = Object.keys(routerMapState).find(key => routerMapState[key] === currentPath);
|
||||
|
||||
if (matchingKey) {
|
||||
setSelectedKeys([matchingKey]);
|
||||
} else if (currentPath.startsWith('/chat/')) {
|
||||
setSelectedKeys(['chat']);
|
||||
} else {
|
||||
setSelectedKeys([]); // 默认选中首页
|
||||
setSelectedKeys(['detail']); // 默认选中首页
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -338,28 +367,10 @@ const SiderBar = () => {
|
||||
hoverStyle={navItemHoverStyle}
|
||||
selectedStyle={navItemSelectedStyle}
|
||||
renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
|
||||
let chats = localStorage.getItem('chats');
|
||||
if (chats) {
|
||||
chats = JSON.parse(chats);
|
||||
if (Array.isArray(chats) && chats.length > 0) {
|
||||
for (let i = 0; i < chats.length; i++) {
|
||||
routerMap['chat' + i] = '/chat/' + i;
|
||||
}
|
||||
if (chats.length > 1) {
|
||||
// delete /chat
|
||||
if (routerMap['chat']) {
|
||||
delete routerMap['chat'];
|
||||
}
|
||||
} else {
|
||||
// rename /chat to /chat/0
|
||||
routerMap['chat'] = '/chat/0';
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Link
|
||||
style={{ textDecoration: 'none' }}
|
||||
to={routerMap[props.itemKey]}
|
||||
to={routerMapState[props.itemKey] || routerMap[props.itemKey]}
|
||||
>
|
||||
{itemElement}
|
||||
</Link>
|
||||
@@ -466,7 +477,7 @@ const SiderBar = () => {
|
||||
|
||||
<Nav.Footer
|
||||
style={{
|
||||
paddingBottom: styleState?.isMobile ? '112px' : '20px',
|
||||
paddingBottom: styleState?.isMobile ? '112px' : '',
|
||||
}}
|
||||
collapseButton={true}
|
||||
collapseText={(collapsed)=>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"主页": "Home",
|
||||
"文档": "Docs",
|
||||
"控制台": "Console",
|
||||
"$%.6f 额度": "$%.6f quota",
|
||||
"%d 点额度": "%d point quota",
|
||||
|
||||
Reference in New Issue
Block a user