XuqmGroup-RNChatDemo/src/context/AuthContext.tsx

118 行
4.0 KiB
TypeScript

import React, { createContext, useCallback, useContext, useEffect, useState } from 'react'
import { Alert, Linking } from 'react-native'
import { XuqmSDK, ImSDK, UpdateSDK } from '@xuqm/rn-sdk'
import { demoApi, type UserProfile } from '../api/demo'
import { save, load, clearSession, K } from '../utils/storage'
import pluginMeta from '../../plugin.json'
const APP_ID = 'ak_demo_chat'
const SERVER_URL = 'https://dev.xuqinmin.com'
interface AuthState {
ready: boolean
userId: string | null
profile: UserProfile | null
}
interface AuthContextValue extends AuthState {
login(userId: string, password: string): Promise<void>
register(userId: string, password: string, nickname: string): Promise<void>
logout(): Promise<void>
refreshProfile(): Promise<void>
updateProfile(data: Partial<Pick<UserProfile, 'nickname' | 'avatar' | 'gender'>>): Promise<void>
}
const AuthContext = createContext<AuthContextValue | null>(null)
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = useState<AuthState>({ ready: false, userId: null, profile: null })
const initSDK = useCallback(async (userId: string, imToken: string, profile: UserProfile) => {
await XuqmSDK.initialize({ appId: APP_ID, serverUrl: SERVER_URL })
await ImSDK.loginWithToken(userId, imToken, 'xuqm_im')
setState({ ready: true, userId, profile })
UpdateSDK.checkAppUpdate()
.then(update => {
if (update) {
Alert.alert(
'发现新版本',
`${update.versionName} 是否立即更新?`,
[
{ text: '稍后', style: 'cancel' },
{ text: '立即更新', onPress: () => update.downloadUrl && Linking.openURL(update.downloadUrl) },
],
)
} else {
UpdateSDK.checkRnUpdate(pluginMeta.moduleId).catch(() => {})
}
})
.catch(() => {})
}, [])
useEffect(() => {
const restore = async () => {
try {
const demoToken = await load<string>(K.DEMO_TOKEN)
const imToken = await load<string>(K.IM_TOKEN)
const profile = await load<UserProfile>(K.PROFILE)
if (demoToken && imToken && profile) {
await initSDK(profile.userId, imToken, profile)
return
}
} catch {
await clearSession()
}
setState(s => ({ ...s, ready: true }))
}
restore()
}, [initSDK])
const handleAuthResult = useCallback(async (result: { demoToken: string; imToken: string; profile: UserProfile }) => {
await save(K.DEMO_TOKEN, result.demoToken)
await save(K.IM_TOKEN, result.imToken)
await save(K.PROFILE, result.profile)
await initSDK(result.profile.userId, result.imToken, result.profile)
}, [initSDK])
const login = useCallback(async (userId: string, password: string) => {
const result = await demoApi.login(userId, password)
await handleAuthResult(result)
}, [handleAuthResult])
const register = useCallback(async (userId: string, password: string, nickname: string) => {
const result = await demoApi.register(userId, password, nickname)
await handleAuthResult(result)
}, [handleAuthResult])
const logout = useCallback(async () => {
ImSDK.disconnect()
await clearSession()
setState({ ready: true, userId: null, profile: null })
}, [])
const refreshProfile = useCallback(async () => {
const profile = await demoApi.getProfile()
await save(K.PROFILE, profile)
setState(s => ({ ...s, profile }))
}, [])
const updateProfile = useCallback(async (data: Partial<Pick<UserProfile, 'nickname' | 'avatar' | 'gender'>>) => {
const profile = await demoApi.updateProfile(data)
await save(K.PROFILE, profile)
setState(s => ({ ...s, profile }))
}, [])
return (
<AuthContext.Provider value={{ ...state, login, register, logout, refreshProfile, updateProfile }}>
{children}
</AuthContext.Provider>
)
}
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext)
if (!ctx) throw new Error('useAuth must be used inside AuthProvider')
return ctx
}