expo-duooomi-app/stores/userStore.ts

189 lines
4.5 KiB
TypeScript

import { root } from '@repo/core'
import { DeviceController } from '@repo/sdk'
import * as Application from 'expo-application'
import { router } from 'expo-router'
import { makeAutoObservable, runInAction } from 'mobx'
import { Platform } from 'react-native'
import { getSession, signOut as authSignOut } from '@/lib/auth'
import { storage } from '@/utils'
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?: {
expiresAt: Date
token: string
createdAt: Date
updatedAt: Date
ipAddress?: string | null
userAgent?: string | null
userId: string
impersonatedBy?: string | null
activeOrganizationId?: string | null
activeTeamId?: string | null
id: string
}
}
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 getUserData() {
const sessionRes = await getSession()
// console.log('getUserData sessionRes--------:', JSON.stringify(sessionRes))
const data = sessionRes.data
if (!data) {
this.reset()
router.replace('/auth')
return
}
const { session, user } = data
// console.log('获取用户信息--------:', JSON.stringify(data))
runInAction(() => {
this.session = { session, user }
this.user = user || null
this.isLogin = !!user
})
if (user?.id) {
this.bindDevice()
}
}
// 设置加载状态
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)
}
}
// 重置store状态
reset() {
this.session = null
this.isLoading = false
this.error = null
this.scannedQR = null
this.setUser(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()