diff --git a/web/src/App.tsx b/web/src/App.tsx index efd8a800..01c4a1e7 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,5 +1,5 @@ import { useColorScheme } from "@mui/joy"; -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { useTranslation } from "react-i18next"; import { Outlet } from "react-router-dom"; import storage from "./helpers/storage"; @@ -16,7 +16,6 @@ const App = () => { const globalStore = useGlobalStore(); const workspaceSettingStore = useWorkspaceSettingStore(); const userStore = useUserStore(); - const [loading, setLoading] = useState(true); const { appearance, locale, systemStatus } = globalStore.state; const userSetting = userStore.userSetting; const workspaceGeneralSetting = @@ -30,19 +29,6 @@ const App = () => { } }, [systemStatus.host]); - useEffect(() => { - const initialState = async () => { - await workspaceSettingStore.fetchWorkspaceSetting(WorkspaceSettingKey.WORKSPACE_SETTING_GENERAL); - try { - await userStore.fetchCurrentUser(); - } catch (error) { - // Do nothing. - } - }; - - Promise.all([initialState()]).then(() => setLoading(false)); - }, []); - useEffect(() => { const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); const handleColorSchemeChange = (e: MediaQueryListEvent) => { @@ -132,7 +118,7 @@ const App = () => { } }, [mode]); - return loading ? null : ; + return ; }; export default App; diff --git a/web/src/layouts/CommonContextProvider.tsx b/web/src/layouts/CommonContextProvider.tsx new file mode 100644 index 00000000..5a4bd5fa --- /dev/null +++ b/web/src/layouts/CommonContextProvider.tsx @@ -0,0 +1,32 @@ +import { useEffect, useState } from "react"; +import { initialGlobalState } from "@/store/module"; +import { useUserStore, useWorkspaceSettingStore } from "@/store/v1"; +import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; + +interface Props { + children: React.ReactNode; +} + +const CommonContextProvider = (props: Props) => { + const workspaceSettingStore = useWorkspaceSettingStore(); + const userStore = useUserStore(); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const initialState = async () => { + await initialGlobalState(); + await workspaceSettingStore.fetchWorkspaceSetting(WorkspaceSettingKey.WORKSPACE_SETTING_GENERAL); + try { + await userStore.fetchCurrentUser(); + } catch (error) { + // Do nothing. + } + }; + + Promise.all([initialState()]).then(() => setLoading(false)); + }, []); + + return loading ? null : <>{props.children}; +}; + +export default CommonContextProvider; diff --git a/web/src/layouts/Root.tsx b/web/src/layouts/HomeLayout.tsx similarity index 78% rename from web/src/layouts/Root.tsx rename to web/src/layouts/HomeLayout.tsx index 94d93fad..36344694 100644 --- a/web/src/layouts/Root.tsx +++ b/web/src/layouts/HomeLayout.tsx @@ -1,17 +1,34 @@ import { Button, IconButton, Tooltip } from "@mui/joy"; import classNames from "classnames"; import { Suspense } from "react"; -import { Outlet } from "react-router-dom"; +import { Outlet, useLocation } from "react-router-dom"; import useLocalStorage from "react-use/lib/useLocalStorage"; import Icon from "@/components/Icon"; import Navigation from "@/components/Navigation"; +import useCurrentUser from "@/hooks/useCurrentUser"; +import useNavigateTo from "@/hooks/useNavigateTo"; import useResponsiveWidth from "@/hooks/useResponsiveWidth"; import Loading from "@/pages/Loading"; +import { Routes } from "@/router"; -function Root() { +const HomeLayout = () => { + const navigateTo = useNavigateTo(); + const location = useLocation(); const { sm } = useResponsiveWidth(); + const currentUser = useCurrentUser(); const [collapsed, setCollapsed] = useLocalStorage("navigation-collapsed", false); + // Redirect to explore page if not logged in. + if ( + !currentUser && + ([Routes.HOME, Routes.TIMELINE, Routes.RESOURCES, Routes.INBOX, Routes.ARCHIVED, Routes.SETTING] as string[]).includes( + location.pathname, + ) + ) { + navigateTo("/explore"); + return; + } + return (
); -} +}; -export default Root; +export default HomeLayout; diff --git a/web/src/main.tsx b/web/src/main.tsx index 6cdab151..c3a7680c 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -9,6 +9,7 @@ import "./css/global.css"; import "./css/tailwind.css"; import "./helpers/polyfill"; import "./i18n"; +import CommonContextProvider from "./layouts/CommonContextProvider"; import "./less/highlight.less"; import router from "./router"; import store from "./store"; @@ -25,7 +26,9 @@ import theme from "./theme"; root.render( - + + + , diff --git a/web/src/router/AuthStatusProvider.tsx b/web/src/router/AuthStatusProvider.tsx deleted file mode 100644 index a3c73846..00000000 --- a/web/src/router/AuthStatusProvider.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useEffect } from "react"; -import useCurrentUser from "@/hooks/useCurrentUser"; -import useNavigateTo from "@/hooks/useNavigateTo"; - -interface Props { - children: React.ReactNode; -} - -const AuthStatusProvider = (props: Props) => { - const navigateTo = useNavigateTo(); - const currentUser = useCurrentUser(); - - useEffect(() => { - if (!currentUser) { - // If not logged in, redirect to explore page by default. - navigateTo("/explore"); - } - }, []); - - if (!currentUser) { - return null; - } - - return <>{props.children}; -}; - -export default AuthStatusProvider; diff --git a/web/src/router/index.tsx b/web/src/router/index.tsx index 45647e00..68f68d31 100644 --- a/web/src/router/index.tsx +++ b/web/src/router/index.tsx @@ -1,11 +1,9 @@ import { lazy } from "react"; import { createBrowserRouter } from "react-router-dom"; import App from "@/App"; +import HomeLayout from "@/layouts/HomeLayout"; import SuspenseWrapper from "@/layouts/SuspenseWrapper"; -import { initialGlobalState } from "@/store/module"; -import AuthStatusProvider from "./AuthStatusProvider"; -const Root = lazy(() => import("@/layouts/Root")); const SignIn = lazy(() => import("@/pages/SignIn")); const SignUp = lazy(() => import("@/pages/SignUp")); const AuthCallback = lazy(() => import("@/pages/AuthCallback")); @@ -22,23 +20,22 @@ const About = lazy(() => import("@/pages/About")); const NotFound = lazy(() => import("@/pages/NotFound")); const PermissionDenied = lazy(() => import("@/pages/PermissionDenied")); -const initialGlobalStateLoader = async () => { - try { - await initialGlobalState(); - } catch (error) { - // do nothing. - } - return null; -}; +export enum Routes { + HOME = "/", + TIMELINE = "/timeline", + RESOURCES = "/resources", + INBOX = "/inbox", + ARCHIVED = "/archived", + SETTING = "/setting", +} const router = createBrowserRouter([ { path: "/", element: , - loader: () => initialGlobalStateLoader(), children: [ { - path: "/auth/", + path: "/auth", element: , children: [ { @@ -57,55 +54,31 @@ const router = createBrowserRouter([ }, { path: "/", - element: , + element: , children: [ { - path: "", - element: ( - - - - ), - }, - { - path: "timeline", - element: ( - - - - ), - }, - { - path: "resources", - element: ( - - - - ), - }, - { - path: "inbox", - element: ( - - - - ), - }, - { - path: "archived", - element: ( - - - - ), - }, - { - path: "setting", - element: ( - - - - ), + path: Routes.HOME, + element: , + }, + { + path: Routes.TIMELINE, + element: , + }, + { + path: Routes.RESOURCES, + element: , + }, + { + path: Routes.INBOX, + element: , + }, + { + path: Routes.ARCHIVED, + element: , + }, + { + path: Routes.SETTING, + element: , }, { path: "explore",