|
|
@ -1,16 +1,16 @@ |
|
|
import { createContext, useContext, useState, type ReactNode } from 'react'; |
|
|
import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'; |
|
|
|
|
|
import { storageGet, storageSet } from '../lib/storage'; |
|
|
|
|
|
|
|
|
/* ===================== 鉴权(引导/登录)上下文 ===================== |
|
|
/* ===================== 鉴权(引导/登录)上下文 ===================== |
|
|
* 管理「引导页是否看过」「是否已登录」「登录令牌」。 |
|
|
* 管理「引导页是否看过」「是否已登录」「登录令牌」「分端标记」。 |
|
|
* 与 RoleContext 配合形成完整漏斗: |
|
|
* 与 RoleContext 配合形成完整漏斗: |
|
|
* 首次启动 → 引导页 → 登录页 → 选择身份(identity-select) → 分端设置 → 对应端 |
|
|
* 首次启动 → 引导页 → 登录页 → 选择身份(identity-select) → 分端设置 → 对应端 |
|
|
* - 求职者:求职意向设置(job-preference) → 求职端 (tabs) |
|
|
* - 求职者:求职意向设置(job-preference) → 求职端 (tabs) |
|
|
* - 招聘者:企业认证(enterprise-certification) → 企业端 (enterprise) |
|
|
* - 招聘者:企业认证(enterprise-certification) → 企业端 (enterprise) |
|
|
* 两个分端设置步骤均允许跳过,设置完成后置位对应标记,不再重复强制。 |
|
|
* 两个分端设置步骤均允许跳过,设置完成后置位对应标记,不再重复强制。 |
|
|
* |
|
|
* |
|
|
* 持久化:当前为会话级(内存)实现,App 重启后回到初始态, |
|
|
* 持久化:已接入 @react-native-async-storage/async-storage, |
|
|
* 需重新引导/登录。若已安装 @react-native-async-storage/async-storage, |
|
|
* 五字段以 JSON 整体存入 'auth' 键,App 重启后自动恢复引导/登录/身份态。 |
|
|
* 可将底部 memoryAuth 替换为真实读写,即可跨重启记住引导/登录态。 |
|
|
|
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
export interface AuthContextValue { |
|
|
export interface AuthContextValue { |
|
|
@ -46,8 +46,9 @@ interface MemoryAuth { |
|
|
enterpriseVerified: boolean; |
|
|
enterpriseVerified: boolean; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** 会话级内存状态(重启即重置) */ |
|
|
const AUTH_KEY = 'auth'; |
|
|
let memoryAuth: MemoryAuth = { |
|
|
|
|
|
|
|
|
const DEFAULT_AUTH: MemoryAuth = { |
|
|
onboardingSeen: false, |
|
|
onboardingSeen: false, |
|
|
isLoggedIn: false, |
|
|
isLoggedIn: false, |
|
|
token: null, |
|
|
token: null, |
|
|
@ -55,42 +56,75 @@ let memoryAuth: MemoryAuth = { |
|
|
enterpriseVerified: false, |
|
|
enterpriseVerified: false, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** 会话级内存镜像(同步读取用),真实来源为 async-storage */ |
|
|
|
|
|
let memoryAuth: MemoryAuth = { ...DEFAULT_AUTH }; |
|
|
|
|
|
|
|
|
|
|
|
function persistAuth(state: MemoryAuth): void { |
|
|
|
|
|
memoryAuth = state; |
|
|
|
|
|
void storageSet(AUTH_KEY, JSON.stringify(state)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function loadAuth(): Promise<MemoryAuth | null> { |
|
|
|
|
|
return storageGet(AUTH_KEY).then((raw) => { |
|
|
|
|
|
if (!raw) return null; |
|
|
|
|
|
try { |
|
|
|
|
|
return JSON.parse(raw) as MemoryAuth; |
|
|
|
|
|
} catch { |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
export function AuthProvider({ children }: { children: ReactNode }) { |
|
|
export function AuthProvider({ children }: { children: ReactNode }) { |
|
|
const [state, setState] = useState<MemoryAuth>(memoryAuth); |
|
|
const [state, setState] = useState<MemoryAuth>(memoryAuth); |
|
|
|
|
|
|
|
|
|
|
|
// 启动时从 async-storage 恢复登录/引导/分端标记
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
let active = true; |
|
|
|
|
|
loadAuth().then((stored) => { |
|
|
|
|
|
if (active && stored) { |
|
|
|
|
|
memoryAuth = stored; |
|
|
|
|
|
setState(stored); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
return () => { |
|
|
|
|
|
active = false; |
|
|
|
|
|
}; |
|
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
const completeOnboarding = () => { |
|
|
const completeOnboarding = () => { |
|
|
const next = { ...state, onboardingSeen: true }; |
|
|
const next = { ...state, onboardingSeen: true }; |
|
|
memoryAuth = next; |
|
|
persistAuth(next); |
|
|
setState(next); |
|
|
setState(next); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const login = (token: string) => { |
|
|
const login = (token: string) => { |
|
|
const next = { ...state, isLoggedIn: true, token }; |
|
|
const next = { ...state, isLoggedIn: true, token }; |
|
|
memoryAuth = next; |
|
|
persistAuth(next); |
|
|
setState(next); |
|
|
setState(next); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const logout = () => { |
|
|
const logout = () => { |
|
|
const next = { |
|
|
const next: MemoryAuth = { |
|
|
...state, |
|
|
...state, |
|
|
isLoggedIn: false, |
|
|
isLoggedIn: false, |
|
|
token: null, |
|
|
token: null, |
|
|
candidateSetupDone: false, |
|
|
candidateSetupDone: false, |
|
|
enterpriseVerified: false, |
|
|
enterpriseVerified: false, |
|
|
}; |
|
|
}; |
|
|
memoryAuth = next; |
|
|
persistAuth(next); |
|
|
setState(next); |
|
|
setState(next); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const completeCandidateSetup = () => { |
|
|
const completeCandidateSetup = () => { |
|
|
const next = { ...state, candidateSetupDone: true }; |
|
|
const next = { ...state, candidateSetupDone: true }; |
|
|
memoryAuth = next; |
|
|
persistAuth(next); |
|
|
setState(next); |
|
|
setState(next); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const completeEnterpriseVerify = () => { |
|
|
const completeEnterpriseVerify = () => { |
|
|
const next = { ...state, enterpriseVerified: true }; |
|
|
const next = { ...state, enterpriseVerified: true }; |
|
|
memoryAuth = next; |
|
|
persistAuth(next); |
|
|
setState(next); |
|
|
setState(next); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|