Добавлены модели и функциональность для управления администраторами, включая авторизацию через JWT, запросы и мутации для получения информации об администраторах и управления пользователями. Обновлены стили и логика работы с токенами в Apollo Client. Улучшен интерфейс взаимодействия с пользователем.
This commit is contained in:
255
src/hooks/useAdminAuth.ts
Normal file
255
src/hooks/useAdminAuth.ts
Normal file
@ -0,0 +1,255 @@
|
||||
import { useMutation, useQuery } from '@apollo/client'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { gql } from '@apollo/client'
|
||||
import { apolloClient } from '@/lib/apollo-client'
|
||||
|
||||
// GraphQL мутации и запросы
|
||||
const ADMIN_LOGIN = gql`
|
||||
mutation AdminLogin($username: String!, $password: String!) {
|
||||
adminLogin(username: $username, password: $password) {
|
||||
success
|
||||
message
|
||||
token
|
||||
admin {
|
||||
id
|
||||
username
|
||||
email
|
||||
isActive
|
||||
lastLogin
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const ADMIN_ME = gql`
|
||||
query AdminMe {
|
||||
adminMe {
|
||||
id
|
||||
username
|
||||
email
|
||||
isActive
|
||||
lastLogin
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const ADMIN_LOGOUT = gql`
|
||||
mutation AdminLogout {
|
||||
adminLogout
|
||||
}
|
||||
`
|
||||
|
||||
interface Admin {
|
||||
id: string
|
||||
username: string
|
||||
email?: string
|
||||
isActive: boolean
|
||||
lastLogin?: string
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
interface UseAdminAuthReturn {
|
||||
login: (username: string, password: string) => Promise<{ success: boolean; message: string; admin?: Admin }>
|
||||
logout: () => void
|
||||
admin: Admin | null
|
||||
isAuthenticated: boolean
|
||||
isLoading: boolean
|
||||
checkAuth: () => Promise<void>
|
||||
}
|
||||
|
||||
// Утилиты для работы с токенами администратора
|
||||
const ADMIN_TOKEN_KEY = 'adminAuthToken'
|
||||
const ADMIN_DATA_KEY = 'adminData'
|
||||
|
||||
const setAdminToken = (token: string) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem(ADMIN_TOKEN_KEY, token)
|
||||
}
|
||||
}
|
||||
|
||||
const getAdminToken = (): string | null => {
|
||||
if (typeof window !== 'undefined') {
|
||||
return localStorage.getItem(ADMIN_TOKEN_KEY)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const removeAdminToken = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem(ADMIN_TOKEN_KEY)
|
||||
localStorage.removeItem(ADMIN_DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
const setAdminData = (admin: Admin) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem(ADMIN_DATA_KEY, JSON.stringify(admin))
|
||||
}
|
||||
}
|
||||
|
||||
export const useAdminAuth = (): UseAdminAuthReturn => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [admin, setAdmin] = useState<Admin | null>(null)
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(() => {
|
||||
return !!getAdminToken()
|
||||
})
|
||||
const [isCheckingAuth, setIsCheckingAuth] = useState(false)
|
||||
|
||||
const [adminLoginMutation] = useMutation(ADMIN_LOGIN)
|
||||
const [adminLogoutMutation] = useMutation(ADMIN_LOGOUT)
|
||||
|
||||
// Проверка авторизации администратора
|
||||
const checkAuth = async () => {
|
||||
if (isCheckingAuth) {
|
||||
return
|
||||
}
|
||||
|
||||
const token = getAdminToken()
|
||||
console.log('useAdminAuth - checkAuth called, token exists:', !!token)
|
||||
|
||||
if (!token) {
|
||||
setIsAuthenticated(false)
|
||||
setAdmin(null)
|
||||
setIsCheckingAuth(false)
|
||||
return
|
||||
}
|
||||
|
||||
setIsCheckingAuth(true)
|
||||
|
||||
try {
|
||||
console.log('useAdminAuth - Making ADMIN_ME query')
|
||||
const { data } = await apolloClient.query({
|
||||
query: ADMIN_ME,
|
||||
errorPolicy: 'all',
|
||||
fetchPolicy: 'network-only',
|
||||
context: {
|
||||
headers: {
|
||||
authorization: `Bearer ${token}`
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log('useAdminAuth - ADMIN_ME response:', !!data?.adminMe)
|
||||
if (data?.adminMe) {
|
||||
setAdmin(data.adminMe)
|
||||
setIsAuthenticated(true)
|
||||
setAdminData(data.adminMe)
|
||||
console.log('useAdminAuth - Admin authenticated:', data.adminMe.username)
|
||||
} else {
|
||||
setIsAuthenticated(false)
|
||||
setAdmin(null)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
console.log('useAdminAuth - ADMIN_ME error:', error)
|
||||
if ((error as { graphQLErrors?: Array<{ extensions?: { code?: string } }> })?.graphQLErrors?.some((e) => e.extensions?.code === 'UNAUTHENTICATED')) {
|
||||
logout()
|
||||
} else {
|
||||
setIsAuthenticated(false)
|
||||
setAdmin(null)
|
||||
}
|
||||
} finally {
|
||||
setIsCheckingAuth(false)
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем авторизацию при загрузке компонента
|
||||
useEffect(() => {
|
||||
const token = getAdminToken()
|
||||
console.log('useAdminAuth - useEffect init, token exists:', !!token, 'admin exists:', !!admin, 'isChecking:', isCheckingAuth)
|
||||
|
||||
if (token && !admin && !isCheckingAuth) {
|
||||
console.log('useAdminAuth - Running checkAuth because token exists but no admin data')
|
||||
checkAuth()
|
||||
} else if (!token) {
|
||||
console.log('useAdminAuth - No token, setting unauthenticated state')
|
||||
setIsAuthenticated(false)
|
||||
setAdmin(null)
|
||||
}
|
||||
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const login = async (username: string, password: string) => {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
console.log('useAdminAuth - Starting adminLogin mutation')
|
||||
|
||||
const { data } = await adminLoginMutation({
|
||||
variables: { username, password }
|
||||
})
|
||||
|
||||
console.log('useAdminAuth - GraphQL response data:', data)
|
||||
const result = data.adminLogin
|
||||
console.log('useAdminAuth - Admin login result:', {
|
||||
success: result.success,
|
||||
hasToken: !!result.token,
|
||||
hasAdmin: !!result.admin,
|
||||
message: result.message
|
||||
})
|
||||
|
||||
if (result.success && result.token && result.admin) {
|
||||
// Сохраняем токен и данные администратора
|
||||
console.log('useAdminAuth - Saving admin token')
|
||||
setAdminToken(result.token)
|
||||
setAdminData(result.admin)
|
||||
|
||||
// Обновляем состояние хука
|
||||
setAdmin(result.admin)
|
||||
setIsAuthenticated(true)
|
||||
console.log('useAdminAuth - State updated: admin set, isAuthenticated=true')
|
||||
|
||||
// Принудительно обновляем Apollo Client
|
||||
apolloClient.resetStore()
|
||||
|
||||
// Перенаправляем в админ-дашборд
|
||||
if (typeof window !== 'undefined') {
|
||||
window.location.href = '/admin/dashboard'
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: result.message,
|
||||
admin: result.admin
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: result.message
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error during admin login:', error)
|
||||
return {
|
||||
success: false,
|
||||
message: 'Ошибка при авторизации'
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const logout = () => {
|
||||
console.log('useAdminAuth - Logging out')
|
||||
removeAdminToken()
|
||||
setAdmin(null)
|
||||
setIsAuthenticated(false)
|
||||
apolloClient.resetStore()
|
||||
|
||||
// Перенаправляем на страницу входа администратора
|
||||
if (typeof window !== 'undefined') {
|
||||
window.location.href = '/admin'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
login,
|
||||
logout,
|
||||
admin,
|
||||
isAuthenticated,
|
||||
isLoading,
|
||||
checkAuth
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user