import { createContext, useState, useContext, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; import { getApiBaseUrl } from '../utils/apiBaseUrl'; const AuthContext = createContext(null); const API_BASE_URL = getApiBaseUrl(); export function AuthProvider({ children }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const navigate = useNavigate(); useEffect(() => { checkAuth(); }, []); const checkAuth = async () => { const token = localStorage.getItem('accessToken'); const refreshToken = localStorage.getItem('refreshToken'); if (!token || !refreshToken) { setLoading(false); return; } try { const response = await axios.get(`${API_BASE_URL}/auth/me`, { headers: { Authorization: `Bearer ${token}` } }); setUser(response.data); } catch (error) { // Try to refresh token try { const refreshResponse = await axios.post(`${API_BASE_URL}/auth/refresh`, { refreshToken }); localStorage.setItem('accessToken', refreshResponse.data.accessToken); // Retry getting user const userResponse = await axios.get(`${API_BASE_URL}/auth/me`, { headers: { Authorization: `Bearer ${refreshResponse.data.accessToken}` } }); setUser(userResponse.data); } catch (refreshError) { // Refresh failed, logout logout(); } } finally { setLoading(false); } }; const login = async (username, password) => { try { const response = await axios.post(`${API_BASE_URL}/auth/login`, { username, password }); completeLogin(response.data); return { success: true }; } catch (error) { console.error('Login error:', error); return { success: false, error: error.response?.data?.error || 'Login failed' }; } }; const loginWithPasskey = async (credential) => { try { const response = await axios.post( `${API_BASE_URL}/auth/passkeys/authentication/verify`, { response: credential } ); completeLogin(response.data); return { success: true }; } catch (error) { console.error('Passkey login error:', error); return { success: false, error: error.response?.data?.error || 'Не удалось выполнить вход по passkey' }; } }; const completeLogin = ({ user, accessToken, refreshToken }) => { localStorage.setItem('accessToken', accessToken); localStorage.setItem('refreshToken', refreshToken); setUser(user); navigate('/'); }; const logout = async () => { const refreshToken = localStorage.getItem('refreshToken'); if (refreshToken) { try { await axios.post(`${API_BASE_URL}/auth/logout`, { refreshToken }); } catch (error) { console.error('Logout error:', error); } } localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); setUser(null); navigate('/login'); }; const getAccessToken = () => { return localStorage.getItem('accessToken'); }; const value = { user, loading, login, loginWithPasskey, logout, getAccessToken, isAuthenticated: !!user, isAdmin: user?.role === 'admin' }; return {children}; } export function useAuth() { const context = useContext(AuthContext); if (!context) { throw new Error('useAuth must be used within AuthProvider'); } return context; }