aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-07-05 22:47:38 +0800
committercrupest <crupest@outlook.com>2021-07-05 22:47:38 +0800
commit6612510d2baa31f6bb946b412351b7992b2ffbe1 (patch)
tree943582be3f5940161d0666fd5a2e4a504466bf9a /FrontEnd
parent5c3f254c6a7ff14981616968b020ed38ca3edf00 (diff)
downloadtimeline-6612510d2baa31f6bb946b412351b7992b2ffbe1.tar.gz
timeline-6612510d2baa31f6bb946b412351b7992b2ffbe1.tar.bz2
timeline-6612510d2baa31f6bb946b412351b7992b2ffbe1.zip
feat: Fix #623, fix #621.
Diffstat (limited to 'FrontEnd')
-rw-r--r--FrontEnd/src/App.tsx100
-rw-r--r--FrontEnd/src/index.tsx4
-rw-r--r--FrontEnd/src/locales/en/translation.json3
-rw-r--r--FrontEnd/src/locales/zh/translation.json3
-rw-r--r--FrontEnd/src/services/user.ts123
5 files changed, 93 insertions, 140 deletions
diff --git a/FrontEnd/src/App.tsx b/FrontEnd/src/App.tsx
index a4363ff5..6497b071 100644
--- a/FrontEnd/src/App.tsx
+++ b/FrontEnd/src/App.tsx
@@ -13,7 +13,7 @@ import TimelinePage from "./views/timeline";
import Search from "./views/search";
import AlertHost from "./views/common/alert/AlertHost";
-import { useRawUser } from "./services/user";
+import { useUser } from "./services/user";
const NoMatch: React.FC = () => {
return <div>Ah-oh, 404!</div>;
@@ -24,60 +24,56 @@ const LazyAdmin = React.lazy(
);
function App(): ReactElement | null {
- const user = useRawUser();
+ const user = useUser();
- if (user === undefined) {
- return <LoadingPage />;
- } else {
- return (
- <React.Suspense fallback={<LoadingPage />}>
- <Router>
- <AppBar />
- <div style={{ height: 56 }} />
- <Switch>
- <Route exact path="/">
- {user == null ? <Home /> : <Center />}
+ return (
+ <React.Suspense fallback={<LoadingPage />}>
+ <Router>
+ <AppBar />
+ <div style={{ height: 56 }} />
+ <Switch>
+ <Route exact path="/">
+ {user == null ? <Home /> : <Center />}
+ </Route>
+ <Route exact path="/home">
+ <Home />
+ </Route>
+ {user != null ? (
+ <Route exact path="/center">
+ <Center />
</Route>
- <Route exact path="/home">
- <Home />
+ ) : null}
+ <Route exact path="/login">
+ <Login />
+ </Route>
+ <Route path="/settings">
+ <Settings />
+ </Route>
+ <Route path="/about">
+ <About />
+ </Route>
+ <Route path="/timelines/:name">
+ <TimelinePage />
+ </Route>
+ <Route path="/users/:username">
+ <User />
+ </Route>
+ <Route path="/search">
+ <Search />
+ </Route>
+ {user && user.hasAdministrationPermission && (
+ <Route path="/admin">
+ <LazyAdmin user={user} />
</Route>
- {user != null ? (
- <Route exact path="/center">
- <Center />
- </Route>
- ) : null}
- <Route exact path="/login">
- <Login />
- </Route>
- <Route path="/settings">
- <Settings />
- </Route>
- <Route path="/about">
- <About />
- </Route>
- <Route path="/timelines/:name">
- <TimelinePage />
- </Route>
- <Route path="/users/:username">
- <User />
- </Route>
- <Route path="/search">
- <Search />
- </Route>
- {user && user.hasAdministrationPermission && (
- <Route path="/admin">
- <LazyAdmin user={user} />
- </Route>
- )}
- <Route>
- <NoMatch />
- </Route>
- </Switch>
- <AlertHost />
- </Router>
- </React.Suspense>
- );
- }
+ )}
+ <Route>
+ <NoMatch />
+ </Route>
+ </Switch>
+ <AlertHost />
+ </Router>
+ </React.Suspense>
+ );
}
export default App;
diff --git a/FrontEnd/src/index.tsx b/FrontEnd/src/index.tsx
index e2132de0..833e2ab8 100644
--- a/FrontEnd/src/index.tsx
+++ b/FrontEnd/src/index.tsx
@@ -14,8 +14,4 @@ import "./service-worker";
import App from "./App";
-import { userService } from "./services/user";
-
-void userService.checkLoginState();
-
ReactDOM.render(<App />, document.getElementById("app"));
diff --git a/FrontEnd/src/locales/en/translation.json b/FrontEnd/src/locales/en/translation.json
index a2766b4e..da824e4a 100644
--- a/FrontEnd/src/locales/en/translation.json
+++ b/FrontEnd/src/locales/en/translation.json
@@ -146,8 +146,7 @@
"login": "login",
"rememberMe": "Remember Me",
"welcomeBack": "Welcome back!",
- "verifyTokenFailed": "User login info is expired. Please login again!",
- "verifyTokenFailedNetwork": "Verifying user login info failed. Please check your network and refresh page!"
+ "tokenInvalid": "Your authentication token is not valid any more. Please log in again!"
},
"login": {
"emptyUsername": "Username can't be empty.",
diff --git a/FrontEnd/src/locales/zh/translation.json b/FrontEnd/src/locales/zh/translation.json
index 5a5a6843..6f1346fb 100644
--- a/FrontEnd/src/locales/zh/translation.json
+++ b/FrontEnd/src/locales/zh/translation.json
@@ -146,8 +146,7 @@
"login": "登录",
"rememberMe": "记住我",
"welcomeBack": "欢迎回来!",
- "verifyTokenFailed": "用户登录信息已过期,请重新登陆!",
- "verifyTokenFailedNetwork": "验证用户登录信息失败,请检查网络连接并刷新页面!"
+ "tokenInvalid": "您的登录信息已失效,请重新登陆!"
},
"login": {
"emptyUsername": "用户名不能为空。",
diff --git a/FrontEnd/src/services/user.ts b/FrontEnd/src/services/user.ts
index 9a8e5687..2f42dd59 100644
--- a/FrontEnd/src/services/user.ts
+++ b/FrontEnd/src/services/user.ts
@@ -3,7 +3,7 @@ import { BehaviorSubject, Observable } from "rxjs";
import { UiLogicError } from "@/common";
-import { HttpNetworkError, setHttpToken } from "@/http/common";
+import { HttpNetworkError, setHttpToken, axios } from "@/http/common";
import {
getHttpTokenClient,
HttpCreateTokenBadCredentialError,
@@ -11,6 +11,7 @@ import {
import { getHttpUserClient, HttpUser, UserPermission } from "@/http/user";
import { pushAlert } from "./alert";
+import { AxiosError } from "axios";
interface IAuthUser extends HttpUser {
token: string;
@@ -58,24 +59,16 @@ export class UserService {
this.userSubject.subscribe((u) => {
setHttpToken(u?.token ?? null);
});
- }
-
- private userSubject = new BehaviorSubject<AuthUser | null | undefined>(
- undefined
- );
-
- get user$(): Observable<AuthUser | null | undefined> {
- return this.userSubject;
- }
-
- get currentUser(): AuthUser | null | undefined {
- return this.userSubject.value;
- }
- async checkLoginState(): Promise<AuthUser | null> {
- if (this.currentUser !== undefined) {
- console.warn("Already checked user. Can't check twice.");
- }
+ axios.interceptors.response.use(undefined, (e: AxiosError) => {
+ if (e.isAxiosError && e.response && e.response.status === 401) {
+ this.userSubject.next(null);
+ pushAlert({
+ type: "danger",
+ message: "user.tokenInvalid",
+ });
+ }
+ });
const savedUserString = localStorage.getItem(USER_STORAGE_KEY);
@@ -89,41 +82,39 @@ export class UserService {
? null
: new AuthUser(savedAuthUserData, savedAuthUserData.token);
- if (savedUser == null) {
- this.userSubject.next(null);
- return null;
+ if (savedUser != null) {
+ this.userSubject.next(savedUser);
+
+ getHttpTokenClient()
+ .verify({ token: savedUser.token })
+ .then(
+ (res) => {
+ const user = new AuthUser(res.user, savedUser.token);
+ localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(user));
+ this.userSubject.next(user);
+ },
+ (error) => {
+ if (!(error instanceof HttpNetworkError)) {
+ localStorage.removeItem(USER_STORAGE_KEY);
+ this.userSubject.next(null);
+ pushAlert({
+ type: "danger",
+ message: "user.tokenInvalid",
+ });
+ }
+ }
+ );
}
+ }
- this.userSubject.next(savedUser);
+ private userSubject = new BehaviorSubject<AuthUser | null>(null);
- const savedToken = savedUser.token;
- try {
- const res = await getHttpTokenClient().verify({ token: savedToken });
- const user = new AuthUser(res.user, savedToken);
- localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(user));
- this.userSubject.next(user);
- pushAlert({
- type: "success",
- message: "user.welcomeBack",
- });
- return user;
- } catch (error) {
- if (error instanceof HttpNetworkError) {
- pushAlert({
- type: "danger",
- message: "user.verifyTokenFailedNetwork",
- });
- return savedUser;
- } else {
- localStorage.removeItem(USER_STORAGE_KEY);
- this.userSubject.next(null);
- pushAlert({
- type: "danger",
- message: "user.verifyTokenFailed",
- });
- return null;
- }
- }
+ get user$(): Observable<AuthUser | null> {
+ return this.userSubject;
+ }
+
+ get currentUser(): AuthUser | null {
+ return this.userSubject.value;
}
async login(
@@ -180,38 +171,10 @@ export class UserService {
export const userService = new UserService();
-export function useRawUser(): AuthUser | null | undefined {
- const [user, setUser] = useState<AuthUser | null | undefined>(
- userService.currentUser
- );
- useEffect(() => {
- const subscription = userService.user$.subscribe((u) => setUser(u));
- return () => {
- subscription.unsubscribe();
- };
- });
- return user;
-}
-
export function useUser(): AuthUser | null {
- const [user, setUser] = useState<AuthUser | null>(() => {
- const initUser = userService.currentUser;
- if (initUser === undefined) {
- throw new UiLogicError(
- "This is a logic error in user module. Current user can't be undefined in useUser."
- );
- }
- return initUser;
- });
+ const [user, setUser] = useState<AuthUser | null>(userService.currentUser);
useEffect(() => {
- const sub = userService.user$.subscribe((u) => {
- if (u === undefined) {
- throw new UiLogicError(
- "This is a logic error in user module. User emitted can't be undefined later."
- );
- }
- setUser(u);
- });
+ const sub = userService.user$.subscribe((u) => setUser(u));
return () => {
sub.unsubscribe();
};