Добавлены модели и функциональность для управления администраторами, включая авторизацию через JWT, запросы и мутации для получения информации об администраторах и управления пользователями. Обновлены стили и логика работы с токенами в Apollo Client. Улучшен интерфейс взаимодействия с пользователем.

This commit is contained in:
Bivekich
2025-07-19 14:53:45 +03:00
parent f24c015021
commit 6287449521
26 changed files with 3931 additions and 19 deletions

255
src/hooks/useAdminAuth.ts Normal file
View 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
}
}