[feat] Implement sso flow
This commit is contained in:
parent
b33bb0aa1b
commit
c6d55c9da3
@ -2,7 +2,6 @@ import { AxiosInstance } from 'axios';
|
|||||||
import Header from '../_APITool/Header';
|
import Header from '../_APITool/Header';
|
||||||
import {
|
import {
|
||||||
UserAPIProps,
|
UserAPIProps,
|
||||||
PostUserRefreshAPIPromise,
|
|
||||||
GetUserSingleSignInAPIPromise,
|
GetUserSingleSignInAPIPromise,
|
||||||
GetUserAccountInfoAPIPromise,
|
GetUserAccountInfoAPIPromise,
|
||||||
PostUserSignOutAPIPromise,
|
PostUserSignOutAPIPromise,
|
||||||
@ -12,7 +11,7 @@ export function CreatUserAPI({ axios, header }: { axios: AxiosInstance; header:
|
|||||||
return {
|
return {
|
||||||
getUserSSO: async (backUrl: string): Promise<GetUserSingleSignInAPIPromise> => {
|
getUserSSO: async (backUrl: string): Promise<GetUserSingleSignInAPIPromise> => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get('/account/login/sso', {
|
const res = await axios.get('/login', {
|
||||||
params: {
|
params: {
|
||||||
back_url: backUrl,
|
back_url: backUrl,
|
||||||
},
|
},
|
||||||
@ -26,44 +25,25 @@ export function CreatUserAPI({ axios, header }: { axios: AxiosInstance; header:
|
|||||||
return errorMessage;
|
return errorMessage;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
postUserRefreshToken: async (): Promise<PostUserRefreshAPIPromise> => {
|
|
||||||
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<GetUserAccountInfoAPIPromise> => {
|
getUserAccountInfo: async (): Promise<GetUserAccountInfoAPIPromise> => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get('/account', {
|
const res = await axios.get('/userinfo', {
|
||||||
headers: { ...header.header },
|
headers: { ...header.header },
|
||||||
});
|
});
|
||||||
return res.data;
|
return res.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = {
|
const errorMessage = {
|
||||||
account: {
|
|
||||||
_id: '',
|
|
||||||
username: '',
|
|
||||||
email: '',
|
|
||||||
display_name: '',
|
display_name: '',
|
||||||
createdAt: '',
|
email: '',
|
||||||
updatedAt: '',
|
groups: [],
|
||||||
error: error.response?.data,
|
username: '',
|
||||||
},
|
|
||||||
};
|
};
|
||||||
return errorMessage;
|
return errorMessage;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
postUserSignOut: async (): Promise<PostUserSignOutAPIPromise> => {
|
postUserSignOut: async (): Promise<PostUserSignOutAPIPromise> => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.post('/account/logout', undefined, {
|
const res = await axios.post('/logout', undefined, {
|
||||||
headers: { ...header.header },
|
headers: { ...header.header },
|
||||||
});
|
});
|
||||||
return res.data;
|
return res.data;
|
||||||
|
9
src/api/user-apis/types.d.ts
vendored
9
src/api/user-apis/types.d.ts
vendored
@ -1,7 +1,6 @@
|
|||||||
import { APIError } from '@Models/GeneralTypes';
|
import { APIError } from '@Models/GeneralTypes';
|
||||||
import {
|
import {
|
||||||
UserTokenInfo,
|
UserAccountInfo,
|
||||||
UserSignInInfo,
|
|
||||||
UserOAuthUrl,
|
UserOAuthUrl,
|
||||||
UserSignOutUrl,
|
UserSignOutUrl,
|
||||||
} from '@Models/Redux/User/types';
|
} from '@Models/Redux/User/types';
|
||||||
@ -9,10 +8,7 @@ import {
|
|||||||
export interface GetUserSingleSignInAPIPromise extends UserOAuthUrl {
|
export interface GetUserSingleSignInAPIPromise extends UserOAuthUrl {
|
||||||
error?: APIError;
|
error?: APIError;
|
||||||
}
|
}
|
||||||
export interface PostUserRefreshAPIPromise extends UserTokenInfo {
|
export interface GetUserAccountInfoAPIPromise extends UserAccountInfo {
|
||||||
error?: APIError;
|
|
||||||
}
|
|
||||||
export interface GetUserAccountInfoAPIPromise extends UserSignInInfo {
|
|
||||||
error?: APIError;
|
error?: APIError;
|
||||||
}
|
}
|
||||||
export interface PostUserSignOutAPIPromise extends UserSignOutUrl {
|
export interface PostUserSignOutAPIPromise extends UserSignOutUrl {
|
||||||
@ -21,7 +17,6 @@ export interface PostUserSignOutAPIPromise extends UserSignOutUrl {
|
|||||||
|
|
||||||
export interface UserAPIProps {
|
export interface UserAPIProps {
|
||||||
getUserSSO: (backUrl: string) => Promise<GetUserSingleSignInAPIPromise>;
|
getUserSSO: (backUrl: string) => Promise<GetUserSingleSignInAPIPromise>;
|
||||||
postUserRefreshToken: () => Promise<PostUserRefreshAPIPromise>;
|
|
||||||
getUserAccountInfo: () => Promise<GetUserAccountInfoAPIPromise>;
|
getUserAccountInfo: () => Promise<GetUserAccountInfoAPIPromise>;
|
||||||
postUserSignOut: () => Promise<PostUserSignOutAPIPromise>;
|
postUserSignOut: () => Promise<PostUserSignOutAPIPromise>;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { createMuiTheme, ThemeOptions } from '@material-ui/core';
|
import { createTheme, ThemeOptions } from '@material-ui/core/styles';
|
||||||
import ValidConfig from './ThemeConfig';
|
import ValidConfig from './ThemeConfig';
|
||||||
import ThemeType from './ThemeType';
|
import ThemeType from './ThemeType';
|
||||||
|
|
||||||
export default function CreateTheme(themeType = ThemeType.v1): ThemeOptions {
|
export default function CreateTheme(themeType = ThemeType.v1): ThemeOptions {
|
||||||
const theme = { ...createMuiTheme(ValidConfig[themeType]) };
|
const theme = { ...createTheme(ValidConfig[themeType]) };
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,13 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
:local(.homeInfoContainer) {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
:local(.homeInfoItem) {
|
||||||
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,57 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo, useEffect, useState } from 'react';
|
||||||
import classNames from 'classnames';
|
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';
|
import Styles from './index.module.css';
|
||||||
|
|
||||||
function Home(): React.ReactElement {
|
function Home(): React.ReactElement {
|
||||||
/* Global & Local State */
|
/* 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 */
|
/* Main */
|
||||||
return <div className={classNames(Styles.homeContainer)}>Home</div>;
|
return (
|
||||||
|
<div className={classNames(Styles.homeContainer)}>
|
||||||
|
<div className={classNames(Styles.homeInfoContainer)}>
|
||||||
|
<Typography className={classNames(Styles.homeInfoItem)} variant="h2">使用者名稱</Typography>
|
||||||
|
<Typography className={classNames(Styles.homeInfoItem)} variant="h3">{storeUser.userAccount.username}</Typography>
|
||||||
|
<Typography className={classNames(Styles.homeInfoItem)} variant="h2">顯示名稱</Typography>
|
||||||
|
<Typography className={classNames(Styles.homeInfoItem)} variant="h3">
|
||||||
|
{storeUser.userAccount.display_name}
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classNames(Styles.homeInfoItem)} variant="h2">電子信箱</Typography>
|
||||||
|
<Typography className={classNames(Styles.homeInfoItem)} variant="h3">{storeUser.userAccount.email}</Typography>
|
||||||
|
<Typography className={classNames(Styles.homeInfoItem)} variant="h2">允許觸及的 Groups</Typography>
|
||||||
|
<Typography className={classNames(Styles.homeInfoItem)} variant="h3">
|
||||||
|
{storeUser.userAccount.groups.join('')}
|
||||||
|
</Typography>
|
||||||
|
<Button variant="contained" color="primary" onClick={onSignOut}>登出</Button>
|
||||||
|
</div>
|
||||||
|
<Loading typePosition="absolute" typeZIndex={20000} typeIcon="line:fix" isLoading={isLoading} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
export default memo(Home);
|
export default memo(Home);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable */
|
||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import { useHistory, useLocation } from 'react-router-dom';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
import { Base64 } from 'js-base64';
|
import { Base64 } from 'js-base64';
|
||||||
|
@ -38,8 +38,11 @@ function SignIn(): React.ReactElement {
|
|||||||
});
|
});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isFirstInitial) return;
|
if (!isFirstInitial) return;
|
||||||
|
if (storeUser.userOAuth.url) {
|
||||||
|
window.location.href = storeUser.userOAuth.url;
|
||||||
|
}
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, [storeUser.userAccount]);
|
}, [storeUser.userOAuth]);
|
||||||
/* Main */
|
/* Main */
|
||||||
return (
|
return (
|
||||||
<div className={classNames(Styles.signInContainer)}>
|
<div className={classNames(Styles.signInContainer)}>
|
||||||
|
@ -1,55 +1,55 @@
|
|||||||
import Immerable from '@Models/GeneralImmer';
|
import Immerable from '@Models/GeneralImmer';
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import { UserSignInInfo, UserAccountInfo, UserOAuthUrl } from './types';
|
import { UserAccountInfo, UserOAuthUrl, UserSignOutUrl } from './types';
|
||||||
|
|
||||||
class User extends Immerable {
|
class User extends Immerable {
|
||||||
public userIsLogin: boolean;
|
public userIsLogin: boolean;
|
||||||
|
|
||||||
public userAuthCheck: boolean;
|
public userAuthCheck: boolean;
|
||||||
|
|
||||||
public userAccount: UserSignInInfo;
|
public userAccount: UserAccountInfo;
|
||||||
|
|
||||||
public userToken: string;
|
public userToken: string;
|
||||||
|
|
||||||
public userOAuth: UserOAuthUrl;
|
public userOAuth: UserOAuthUrl;
|
||||||
|
|
||||||
|
public userSignOutUrl: UserSignOutUrl;
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super();
|
super();
|
||||||
this.userIsLogin = false;
|
this.userIsLogin = false;
|
||||||
this.userAuthCheck = true;
|
this.userAuthCheck = false;
|
||||||
this.userAccount = {
|
this.userAccount = {
|
||||||
account: {
|
|
||||||
_id: '',
|
|
||||||
username: '',
|
|
||||||
email: '',
|
|
||||||
display_name: '',
|
display_name: '',
|
||||||
createdAt: '',
|
email: '',
|
||||||
updatedAt: '',
|
groups: [],
|
||||||
},
|
username: '',
|
||||||
};
|
};
|
||||||
this.userToken = '';
|
this.userToken = '';
|
||||||
this.userOAuth = {
|
this.userOAuth = {
|
||||||
url: '',
|
url: '',
|
||||||
};
|
};
|
||||||
|
this.userSignOutUrl = {
|
||||||
|
url: '',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public initialize(): void {
|
public initialize(): void {
|
||||||
this.userIsLogin = false;
|
this.userIsLogin = false;
|
||||||
this.userAuthCheck = false;
|
this.userAuthCheck = false;
|
||||||
this.userAccount = {
|
this.userAccount = {
|
||||||
account: {
|
|
||||||
_id: '',
|
|
||||||
username: '',
|
|
||||||
email: '',
|
|
||||||
display_name: '',
|
display_name: '',
|
||||||
createdAt: '',
|
email: '',
|
||||||
updatedAt: '',
|
groups: [],
|
||||||
},
|
username: '',
|
||||||
};
|
};
|
||||||
this.userToken = '';
|
this.userToken = '';
|
||||||
this.userOAuth = {
|
this.userOAuth = {
|
||||||
url: '',
|
url: '',
|
||||||
};
|
};
|
||||||
|
this.userSignOutUrl = {
|
||||||
|
url: '',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateUserLoginState(newUserLoginState: boolean): void {
|
public updateUserLoginState(newUserLoginState: boolean): void {
|
||||||
@ -65,12 +65,16 @@ class User extends Immerable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public updateUserAccountInFo(newUserAccount: UserAccountInfo): void {
|
public updateUserAccountInFo(newUserAccount: UserAccountInfo): void {
|
||||||
this.userAccount.account = cloneDeep(newUserAccount);
|
this.userAccount = cloneDeep(newUserAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateUserOAuthUrl(newUserOAuth: UserOAuthUrl): void {
|
public updateUserOAuthUrl(newUserOAuth: UserOAuthUrl): void {
|
||||||
this.userOAuth = cloneDeep(newUserOAuth);
|
this.userOAuth = cloneDeep(newUserOAuth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateUserSignOutUrl(newSignOutUrl: UserSignOutUrl): void {
|
||||||
|
this.userSignOutUrl = cloneDeep(newSignOutUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default User;
|
export default User;
|
||||||
|
16
src/models/Redux/User/types.d.ts
vendored
16
src/models/Redux/User/types.d.ts
vendored
@ -1,13 +1,8 @@
|
|||||||
import { TimeStamp } from '@Models/GeneralTypes';
|
export interface UserAccountInfo {
|
||||||
|
|
||||||
export interface UserAccountInfo extends TimeStamp {
|
|
||||||
_id: string;
|
|
||||||
username: string;
|
|
||||||
email: string;
|
|
||||||
display_name: string;
|
display_name: string;
|
||||||
}
|
email: string;
|
||||||
export interface UserSignInInfo {
|
groups: string[];
|
||||||
account: UserAccountInfo;
|
username: string;
|
||||||
}
|
}
|
||||||
export interface UserTokenInfo {
|
export interface UserTokenInfo {
|
||||||
token: string;
|
token: string;
|
||||||
@ -15,6 +10,9 @@ export interface UserTokenInfo {
|
|||||||
export interface UserOAuthUrl {
|
export interface UserOAuthUrl {
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
export interface UserSignOutUrl {
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
export interface UserOAuthResponse {
|
export interface UserOAuthResponse {
|
||||||
success?: string;
|
success?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import API from '@API/index';
|
import API from '@API/index';
|
||||||
import Env from '@Env/index';
|
import Env from '@Env/index';
|
||||||
import { postGlobalReduxReset } from '@Reducers/global/actions';
|
import { postGlobalReduxReset } from '@Reducers/global/actions';
|
||||||
import { errorCatch } from './errorCapture';
|
|
||||||
|
|
||||||
const EXPIRE_TIME_MS = 1000 * 60 * 60 * 24; // 確認一天前有沒有過期
|
const EXPIRE_TIME_MS = 1000 * 60 * 60 * 24; // 確認一天前有沒有過期
|
||||||
|
|
||||||
@ -32,17 +31,8 @@ export const readLocalUserToken = async (env: Env, api: API): Promise<boolean> =
|
|||||||
removeLocalUserToken(env);
|
removeLocalUserToken(env);
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
if (result.error) {
|
|
||||||
api.removeAccessToken();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
export const checkUserTokenIsValid = async (env: Env, api: API, dispatch: any): Promise<boolean> => {
|
export const checkUserTokenIsValid = async (env: Env, api: API, dispatch: any): Promise<boolean> => {
|
||||||
@ -56,27 +46,10 @@ export const checkUserTokenIsValid = async (env: Env, api: API, dispatch: any):
|
|||||||
}
|
}
|
||||||
/* 過期 */
|
/* 過期 */
|
||||||
if (isAccessTokenExpired) {
|
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();
|
api.removeAccessToken();
|
||||||
dispatch(postGlobalReduxReset());
|
dispatch(postGlobalReduxReset());
|
||||||
dispatch(errorCatch(result.error));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* 不合法 */
|
/* 不合法 */
|
||||||
|
@ -5,6 +5,7 @@ enum User {
|
|||||||
SET_USER_TOKEN = 'SET_USER_TOKEN',
|
SET_USER_TOKEN = 'SET_USER_TOKEN',
|
||||||
SET_USER_ACCOUNT_INFO = 'SET_USER_ACCOUNT_INFO',
|
SET_USER_ACCOUNT_INFO = 'SET_USER_ACCOUNT_INFO',
|
||||||
SET_USER_OAUTH_URL = 'SET_USER_OAUTH_URL',
|
SET_USER_OAUTH_URL = 'SET_USER_OAUTH_URL',
|
||||||
|
SET_USER_SIGN_OUT_URL = 'SET_USER_SIGN_OUT_URL',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default User;
|
export default User;
|
||||||
|
@ -2,9 +2,13 @@ import { ThunkAction } from 'redux-thunk';
|
|||||||
import { StoreState } from '@Reducers/_InitializeStore/types';
|
import { StoreState } from '@Reducers/_InitializeStore/types';
|
||||||
import { MiddleWare } from '@Reducers/_initializeMiddleware/types';
|
import { MiddleWare } from '@Reducers/_initializeMiddleware/types';
|
||||||
import { errorCatch } from '@Reducers/_Capture/errorCapture';
|
import { errorCatch } from '@Reducers/_Capture/errorCapture';
|
||||||
|
import { postGlobalReduxReset } from '@Reducers/global/actions';
|
||||||
import { delay } from '@Tools/utility';
|
import { delay } from '@Tools/utility';
|
||||||
import {
|
import {
|
||||||
checkUserTokenIsValid,
|
checkUserTokenIsValid,
|
||||||
|
saveLocalUserToken,
|
||||||
|
readLocalUserToken,
|
||||||
|
removeLocalUserToken,
|
||||||
} from '@Reducers/_Capture/tokenCapture';
|
} from '@Reducers/_Capture/tokenCapture';
|
||||||
import USER_ACTION from '@Reducers/_Constants/User';
|
import USER_ACTION from '@Reducers/_Constants/User';
|
||||||
import {
|
import {
|
||||||
@ -13,8 +17,10 @@ import {
|
|||||||
SetUserTokenAction,
|
SetUserTokenAction,
|
||||||
SetUserAccountInfoAction,
|
SetUserAccountInfoAction,
|
||||||
SetUserOAuthAction,
|
SetUserOAuthAction,
|
||||||
|
SetUserSignOutAction,
|
||||||
UserAccountInfo,
|
UserAccountInfo,
|
||||||
UserOAuthUrl,
|
UserOAuthUrl,
|
||||||
|
UserSignOutUrl,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
/* User */
|
/* User */
|
||||||
@ -38,6 +44,10 @@ export const SET_USER_OAUTH_URL = ({ url }: { url: UserOAuthUrl }): SetUserOAuth
|
|||||||
type: USER_ACTION.SET_USER_OAUTH_URL,
|
type: USER_ACTION.SET_USER_OAUTH_URL,
|
||||||
url,
|
url,
|
||||||
});
|
});
|
||||||
|
export const SET_USER_SIGN_OUT_URL = ({ url }: { url: UserSignOutUrl }): SetUserSignOutAction => ({
|
||||||
|
type: USER_ACTION.SET_USER_SIGN_OUT_URL,
|
||||||
|
url,
|
||||||
|
});
|
||||||
|
|
||||||
/* User Action */
|
/* User Action */
|
||||||
export const getUserAccountInfo = (): ThunkAction<Promise<void>, StoreState, MiddleWare, { type: string }> => async (
|
export const getUserAccountInfo = (): ThunkAction<Promise<void>, StoreState, MiddleWare, { type: string }> => async (
|
||||||
@ -50,7 +60,7 @@ export const getUserAccountInfo = (): ThunkAction<Promise<void>, StoreState, Mid
|
|||||||
const result = await api.user.getUserAccountInfo();
|
const result = await api.user.getUserAccountInfo();
|
||||||
dispatch(
|
dispatch(
|
||||||
SET_USER_ACCOUNT_INFO({
|
SET_USER_ACCOUNT_INFO({
|
||||||
accountInfo: result.account,
|
accountInfo: result,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
@ -77,3 +87,59 @@ export const getUserSSO = (
|
|||||||
dispatch(errorCatch(result.error));
|
dispatch(errorCatch(result.error));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
export const getUserIsLogin = (): ThunkAction<Promise<void>, StoreState, MiddleWare, { type: string }> => async (
|
||||||
|
dispatch,
|
||||||
|
getState,
|
||||||
|
{ api, env },
|
||||||
|
): Promise<void> => {
|
||||||
|
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<Promise<void>, StoreState, MiddleWare, { type: string }> => async (
|
||||||
|
dispatch,
|
||||||
|
getState,
|
||||||
|
{ api, env },
|
||||||
|
): Promise<void> => {
|
||||||
|
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<Promise<void>, StoreState, MiddleWare, { type: string }> => async (
|
||||||
|
dispatch,
|
||||||
|
getState,
|
||||||
|
{ api, env },
|
||||||
|
): Promise<void> => {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -26,6 +26,9 @@ export function createUserReducer(params: CreateUserReducerParams): Reducer<User
|
|||||||
case USER_ACTION.SET_USER_OAUTH_URL:
|
case USER_ACTION.SET_USER_OAUTH_URL:
|
||||||
draft.updateUserOAuthUrl(action.url);
|
draft.updateUserOAuthUrl(action.url);
|
||||||
break;
|
break;
|
||||||
|
case USER_ACTION.SET_USER_SIGN_OUT_URL:
|
||||||
|
draft.updateUserSignOutUrl(action.url);
|
||||||
|
break;
|
||||||
case GLOBAL_ACTION.SET_GLOBAL_REDUX_RESET:
|
case GLOBAL_ACTION.SET_GLOBAL_REDUX_RESET:
|
||||||
draft.initialize();
|
draft.initialize();
|
||||||
break;
|
break;
|
||||||
|
12
src/reducers/user/types.d.ts
vendored
12
src/reducers/user/types.d.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
import USER_ACTION from '@Reducers/_Constants/User';
|
import USER_ACTION from '@Reducers/_Constants/User';
|
||||||
import User from '@Models/Redux/User';
|
import User from '@Models/Redux/User';
|
||||||
import { UserAccountInfo, UserOAuthUrl } from '@Models/Redux/User/types';
|
import { UserAccountInfo, UserOAuthUrl, UserSignOutUrl } from '@Models/Redux/User/types';
|
||||||
import { SetGlobalReduxResetAction } from '@Reducers/global/types';
|
import { SetGlobalReduxResetAction } from '@Reducers/global/types';
|
||||||
|
|
||||||
export type UserState = User;
|
export type UserState = User;
|
||||||
@ -38,6 +38,11 @@ export interface SetUserOAuthAction {
|
|||||||
url: UserOAuthUrl;
|
url: UserOAuthUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetUserSignOutAction {
|
||||||
|
type: USER_ACTION.SET_USER_SIGN_OUT_URL;
|
||||||
|
url: UserSignOutUrl;
|
||||||
|
}
|
||||||
|
|
||||||
export type UserActionTypes =
|
export type UserActionTypes =
|
||||||
| SetUserContentInitialAction
|
| SetUserContentInitialAction
|
||||||
| SetUserLoginStateAction
|
| SetUserLoginStateAction
|
||||||
@ -45,6 +50,7 @@ export type UserActionTypes =
|
|||||||
| SetUserTokenAction
|
| SetUserTokenAction
|
||||||
| SetUserAccountInfoAction
|
| SetUserAccountInfoAction
|
||||||
| SetGlobalReduxResetAction
|
| SetGlobalReduxResetAction
|
||||||
| SetUserOAuthAction;
|
| SetUserOAuthAction
|
||||||
|
| SetUserSignOutAction;
|
||||||
|
|
||||||
export { UserAccountInfo, UserOAuthUrl };
|
export { UserAccountInfo, UserOAuthUrl, UserSignOutUrl };
|
||||||
|
Loading…
Reference in New Issue
Block a user