diff --git a/src/api/user-apis/index.ts b/src/api/user-apis/index.ts index 04dbd98..139b01f 100644 --- a/src/api/user-apis/index.ts +++ b/src/api/user-apis/index.ts @@ -2,7 +2,6 @@ import { AxiosInstance } from 'axios'; import Header from '../_APITool/Header'; import { UserAPIProps, - PostUserRefreshAPIPromise, GetUserSingleSignInAPIPromise, GetUserAccountInfoAPIPromise, PostUserSignOutAPIPromise, @@ -12,7 +11,7 @@ export function CreatUserAPI({ axios, header }: { axios: AxiosInstance; header: return { getUserSSO: async (backUrl: string): Promise => { try { - const res = await axios.get('/account/login/sso', { + const res = await axios.get('/login', { params: { back_url: backUrl, }, @@ -26,44 +25,25 @@ export function CreatUserAPI({ axios, header }: { axios: AxiosInstance; header: return errorMessage; } }, - postUserRefreshToken: async (): Promise => { - try { - const res = await axios.post('/account/refresh_token', undefined, { - headers: { ...header.header }, - }); - return res.data; - } catch (error) { - const errorMessage = { - token: '', - error: error.response?.data, - }; - return errorMessage; - } - }, getUserAccountInfo: async (): Promise => { try { - const res = await axios.get('/account', { + const res = await axios.get('/userinfo', { headers: { ...header.header }, }); return res.data; } catch (error) { const errorMessage = { - account: { - _id: '', - username: '', - email: '', - display_name: '', - createdAt: '', - updatedAt: '', - error: error.response?.data, - }, + display_name: '', + email: '', + groups: [], + username: '', }; return errorMessage; } }, postUserSignOut: async (): Promise => { try { - const res = await axios.post('/account/logout', undefined, { + const res = await axios.post('/logout', undefined, { headers: { ...header.header }, }); return res.data; diff --git a/src/api/user-apis/types.d.ts b/src/api/user-apis/types.d.ts index 8ae296c..8bc8032 100644 --- a/src/api/user-apis/types.d.ts +++ b/src/api/user-apis/types.d.ts @@ -1,7 +1,6 @@ import { APIError } from '@Models/GeneralTypes'; import { - UserTokenInfo, - UserSignInInfo, + UserAccountInfo, UserOAuthUrl, UserSignOutUrl, } from '@Models/Redux/User/types'; @@ -9,10 +8,7 @@ import { export interface GetUserSingleSignInAPIPromise extends UserOAuthUrl { error?: APIError; } -export interface PostUserRefreshAPIPromise extends UserTokenInfo { - error?: APIError; -} -export interface GetUserAccountInfoAPIPromise extends UserSignInInfo { +export interface GetUserAccountInfoAPIPromise extends UserAccountInfo { error?: APIError; } export interface PostUserSignOutAPIPromise extends UserSignOutUrl { @@ -21,7 +17,6 @@ export interface PostUserSignOutAPIPromise extends UserSignOutUrl { export interface UserAPIProps { getUserSSO: (backUrl: string) => Promise; - postUserRefreshToken: () => Promise; getUserAccountInfo: () => Promise; postUserSignOut: () => Promise; } diff --git a/src/base/themes/ThemeCreate.ts b/src/base/themes/ThemeCreate.ts index 56ff601..2fc2eae 100644 --- a/src/base/themes/ThemeCreate.ts +++ b/src/base/themes/ThemeCreate.ts @@ -1,8 +1,8 @@ -import { createMuiTheme, ThemeOptions } from '@material-ui/core'; +import { createTheme, ThemeOptions } from '@material-ui/core/styles'; import ValidConfig from './ThemeConfig'; import ThemeType from './ThemeType'; export default function CreateTheme(themeType = ThemeType.v1): ThemeOptions { - const theme = { ...createMuiTheme(ValidConfig[themeType]) }; + const theme = { ...createTheme(ValidConfig[themeType]) }; return theme; } diff --git a/src/components/Pages/Home/index.module.css b/src/components/Pages/Home/index.module.css index 9d74142..0400ba6 100644 --- a/src/components/Pages/Home/index.module.css +++ b/src/components/Pages/Home/index.module.css @@ -3,4 +3,13 @@ width: 100%; height: 100%; position: relative; + display: flex; + justify-content: center; + align-items: center; +} +:local(.homeInfoContainer) { + position: relative; +} +:local(.homeInfoItem) { + margin-bottom: 8px; } diff --git a/src/components/Pages/Home/index.tsx b/src/components/Pages/Home/index.tsx index 526ec47..9e548b5 100644 --- a/src/components/Pages/Home/index.tsx +++ b/src/components/Pages/Home/index.tsx @@ -1,10 +1,57 @@ -import React, { memo } from 'react'; +import React, { memo, useEffect, useState } from 'react'; import classNames from 'classnames'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; +import useReduxApi from '@Hooks/useReduxApi'; +import useDidMount from '@Hooks/useDidMount'; +import useMappedState from '@Hooks/useMappedState'; +import Loading from '@Components/Base/Loading'; import Styles from './index.module.css'; function Home(): React.ReactElement { /* Global & Local State */ + const reduxUser = useReduxApi('user'); + const storeUser = useMappedState((state) => state.user); + const [isFirstInitial, setIsFirstInitial] = useState(false); + const [isLoading, setIsLoading] = useState(false); + /* Functions */ + const onSignOut = (): void => { + reduxUser('postUserSignOut', []); + }; + const initialize = (): void => { + setIsFirstInitial(true); + }; + /* Hooks */ + useDidMount(() => { + initialize(); + }); + useEffect(() => { + if (!isFirstInitial) return; + if (storeUser.userSignOutUrl.url) { + window.location.href = storeUser.userSignOutUrl.url; + } + setIsLoading(false); + }, [storeUser.userSignOutUrl]); /* Main */ - return
Home
; + return ( +
+
+ 使用者名稱 + {storeUser.userAccount.username} + 顯示名稱 + + {storeUser.userAccount.display_name} + + 電子信箱 + {storeUser.userAccount.email} + 允許觸及的 Groups + + {storeUser.userAccount.groups.join('')} + + +
+ +
+ ); } export default memo(Home); diff --git a/src/components/Pages/OAuth/index.tsx b/src/components/Pages/OAuth/index.tsx index 693d99e..fa97be0 100644 --- a/src/components/Pages/OAuth/index.tsx +++ b/src/components/Pages/OAuth/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable */ import React, { memo } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { Base64 } from 'js-base64'; diff --git a/src/components/Pages/SignIn/index.tsx b/src/components/Pages/SignIn/index.tsx index 9944fec..61598c7 100644 --- a/src/components/Pages/SignIn/index.tsx +++ b/src/components/Pages/SignIn/index.tsx @@ -38,8 +38,11 @@ function SignIn(): React.ReactElement { }); useEffect(() => { if (!isFirstInitial) return; + if (storeUser.userOAuth.url) { + window.location.href = storeUser.userOAuth.url; + } setIsLoading(false); - }, [storeUser.userAccount]); + }, [storeUser.userOAuth]); /* Main */ return (
diff --git a/src/models/Redux/User/index.ts b/src/models/Redux/User/index.ts index ec3090b..ac6f03e 100644 --- a/src/models/Redux/User/index.ts +++ b/src/models/Redux/User/index.ts @@ -1,55 +1,55 @@ import Immerable from '@Models/GeneralImmer'; import cloneDeep from 'lodash/cloneDeep'; -import { UserSignInInfo, UserAccountInfo, UserOAuthUrl } from './types'; +import { UserAccountInfo, UserOAuthUrl, UserSignOutUrl } from './types'; class User extends Immerable { public userIsLogin: boolean; public userAuthCheck: boolean; - public userAccount: UserSignInInfo; + public userAccount: UserAccountInfo; public userToken: string; public userOAuth: UserOAuthUrl; + public userSignOutUrl: UserSignOutUrl; + public constructor() { super(); this.userIsLogin = false; - this.userAuthCheck = true; + this.userAuthCheck = false; this.userAccount = { - account: { - _id: '', - username: '', - email: '', - display_name: '', - createdAt: '', - updatedAt: '', - }, + display_name: '', + email: '', + groups: [], + username: '', }; this.userToken = ''; this.userOAuth = { url: '', }; + this.userSignOutUrl = { + url: '', + }; } public initialize(): void { this.userIsLogin = false; this.userAuthCheck = false; this.userAccount = { - account: { - _id: '', - username: '', - email: '', - display_name: '', - createdAt: '', - updatedAt: '', - }, + display_name: '', + email: '', + groups: [], + username: '', }; this.userToken = ''; this.userOAuth = { url: '', }; + this.userSignOutUrl = { + url: '', + }; } public updateUserLoginState(newUserLoginState: boolean): void { @@ -65,12 +65,16 @@ class User extends Immerable { } public updateUserAccountInFo(newUserAccount: UserAccountInfo): void { - this.userAccount.account = cloneDeep(newUserAccount); + this.userAccount = cloneDeep(newUserAccount); } public updateUserOAuthUrl(newUserOAuth: UserOAuthUrl): void { this.userOAuth = cloneDeep(newUserOAuth); } + + public updateUserSignOutUrl(newSignOutUrl: UserSignOutUrl): void { + this.userSignOutUrl = cloneDeep(newSignOutUrl); + } } export default User; diff --git a/src/models/Redux/User/types.d.ts b/src/models/Redux/User/types.d.ts index ecd0715..5304a78 100644 --- a/src/models/Redux/User/types.d.ts +++ b/src/models/Redux/User/types.d.ts @@ -1,13 +1,8 @@ -import { TimeStamp } from '@Models/GeneralTypes'; - -export interface UserAccountInfo extends TimeStamp { - _id: string; - username: string; - email: string; +export interface UserAccountInfo { display_name: string; -} -export interface UserSignInInfo { - account: UserAccountInfo; + email: string; + groups: string[]; + username: string; } export interface UserTokenInfo { token: string; @@ -15,6 +10,9 @@ export interface UserTokenInfo { export interface UserOAuthUrl { url: string; } +export interface UserSignOutUrl { + url: string; +} export interface UserOAuthResponse { success?: string; error?: string; diff --git a/src/reducers/_Capture/tokenCapture.ts b/src/reducers/_Capture/tokenCapture.ts index 1df7c49..29ff23c 100644 --- a/src/reducers/_Capture/tokenCapture.ts +++ b/src/reducers/_Capture/tokenCapture.ts @@ -1,7 +1,6 @@ import API from '@API/index'; import Env from '@Env/index'; import { postGlobalReduxReset } from '@Reducers/global/actions'; -import { errorCatch } from './errorCapture'; const EXPIRE_TIME_MS = 1000 * 60 * 60 * 24; // 確認一天前有沒有過期 @@ -32,16 +31,7 @@ export const readLocalUserToken = async (env: Env, api: API): Promise = removeLocalUserToken(env); return false; } - const result = await api.user.postUserRefreshToken(); - if (!result.error) { - api.updateAccessToken(result.token); - localStorage.setItem(localTokenName, JSON.stringify({ token: result.token })); - return true; - } - if (result.error) { - api.removeAccessToken(); - return false; - } + return true; } return false; }; @@ -56,26 +46,9 @@ export const checkUserTokenIsValid = async (env: Env, api: API, dispatch: any): } /* 過期 */ if (isAccessTokenExpired) { - const result = await api.user.postUserRefreshToken(); // 嘗試更新 Token - /* 更新成功, 更換 API Token */ - if (!result.error) { - const localTokenName = env.TokenLocalStorageName; - const localToken = localStorage.getItem(localTokenName); - if (localToken) { - api.removeAccessToken(); - localStorage.removeItem(localTokenName); - } - localStorage.setItem(localTokenName, JSON.stringify({ token: result.token })); - api.updateAccessToken(result.token); - return true; - } - /* 更新失敗, 清空所有狀態, 讓使用者重新登入 */ - if (result.error) { - api.removeAccessToken(); - dispatch(postGlobalReduxReset()); - dispatch(errorCatch(result.error)); - return false; - } + api.removeAccessToken(); + dispatch(postGlobalReduxReset()); + return false; } return true; } diff --git a/src/reducers/_Constants/User.ts b/src/reducers/_Constants/User.ts index b8052d7..94a0642 100644 --- a/src/reducers/_Constants/User.ts +++ b/src/reducers/_Constants/User.ts @@ -5,6 +5,7 @@ enum User { SET_USER_TOKEN = 'SET_USER_TOKEN', SET_USER_ACCOUNT_INFO = 'SET_USER_ACCOUNT_INFO', SET_USER_OAUTH_URL = 'SET_USER_OAUTH_URL', + SET_USER_SIGN_OUT_URL = 'SET_USER_SIGN_OUT_URL', } export default User; diff --git a/src/reducers/user/actions.ts b/src/reducers/user/actions.ts index 36a3c8b..eb48b7f 100644 --- a/src/reducers/user/actions.ts +++ b/src/reducers/user/actions.ts @@ -2,9 +2,13 @@ import { ThunkAction } from 'redux-thunk'; import { StoreState } from '@Reducers/_InitializeStore/types'; import { MiddleWare } from '@Reducers/_initializeMiddleware/types'; import { errorCatch } from '@Reducers/_Capture/errorCapture'; +import { postGlobalReduxReset } from '@Reducers/global/actions'; import { delay } from '@Tools/utility'; import { checkUserTokenIsValid, + saveLocalUserToken, + readLocalUserToken, + removeLocalUserToken, } from '@Reducers/_Capture/tokenCapture'; import USER_ACTION from '@Reducers/_Constants/User'; import { @@ -13,8 +17,10 @@ import { SetUserTokenAction, SetUserAccountInfoAction, SetUserOAuthAction, + SetUserSignOutAction, UserAccountInfo, UserOAuthUrl, + UserSignOutUrl, } from './types'; /* User */ @@ -38,6 +44,10 @@ export const SET_USER_OAUTH_URL = ({ url }: { url: UserOAuthUrl }): SetUserOAuth type: USER_ACTION.SET_USER_OAUTH_URL, url, }); +export const SET_USER_SIGN_OUT_URL = ({ url }: { url: UserSignOutUrl }): SetUserSignOutAction => ({ + type: USER_ACTION.SET_USER_SIGN_OUT_URL, + url, +}); /* User Action */ export const getUserAccountInfo = (): ThunkAction, StoreState, MiddleWare, { type: string }> => async ( @@ -50,7 +60,7 @@ export const getUserAccountInfo = (): ThunkAction, StoreState, Mid const result = await api.user.getUserAccountInfo(); dispatch( SET_USER_ACCOUNT_INFO({ - accountInfo: result.account, + accountInfo: result, }), ); if (result.error) { @@ -77,3 +87,59 @@ export const getUserSSO = ( dispatch(errorCatch(result.error)); } }; +export const getUserIsLogin = (): ThunkAction, StoreState, MiddleWare, { type: string }> => async ( + dispatch, + getState, + { api, env }, +): Promise => { + const isValidToken = await readLocalUserToken(env, api); + if (isValidToken) { + dispatch(SET_USER_LOGIN_STATE({ isLogin: true })); + dispatch(getUserAccountInfo()); + } else { + api.removeAccessToken(); + removeLocalUserToken(env); + } + await delay(500); + dispatch(SET_USER_AUTH_STATE({ isAuth: true })); +}; +export const postUserTokenInfoSignIn = ( + token: string, +): ThunkAction, StoreState, MiddleWare, { type: string }> => async ( + dispatch, + getState, + { api, env }, +): Promise => { + api.updateAccessToken(token); + saveLocalUserToken(env, token); + dispatch(SET_USER_TOKEN({ token })); + dispatch(SET_USER_LOGIN_STATE({ isLogin: true })); + dispatch(getUserAccountInfo()); + await delay(500); +}; +export const postUserSignOut = ( + callback?: () => void, +): ThunkAction, StoreState, MiddleWare, { type: string }> => async ( + dispatch, + getState, + { api, env }, +): Promise => { + const result = await api.user.postUserSignOut(); + if (!result.error) { + if (result.url) { + dispatch( + SET_USER_SIGN_OUT_URL({ + url: result, + }), + ); + } else { + dispatch(postGlobalReduxReset()); + if (callback) callback(); + } + api.removeAccessToken(); + removeLocalUserToken(env); + } + if (result.error) { + dispatch(errorCatch(result.error)); + } +}; diff --git a/src/reducers/user/index.ts b/src/reducers/user/index.ts index e89a3a5..9ce38a5 100644 --- a/src/reducers/user/index.ts +++ b/src/reducers/user/index.ts @@ -26,6 +26,9 @@ export function createUserReducer(params: CreateUserReducerParams): Reducer