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