158 lines
3.4 KiB
TypeScript
158 lines
3.4 KiB
TypeScript
import Loader from "@/components/loader";
|
|
import React, {createContext, useEffect, useReducer} from "react";
|
|
import {auth, getUserInfo} from "@/service/api/user.ts";
|
|
import {getAuthToken, setAuthToken} from "@/hooks/useAuth.ts";
|
|
import {getRoleByUsername} from "@/contexts/auth/role.ts";
|
|
|
|
|
|
const AuthContext = createContext<AuthContextType | null>(null)
|
|
|
|
const initialState: AuthProps = {
|
|
isLoggedIn: false,
|
|
isInitialized: false,
|
|
user: null
|
|
};
|
|
const authReducer = (state: AuthProps, action: { action?: string, payload: Partial<AuthProps> }) => {
|
|
return {
|
|
...state,
|
|
...action.payload,
|
|
}
|
|
}
|
|
|
|
const UserRoleStorageKey = 'user-current-role';
|
|
|
|
function getCurrentRole(username: string) {
|
|
return (localStorage.getItem(UserRoleStorageKey) || getRoleByUsername(username)) as UserRole
|
|
}
|
|
|
|
export function setCurrentRole(role: UserRole) {
|
|
localStorage.setItem(UserRoleStorageKey, role)
|
|
}
|
|
|
|
function removeRoleStorage() {
|
|
localStorage.removeItem(UserRoleStorageKey)
|
|
}
|
|
|
|
function getInitUserData(user: UserProfile) {
|
|
const {roles} = user;
|
|
const role = !roles || roles.length === 0 ? 'staff' : (
|
|
roles.includes('root') ? 'root' : (
|
|
roles.includes('fo') ? 'fo' : 'ro'
|
|
)
|
|
) as UserRole
|
|
|
|
return {
|
|
...user,
|
|
origin_role: role,
|
|
role: role == 'root' ? (getCurrentRole(user.username) || role) : role
|
|
}
|
|
}
|
|
|
|
export const AuthProvider = ({children}: { children: React.ReactNode }) => {
|
|
const [state, dispatch] = useReducer(authReducer, initialState);
|
|
|
|
// MOCK INIT DATA
|
|
const refreshUserInfo = async ()=>{
|
|
const user = await getUserInfo();
|
|
dispatch({
|
|
action: 'refresh',
|
|
payload: {
|
|
isLoggedIn: !!user,
|
|
user: getInitUserData(user)
|
|
}
|
|
})
|
|
}
|
|
const init = async () => {
|
|
const token = getAuthToken();
|
|
if (!token) {
|
|
dispatch({
|
|
payload: {
|
|
isInitialized: true,
|
|
}
|
|
})
|
|
return 'initialized'
|
|
}
|
|
getUserInfo().then(user => {
|
|
dispatch({
|
|
action: 'init',
|
|
payload: {
|
|
isInitialized: true,
|
|
isLoggedIn: !!user,
|
|
user: getInitUserData(user)
|
|
}
|
|
})
|
|
}).finally(() => {
|
|
dispatch({
|
|
payload: {
|
|
isInitialized: true,
|
|
}
|
|
})
|
|
})
|
|
return 'initialized'
|
|
}
|
|
// 登录
|
|
const login = async (code: string, state: string) => {
|
|
const user = await auth(code, state)
|
|
// 保存token
|
|
setAuthToken(user.token, user.expiration_time ? (new Date(user.expiration_time)).getTime() : -1);
|
|
|
|
//
|
|
dispatch({
|
|
action: 'login',
|
|
payload: {
|
|
isLoggedIn: true,
|
|
user: getInitUserData(user)
|
|
}
|
|
})
|
|
}
|
|
// 登出
|
|
const logout = async () => {
|
|
setTimeout(() => {
|
|
const a = document.createElement('a')
|
|
a.setAttribute('href', 'https://portal.chuhai.edu.hk/signout')
|
|
a.setAttribute('target', '_blank')
|
|
a.click()
|
|
}, 0)
|
|
setAuthToken(null)
|
|
removeRoleStorage()
|
|
dispatch({
|
|
action: 'logout',
|
|
payload: {
|
|
isLoggedIn: false,
|
|
user: null
|
|
}
|
|
})
|
|
}
|
|
const mockLogin = async () => {
|
|
console.log('mock login')
|
|
}
|
|
|
|
const updateUser = async (user: Partial<UserProfile>) => {
|
|
dispatch({
|
|
action: 'updateUser',
|
|
payload: {
|
|
user: {
|
|
...state.user,
|
|
...user
|
|
} as never,
|
|
|
|
}
|
|
})
|
|
};
|
|
|
|
useEffect(() => {
|
|
init().then(console.log)
|
|
}, [])
|
|
|
|
// 判断是否已经初始化
|
|
if (state.isInitialized !== undefined && !state.isInitialized) {
|
|
return <Loader/>;
|
|
}
|
|
return (<AuthContext.Provider value={{
|
|
...state,
|
|
login, logout,
|
|
mockLogin, updateUser,
|
|
refreshUserInfo
|
|
}}>{children}</AuthContext.Provider>)
|
|
}
|
|
export default AuthContext |