Files
sfera-new/src/hooks/useAuth.ts

368 lines
11 KiB
TypeScript
Raw 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 { useMutation } from '@apollo/client'
import { useState, useEffect } from 'react'
import {
SEND_SMS_CODE,
VERIFY_SMS_CODE,
REGISTER_FULFILLMENT_ORGANIZATION,
REGISTER_SELLER_ORGANIZATION
} from '@/graphql/mutations'
import { GET_ME } from '@/graphql/queries'
import { setAuthToken, setUserData, removeAuthToken, getAuthToken, apolloClient } from '@/lib/apollo-client'
import { useApolloRefresh } from './useApolloRefresh'
interface User {
id: string
phone: string
avatar?: string
managerName?: string
createdAt?: string
organization?: {
id: string
inn: string
kpp?: string
name?: string
fullName?: string
address?: string
addressFull?: string
ogrn?: string
ogrnDate?: string
status?: string
actualityDate?: string
registrationDate?: string
liquidationDate?: string
managementName?: string
managementPost?: string
opfCode?: string
opfFull?: string
opfShort?: string
okato?: string
oktmo?: string
okpo?: string
okved?: string
employeeCount?: number
revenue?: string
taxSystem?: string
phones?: unknown
emails?: unknown
type: 'FULFILLMENT' | 'SELLER' | 'LOGIST' | 'WHOLESALE'
apiKeys: Array<{
id: string
marketplace: 'WILDBERRIES' | 'OZON'
isActive: boolean
validationData?: unknown
}>
}
}
interface UseAuthReturn {
// SMS методы
sendSmsCode: (phone: string) => Promise<{ success: boolean; message: string }>
verifySmsCode: (phone: string, code: string) => Promise<{
success: boolean
message: string
user?: User
}>
// Регистрация организаций
registerFulfillmentOrganization: (phone: string, inn: string) => Promise<{
success: boolean
message: string
user?: User
}>
registerSellerOrganization: (data: {
phone: string
wbApiKey?: string
ozonApiKey?: string
ozonClientId?: string
}) => Promise<{
success: boolean
message: string
user?: User
}>
// Состояние
user: User | null
isAuthenticated: boolean
isLoading: boolean
checkAuth: () => Promise<void>
logout: () => void
}
export const useAuth = (): UseAuthReturn => {
// Инициализируем состояния с проверкой токена
const [isLoading, setIsLoading] = useState(false)
const [user, setUser] = useState<User | null>(null)
const [isAuthenticated, setIsAuthenticated] = useState(() => {
// Проверяем наличие токена при инициализации
return !!getAuthToken()
})
const [isCheckingAuth, setIsCheckingAuth] = useState(false) // Защита от повторных вызовов
const { refreshApolloClient } = useApolloRefresh()
const [sendSmsCodeMutation] = useMutation(SEND_SMS_CODE)
const [verifySmsCodeMutation] = useMutation(VERIFY_SMS_CODE)
const [registerFulfillmentMutation] = useMutation(REGISTER_FULFILLMENT_ORGANIZATION)
const [registerSellerMutation] = useMutation(REGISTER_SELLER_ORGANIZATION)
// Проверка авторизации при инициализации
const checkAuth = async () => {
if (isCheckingAuth) {
console.log('useAuth - checkAuth already in progress, skipping')
return
}
const token = getAuthToken()
console.log('useAuth - checkAuth called, token exists:', !!token)
if (!token) {
setIsAuthenticated(false)
setUser(null)
setIsCheckingAuth(false)
return
}
setIsCheckingAuth(true)
try {
console.log('useAuth - Making GET_ME query')
const { data } = await apolloClient.query({
query: GET_ME,
errorPolicy: 'all',
fetchPolicy: 'network-only' // Всегда делаем свежий запрос
})
console.log('useAuth - GET_ME response:', !!data?.me)
if (data?.me) {
setUser(data.me)
setIsAuthenticated(true)
setUserData(data.me)
console.log('useAuth - User authenticated:', data.me.phone)
} else {
setIsAuthenticated(false)
setUser(null)
}
} catch (error: unknown) {
console.log('useAuth - GET_ME error:', error)
if ((error as { graphQLErrors?: Array<{ extensions?: { code?: string } }> })?.graphQLErrors?.some((e) => e.extensions?.code === 'UNAUTHENTICATED')) {
logout()
} else {
setIsAuthenticated(false)
setUser(null)
}
} finally {
setIsCheckingAuth(false)
}
}
// Проверяем авторизацию при загрузке компонента только если нет данных пользователя
useEffect(() => {
const token = getAuthToken()
console.log('useAuth - useEffect init, token exists:', !!token, 'user exists:', !!user, 'isChecking:', isCheckingAuth)
if (token && !user && !isCheckingAuth) {
console.log('useAuth - Running checkAuth because token exists but no user data')
checkAuth()
} else if (!token) {
console.log('useAuth - No token, setting unauthenticated state')
setIsAuthenticated(false)
setUser(null)
}
}, []) // eslint-disable-line react-hooks/exhaustive-deps
const sendSmsCode = async (phone: string) => {
try {
setIsLoading(true)
const { data } = await sendSmsCodeMutation({
variables: { phone }
})
return {
success: data.sendSmsCode.success,
message: data.sendSmsCode.message
}
} catch (error) {
console.error('Error sending SMS code:', error)
return {
success: false,
message: 'Ошибка при отправке SMS кода'
}
} finally {
setIsLoading(false)
}
}
const verifySmsCode = async (phone: string, code: string) => {
try {
setIsLoading(true)
console.log('useAuth - Starting verifySmsCode mutation with:', { phone, code })
const { data } = await verifySmsCodeMutation({
variables: { phone, code }
})
console.log('useAuth - GraphQL response data:', data)
const result = data.verifySmsCode
console.log('useAuth - SMS verification result:', {
success: result.success,
hasToken: !!result.token,
hasUser: !!result.user,
message: result.message
})
if (result.success && result.token && result.user) {
// Сохраняем токен и данные пользователя
console.log('useAuth - Saving token:', result.token ? `${result.token.substring(0, 20)}...` : 'No token')
setAuthToken(result.token)
setUserData(result.user)
// Обновляем состояние хука
setUser(result.user)
setIsAuthenticated(true)
console.log('useAuth - State updated: user set, isAuthenticated=true')
// Проверяем что токен действительно сохранился
const savedToken = typeof window !== 'undefined' ? localStorage.getItem('authToken') : null
console.log('useAuth - Token saved to localStorage:', savedToken ? `${savedToken.substring(0, 20)}...` : 'Not saved')
// Принудительно обновляем Apollo Client
refreshApolloClient()
return {
success: true,
message: result.message,
user: result.user
}
}
return {
success: false,
message: result.message
}
} catch (error) {
console.error('Error verifying SMS code:', error)
console.error('Error details:', {
message: error instanceof Error ? error.message : 'Unknown error',
graphQLErrors: (error as { graphQLErrors?: unknown })?.graphQLErrors,
networkError: (error as { networkError?: unknown })?.networkError
})
return {
success: false,
message: 'Ошибка при проверке SMS кода'
}
} finally {
setIsLoading(false)
}
}
const registerFulfillmentOrganization = async (phone: string, inn: string) => {
try {
setIsLoading(true)
// Проверяем токен перед запросом
const currentToken = typeof window !== 'undefined' ? localStorage.getItem('authToken') : null
console.log('useAuth - Token before registerFulfillment request:', currentToken ? `${currentToken.substring(0, 20)}...` : 'No token')
const { data } = await registerFulfillmentMutation({
variables: {
input: { phone, inn }
}
})
const result = data.registerFulfillmentOrganization
if (result.success && result.user) {
// Обновляем данные пользователя
setUserData(result.user)
return {
success: true,
message: result.message,
user: result.user
}
}
return {
success: false,
message: result.message
}
} catch (error) {
console.error('Error registering fulfillment organization:', error)
return {
success: false,
message: 'Ошибка при регистрации фулфилмент организации'
}
} finally {
setIsLoading(false)
}
}
const registerSellerOrganization = async (data: {
phone: string
wbApiKey?: string
ozonApiKey?: string
ozonClientId?: string
}) => {
try {
setIsLoading(true)
const { data: result } = await registerSellerMutation({
variables: { input: data }
})
const registerResult = result.registerSellerOrganization
if (registerResult.success && registerResult.user) {
// Обновляем данные пользователя
setUserData(registerResult.user)
return {
success: true,
message: registerResult.message,
user: registerResult.user
}
}
return {
success: false,
message: registerResult.message
}
} catch (error) {
console.error('Error registering seller organization:', error)
return {
success: false,
message: 'Ошибка при регистрации селлер организации'
}
} finally {
setIsLoading(false)
}
}
const logout = () => {
console.log('useAuth - Logging out')
removeAuthToken()
setUser(null)
setIsAuthenticated(false)
refreshApolloClient()
// Перенаправляем на главную страницу
if (typeof window !== 'undefined') {
window.location.href = '/'
}
}
return {
// SMS методы
sendSmsCode,
verifySmsCode,
// Регистрация организаций
registerFulfillmentOrganization,
registerSellerOrganization,
// Состояние
user,
isAuthenticated,
isLoading,
checkAuth,
logout
}
}