Files
nademitex_user/src/stores/auth.ts
T
2026-09-19 16:59:15 +03:30

142 lines
3.6 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { User } from '@/types'
import {
getCurrentUser,
logout as authLogout,
sendOtp,
verifyOtp,
updateProfile as authUpdateProfile,
fetchMe,
} from '@/services/authService'
import {
getPendingRegister,
setPendingRegister,
type PendingRegister,
} from '@/utils/pendingRegister'
import { useCartStore } from './cart'
import { useOrderStore } from './order'
import { useCatalogStore } from './catalog'
import { useNotificationStore } from './notification'
import { useFavoritesStore } from './favorites'
export const useAuthStore = defineStore('auth', () => {
const user = ref<User | null>(getCurrentUser())
const loading = ref(false)
const error = ref<string | null>(null)
const pendingRegister = ref<PendingRegister | null>(getPendingRegister())
const isAuthenticated = computed(() => !!user.value)
const fullName = computed(() =>
user.value ? `${user.value.firstName} ${user.value.lastName}` : '',
)
const isAgent = computed(() => user.value?.appRole === 'agent')
const isCustomerOnly = computed(
() => !!user.value && user.value.appRole !== 'agent',
)
function clearError() {
error.value = null
}
function clearPendingRegister() {
pendingRegister.value = null
setPendingRegister(null)
}
async function requestOtp(
phone: string,
options: { firstName?: string; lastName?: string; isRegister: boolean },
) {
loading.value = true
error.value = null
try {
// Re-read storage on every call (survives HMR / refresh / separate tabs).
const stored = getPendingRegister()
pendingRegister.value = stored
const firstName = options.firstName?.trim() || stored?.firstName
const lastName = options.lastName?.trim() || stored?.lastName
if (options.isRegister && firstName && lastName) {
pendingRegister.value = { firstName, lastName }
setPendingRegister(pendingRegister.value)
}
const result = await sendOtp(phone, {
isRegister: options.isRegister,
firstName,
lastName,
})
if (!result.success) error.value = result.message
return result
} finally {
loading.value = false
}
}
async function confirmOtp(phone: string, code: string) {
loading.value = true
error.value = null
const result = await verifyOtp(phone, code)
loading.value = false
if (result.success && result.user) {
user.value = result.user
clearPendingRegister()
await Promise.all([
useCatalogStore().loadCompanies(),
useCartStore().hydrate(),
useOrderStore().hydrate(),
useNotificationStore().hydrate(),
useFavoritesStore().hydrate(),
])
} else {
error.value = result.message
}
return result
}
function logout() {
authLogout()
user.value = null
clearPendingRegister()
useCartStore().resetLocal()
useOrderStore().resetLocal()
useNotificationStore().resetLocal()
useFavoritesStore().resetLocal()
}
async function updateProfile(
data: Partial<Pick<User, 'firstName' | 'lastName' | 'nationalId' | 'avatarUrl' | 'address'>>,
) {
if (!user.value) return null
const updated = await authUpdateProfile(data)
if (updated) user.value = updated
return updated
}
async function hydrate() {
user.value = getCurrentUser()
if (!user.value) return
const me = await fetchMe()
user.value = me
}
return {
user,
loading,
error,
isAuthenticated,
fullName,
isAgent,
isCustomerOnly,
clearError,
requestOtp,
confirmOtp,
logout,
updateProfile,
hydrate,
}
})