"use client"; // ============================================================================ // Auth Provider // ============================================================================ import React, { createContext, useContext, useState, useEffect, useCallback, } from "react"; import { useRouter } from "next/navigation"; import { authApi } from "@/lib/api"; import { USE_MOCKS, STORAGE_KEYS } from "@/lib/utils/constants"; import type { User } from "@/lib/types/api"; interface AuthContextType { user: User | null; loading: boolean; error: string | null; login: (token: string) => Promise; loginMock: () => Promise; logout: () => void; refreshUser: () => Promise; } const AuthContext = createContext(undefined); export const useAuth = () => { const context = useContext(AuthContext); if (!context) { throw new Error("useAuth must be used within AuthProvider"); } return context; }; interface AuthProviderProps { children: React.ReactNode; } export const AuthProvider: React.FC = ({ children }) => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const router = useRouter(); // Initialize auth state on mount useEffect(() => { const initAuth = async () => { try { if (!authApi.isAuthenticated()) { setLoading(false); return; } // Try to get user from storage first const storedUser = authApi.getUserFromStorage(); if (storedUser) { setUser(storedUser); setLoading(false); return; } // If no stored user, fetch from API const userData = await authApi.me(); setUser(userData); } catch (err: any) { console.error("Auth initialization error:", err); // Clear invalid tokens authApi.logout(); } finally { setLoading(false); } }; initAuth(); }, []); // Login with token from Telegram bot const login = useCallback( async (token: string) => { try { setLoading(true); setError(null); // Exchange token for JWT await authApi.complete(token); // Fetch user data with the JWT token if (!USE_MOCKS) { const userData = await authApi.me(); setUser(userData); // Save user to storage if (typeof window !== "undefined") { localStorage.setItem(STORAGE_KEYS.USER, JSON.stringify(userData)); } } else { // For mocks, get user from mock data const userData = authApi.getUserFromStorage(); setUser(userData); } // Redirect to home router.push("/"); } catch (err: any) { const errorMessage = err?.detail || err?.error?.message || "Ошибка авторизации"; setError(errorMessage); throw err; } finally { setLoading(false); } }, [router] ); // Mock login (for development without backend) const loginMock = useCallback(async () => { if (!USE_MOCKS) { throw new Error("Mock login is only available in mock mode"); } try { setLoading(true); setError(null); // Use mock token await login("mock_token_123"); } catch (err: any) { const errorMessage = err?.error?.message || "Ошибка мок-авторизации"; setError(errorMessage); throw err; } finally { setLoading(false); } }, [login]); // Logout const logout = useCallback(() => { authApi.logout(); setUser(null); router.push("/login"); }, [router]); // Refresh user data const refreshUser = useCallback(async () => { try { const userData = await authApi.me(); setUser(userData); } catch (err) { console.error("Error refreshing user:", err); throw err; } }, []); const value: AuthContextType = { user, loading, error, login, loginMock, logout, refreshUser, }; return {children}; };