368 lines
11 KiB
TypeScript
368 lines
11 KiB
TypeScript
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
|
||
}
|
||
}
|