diff --git a/web/package.json b/web/package.json
index c3970bf..6a522be 100644
--- a/web/package.json
+++ b/web/package.json
@@ -18,7 +18,7 @@
"react-dom": "^18.1.0",
"react-feather": "^2.0.10",
"react-redux": "^8.0.1",
- "react-router-dom": "6"
+ "react-router-dom": "^6.4.0"
},
"devDependencies": {
"@types/lodash-es": "^4.17.5",
diff --git a/web/src/App.tsx b/web/src/App.tsx
index 4ed6451..79c8089 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -1,59 +1,8 @@
-import { useEffect } from "react";
-import { Route, Routes, useLocation, useNavigate } from "react-router-dom";
-import { userService, workspaceService } from "./services";
-import useLoading from "./hooks/useLoading";
-import Only from "./components/common/OnlyWhen";
-import Auth from "./pages/Auth";
-import Home from "./pages/Home";
-import WorkspaceDetail from "./pages/WorkspaceDetail";
-import UserDetail from "./pages/UserDetail";
-import ShortcutRedirector from "./pages/ShortcutRedirector";
-
-const pathnameWhitelist = [/\/.+?\/go\/.+/];
+import { RouterProvider } from "react-router-dom";
+import router from "./router";
function App() {
- const navigate = useNavigate();
- const location = useLocation();
- const pageLoadingStatus = useLoading();
-
- useEffect(() => {
- let needAuth = true;
-
- for (const regexp of pathnameWhitelist) {
- if (regexp.test(location.pathname)) {
- needAuth = false;
- break;
- }
- }
- if (!needAuth) {
- pageLoadingStatus.setFinish();
- return;
- }
-
- userService.initialState().finally(() => {
- if (!userService.getState().user) {
- pageLoadingStatus.setFinish();
- navigate("/user/auth");
- return;
- }
-
- Promise.all([workspaceService.fetchWorkspaceList()]).finally(() => {
- pageLoadingStatus.setFinish();
- });
- });
- }, []);
-
- return (
-
-
- } />
- } />
- } />
- } />
- } />
-
-
- );
+ return ;
}
export default App;
diff --git a/web/src/components/Header.tsx b/web/src/components/Header.tsx
index d7f4494..4aec5a6 100644
--- a/web/src/components/Header.tsx
+++ b/web/src/components/Header.tsx
@@ -3,7 +3,6 @@ import { useAppSelector } from "../store";
import { userService } from "../services";
import Icon from "./Icon";
import Dropdown from "./common/Dropdown";
-import Only from "./common/OnlyWhen";
import showCreateWorkspaceDialog from "./CreateWorkspaceDialog";
const Header: React.FC = () => {
@@ -25,7 +24,7 @@ const Header: React.FC = () => {
Corgi
- 0 && activedWorkspace !== undefined}>
+ {workspaceList.length > 0 && activedWorkspace !== undefined && (
<>
/
{
className="w-full px-3 leading-10 flex flex-row justify-between items-center text-left cursor-pointer rounded whitespace-nowrap hover:bg-gray-100"
>
{workspace.name}
-
-
-
+ {workspace.name === activedWorkspace?.name && }
);
})}
@@ -63,7 +60,7 @@ const Header: React.FC = () => {
actionsClassName="!w-48 !-left-4"
>
>
-
+ )}
{user ? (
diff --git a/web/src/components/common/OnlyWhen.tsx b/web/src/components/common/OnlyWhen.tsx
deleted file mode 100644
index c366fbe..0000000
--- a/web/src/components/common/OnlyWhen.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { ReactNode } from "react";
-
-interface OnlyWhenProps {
- children: ReactNode;
- when: boolean;
-}
-
-const OnlyWhen: React.FC
= (props: OnlyWhenProps) => {
- const { children, when } = props;
- return when ? <>{children}> : null;
-};
-
-const Only = OnlyWhen;
-
-export default Only;
diff --git a/web/src/main.tsx b/web/src/main.tsx
index 3310e42..f09bec9 100644
--- a/web/src/main.tsx
+++ b/web/src/main.tsx
@@ -1,6 +1,5 @@
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
-import { BrowserRouter } from "react-router-dom";
import store from "./store";
import App from "./App";
import "./helpers/polyfill";
@@ -9,9 +8,7 @@ import "./css/index.css";
const container = document.getElementById("root");
const root = createRoot(container as HTMLElement);
root.render(
-
-
-
-
-
+
+
+
);
diff --git a/web/src/pages/Auth.tsx b/web/src/pages/Auth.tsx
index a2790c9..18c98d1 100644
--- a/web/src/pages/Auth.tsx
+++ b/web/src/pages/Auth.tsx
@@ -5,7 +5,6 @@ import { validate, ValidatorConfig } from "../helpers/validator";
import { userService } from "../services";
import useLoading from "../hooks/useLoading";
import Icon from "../components/Icon";
-import Only from "../components/common/OnlyWhen";
import toastHelper from "../components/Toast";
const validateConfig: ValidatorConfig = {
@@ -123,9 +122,7 @@ const Auth: React.FC = () => {
Corgi
-
-
-
+ {actionBtnLoadingState.isLoading && }
diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx
index 1e17247..51cff35 100644
--- a/web/src/pages/Home.tsx
+++ b/web/src/pages/Home.tsx
@@ -1,5 +1,6 @@
import { useEffect } from "react";
-import { workspaceService } from "../services";
+import { useNavigate } from "react-router-dom";
+import { userService, workspaceService } from "../services";
import { useAppSelector } from "../store";
import useLoading from "../hooks/useLoading";
import Icon from "../components/Icon";
@@ -8,10 +9,16 @@ import WorkspaceListView from "../components/WorkspaceListView";
import showCreateWorkspaceDialog from "../components/CreateWorkspaceDialog";
const Home: React.FC = () => {
+ const navigate = useNavigate();
const { workspaceList } = useAppSelector((state) => state.workspace);
const loadingState = useLoading();
useEffect(() => {
+ if (!userService.getState().user) {
+ navigate("/user/auth");
+ return;
+ }
+
Promise.all([workspaceService.fetchWorkspaceList()]).finally(() => {
loadingState.setFinish();
});
diff --git a/web/src/pages/ShortcutRedirector.tsx b/web/src/pages/ShortcutRedirector.tsx
index c068781..3dae414 100644
--- a/web/src/pages/ShortcutRedirector.tsx
+++ b/web/src/pages/ShortcutRedirector.tsx
@@ -1,19 +1,26 @@
import { useEffect, useState } from "react";
-import { useParams } from "react-router-dom";
+import { useNavigate, useParams } from "react-router-dom";
import Header from "../components/Header";
import { getShortcutWithNameAndWorkspaceName } from "../helpers/api";
import useLoading from "../hooks/useLoading";
+import { userService } from "../services";
interface State {
errMessage?: string;
}
const ShortcutRedirector: React.FC = () => {
+ const navigate = useNavigate();
const params = useParams();
const [state, setState] = useState
();
const loadingState = useLoading();
useEffect(() => {
+ if (!userService.getState().user) {
+ navigate("/user/auth");
+ return;
+ }
+
const workspaceName = params.workspaceName || "";
const shortcutName = params.shortcutName || "";
getShortcutWithNameAndWorkspaceName(workspaceName, shortcutName)
diff --git a/web/src/pages/UserDetail.tsx b/web/src/pages/UserDetail.tsx
index f6f1e79..ac8a9b9 100644
--- a/web/src/pages/UserDetail.tsx
+++ b/web/src/pages/UserDetail.tsx
@@ -1,3 +1,5 @@
+import { useEffect } from "react";
+import { useNavigate } from "react-router-dom";
import { useAppSelector } from "../store";
import Header from "../components/Header";
import { showCommonDialog } from "../components/Dialog/CommonDialog";
@@ -8,8 +10,16 @@ import toastHelper from "../components/Toast";
import showChangePasswordDialog from "../components/ChangePasswordDialog";
const UserDetail: React.FC = () => {
+ const navigate = useNavigate();
const { user } = useAppSelector((state) => state.user);
+ useEffect(() => {
+ if (!userService.getState().user) {
+ navigate("/user/auth");
+ return;
+ }
+ }, []);
+
const handleChangePasswordBtnClick = async () => {
showChangePasswordDialog();
};
diff --git a/web/src/pages/WorkspaceDetail.tsx b/web/src/pages/WorkspaceDetail.tsx
index e6fb615..28fe062 100644
--- a/web/src/pages/WorkspaceDetail.tsx
+++ b/web/src/pages/WorkspaceDetail.tsx
@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
-import { useParams } from "react-router-dom";
-import { shortcutService, workspaceService } from "../services";
+import { useNavigate, useParams } from "react-router-dom";
+import { shortcutService, userService, workspaceService } from "../services";
import { useAppSelector } from "../store";
import useLoading from "../hooks/useLoading";
import Icon from "../components/Icon";
@@ -15,6 +15,7 @@ interface State {
}
const WorkspaceDetail: React.FC = () => {
+ const navigate = useNavigate();
const params = useParams();
const { shortcutList } = useAppSelector((state) => state.shortcut);
const [state, setState] = useState({
@@ -23,6 +24,11 @@ const WorkspaceDetail: React.FC = () => {
const loadingState = useLoading();
useEffect(() => {
+ if (!userService.getState().user) {
+ navigate("/user/auth");
+ return;
+ }
+
const workspace = workspaceService.getWorkspaceByName(params.workspaceName ?? "");
if (!workspace) {
toastHelper.error("workspace not found");
diff --git a/web/src/router/index.tsx b/web/src/router/index.tsx
new file mode 100644
index 0000000..68fbd82
--- /dev/null
+++ b/web/src/router/index.tsx
@@ -0,0 +1,62 @@
+import { createBrowserRouter } from "react-router-dom";
+import { userService, workspaceService } from "../services";
+import Auth from "../pages/Auth";
+import Home from "../pages/Home";
+import UserDetail from "../pages/UserDetail";
+import WorkspaceDetail from "../pages/WorkspaceDetail";
+import ShortcutRedirector from "../pages/ShortcutRedirector";
+
+const router = createBrowserRouter([
+ {
+ path: "/",
+ element: ,
+ loader: async () => {
+ try {
+ await userService.initialState();
+ } catch (error) {
+ // do nth
+ }
+ },
+ },
+ {
+ path: "/user/auth",
+ element: ,
+ },
+ {
+ path: "/account",
+ element: ,
+ loader: async () => {
+ try {
+ await userService.initialState();
+ } catch (error) {
+ // do nth
+ }
+ },
+ },
+ {
+ path: "/:workspaceName",
+ element: ,
+ loader: async () => {
+ try {
+ await userService.initialState();
+ await workspaceService.fetchWorkspaceList();
+ } catch (error) {
+ // do nth
+ }
+ },
+ },
+ {
+ path: "/:workspaceName/go/:shortcutName",
+ element: ,
+ loader: async () => {
+ try {
+ await userService.initialState();
+ await workspaceService.fetchWorkspaceList();
+ } catch (error) {
+ // do nth
+ }
+ },
+ },
+]);
+
+export default router;
diff --git a/web/yarn.lock b/web/yarn.lock
index 07ded7d..5be25ad 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -229,13 +229,6 @@
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.7.6":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
- integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
- dependencies:
- regenerator-runtime "^0.13.4"
-
"@babel/template@^7.18.10":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
@@ -383,6 +376,11 @@
redux-thunk "^2.4.1"
reselect "^4.1.5"
+"@remix-run/router@1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.0.0.tgz#a2189335a5f6428aa904ccc291988567018b6e01"
+ integrity sha512-SCR1cxRSMNKjaVYptCzBApPDqGwa3FGdjVHc+rOToocNPHQdIYLZBfv/3f+KvYuXDkUGVIW9IAzmPNZDRL1I4A==
+
"@types/hoist-non-react-statics@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
@@ -1497,13 +1495,6 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
-history@^5.2.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
- integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==
- dependencies:
- "@babel/runtime" "^7.7.6"
-
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
@@ -2172,20 +2163,19 @@ react-refresh@^0.14.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
-react-router-dom@6:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.3.0.tgz#a0216da813454e521905b5fa55e0e5176123f43d"
- integrity sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==
+react-router-dom@^6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.4.0.tgz#a7d7c394c9e730b045cdd4f5d6c2d1ccb9e26947"
+ integrity sha512-4Aw1xmXKeleYYQ3x0Lcl2undHR6yMjXZjd9DKZd53SGOYqirrUThyUb0wwAX5VZAyvSuzjNJmZlJ3rR9+/vzqg==
dependencies:
- history "^5.2.0"
- react-router "6.3.0"
+ react-router "6.4.0"
-react-router@6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557"
- integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==
+react-router@6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.4.0.tgz#68449c23dc893fc7a57db068c19987be1de72edb"
+ integrity sha512-B+5bEXFlgR1XUdHYR6P94g299SjrfCBMmEDJNcFbpAyRH1j1748yt9NdDhW3++nw1lk3zQJ6aOO66zUx3KlTZg==
dependencies:
- history "^5.2.0"
+ "@remix-run/router" "1.0.0"
react@^18.1.0:
version "18.2.0"