expo-duooomi-app/stores/userStore.ts

196 lines
4.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { root } from '@repo/core'
import { DeviceController } from '@repo/sdk'
import * as Application from 'expo-application'
import { makeAutoObservable, runInAction } from 'mobx'
import { useEffect } from 'react'
import { Platform } from 'react-native'
import { signOut as authSignOut, useSession } from '@/lib/auth'
import { storage } from '@/utils'
// console.log('useSession---------------', useSession)
interface User {
id: string
email: string
name?: string
image?: string | null
createdAt: Date
updatedAt: Date
emailVerified?: boolean
username?: string | null
banExpires?: Date | null
banReason?: string | null
banned?: boolean | null
displayUsername?: string | null
metadata?: any | null
phoneNumber?: string | null
phoneNumberVerified?: boolean | null
role?: string | null
stripeCustomerId?: string | null
}
interface Session {
user?: User
session?: {
id: string
userId: string
expiresAt: Date
createdAt: Date
updatedAt: Date
activeOrganizationId?: string | null
activeTeamId?: string | null
impersonatedBy?: string | null
ipAddress?: string | null
token?: string | null
userAgent?: string | null
}
}
class UserStore {
user: User | null = null
session: Session | null = null
isLogin: boolean = true
isLoading: boolean = false
error: string | null = null
scannedQR: string | null = null // 扫描的二维码
constructor() {
// autoBind ensures methods keep `this`, and all fields become observable/actions
makeAutoObservable(this)
this.loadLoginState()
}
async loadLoginState() {
const isLogin = await storage.get('isLogin')
runInAction(() => {
this.isLogin = !!isLogin
})
}
// 设置用户信息
async setUser(user: User | null) {
runInAction(() => {
this.user = user
this.isLogin = !!user
})
await storage.set('isLogin', !!user)
}
// 设置会话信息
async setSession(session: Session | null) {
runInAction(() => {
this.session = session
this.user = session?.user || null
this.isLogin = !!session?.user
if (session?.user) {
this.bindDevice()
}
})
await storage.set('isLogin', !!session?.user)
}
// 设置加载状态
setLoading(loading: boolean) {
this.isLoading = loading
}
// 设置错误信息
setError(error: string | null) {
this.error = error
}
// 登出方法
signOut = async () => {
this.setLoading(true)
try {
await authSignOut()
this.reset()
// 登出时重置余额store
const { userBalanceStore } = await import('./userBalanceStore')
userBalanceStore.reset()
} catch (error) {
this.setError(error instanceof Error ? error.message : '登出失败')
console.error('登出失败:', error)
} finally {
this.setLoading(false)
}
}
// 从session更新用户状态
updateFromSession(sessionData: Session | null) {
this.setSession(sessionData)
}
// 重置store状态
reset() {
this.user = null
this.session = null
this.isLoading = false
this.error = null
this.scannedQR = null
}
// ==================== 二维码相关方法 ====================
// 设置扫描的二维码
setScannedQR(value: string) {
this.scannedQR = value
}
// 绑定设备信息
async bindDevice() {
const deviceController = root.get(DeviceController)
const isIos = Platform.OS === 'ios'
const userDeviceId = isIos ? await Application.getIosIdForVendorAsync() : Application.getAndroidId()
const appVersion = Application.nativeApplicationVersion!
const data = {
appVersion,
userDeviceId: userDeviceId!,
}
// console.log('绑定设备数据--------:', data)
deviceController.upsertUserDevice(data).then((r) => {
console.log('绑定设备成功:', r)
})
}
// 绑定吧唧蓝牙设备
async bindBluetooth(params: { sn: string; version: string; userDeviceId?: string }) {
const deviceController = root.get(DeviceController)
const isIos = Platform.OS === 'ios'
const userDeviceId = isIos ? await Application.getIosIdForVendorAsync() : Application.getAndroidId()
const data = {
sn: params.sn,
userDeviceId: params.userDeviceId || userDeviceId!,
version: params.version,
}
// console.log('bindBluetooth--------', data)
deviceController.upsertBluetoothDevice(data).then((r) => {
console.log('bindBluetooth--------', r)
})
}
}
// 创建单例实例
export const userStore = new UserStore()
// 创建一个hook来使用session数据更新store
export const useUserSession = () => {
const session = useSession()
// 使用useEffect在副作用中更新store状态避免在render过程中修改
useEffect(() => {
userStore.setLoading(session.isPending)
userStore.updateFromSession(session.data)
}, [session.isPending, session.data])
return session
}