Files
frontend/app/context/AuthContext.jsx
fullofempt 433b9e896c WIP API
2025-12-14 18:47:14 +05:00

152 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { createContext, useContext, useState, useEffect } from "react";
import { useRouter } from "next/navigation";
const AuthContext = createContext(null);
// базовый URL из YAML (у себя можешь вынести в .env)
const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL;
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null); // {id, email, role, name, accessToken, refreshToken}
const [loading, setLoading] = useState(true);
const router = useRouter();
// поднимаем пользователя из localStorage
useEffect(() => {
const saved =
typeof window !== "undefined"
? localStorage.getItem("authUser")
: null;
if (saved) {
setUser(JSON.parse(saved));
}
setLoading(false);
}, []);
// основная авторизация: запрос на /auth/login
const login = async (email, password) => {
const res = await fetch(`${API_BASE}/auth/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ email, password }),
});
// удобно смотреть в Postman: этот же URL, метод, тело из JSON[file:519]
// в Postman просто скопируй URL и тело — увидишь точный JSON-ответ
if (!res.ok) {
// читаем тело как текст, чтобы в консоли / Postman было понятно
let errorMessage = "Неверный логин или пароль";
try {
const data = await res.json();
if (data.error) {
errorMessage = data.error;
}
} catch {
const text = await res.text();
if (text) errorMessage = text;
}
throw new Error(errorMessage);
}
const data = await res.json();
// ожидаемый формат по YAML: AuthResponse[file:519]
// Примерно:
// {
// "access_token": "...",
// "refresh_token": "...",
// "token_type": "bearer",
// "user": { "id": 1, "email": "...", ... }
// }
const authUser = {
id: data.user?.id,
email: data.user?.email,
name: data.user?.first_name || data.user?.email,
// роль пока не знаем наверняка — вытащим отдельным запросом
role: null,
accessToken: data.access_token,
refreshToken: data.refresh_token,
};
// 1) сохраняем токены/пользователя
setUser(authUser);
localStorage.setItem("authUser", JSON.stringify(authUser));
// 2) тянем роли пользователя (GET /users/me/roles)[file:519]
try {
const rolesRes = await fetch(`${API_BASE}/users/me/roles`, {
method: "GET",
headers: {
Authorization: `Bearer ${data.access_token}`,
Accept: "application/json",
},
});
if (rolesRes.ok) {
const roles = await rolesRes.json(); // массив объектов Role[file:519]
// ищем первую подходящую роль
const roleNames = roles.map((r) => r.name);
let appRole = null;
if (roleNames.includes("requester")) appRole = "requester";
if (roleNames.includes("volunteer")) appRole = "volunteer";
if (roleNames.includes("moderator")) appRole = "moderator";
if (roleNames.includes("admin")) appRole = "moderator"; // можно перекинуть в модераторский интерфейс
const updatedUser = { ...authUser, role: appRole };
setUser(updatedUser);
localStorage.setItem("authUser", JSON.stringify(updatedUser));
// 3) редирект по роли (как у тебя было)
if (appRole === "requester") router.push("/home");
else if (appRole === "volunteer") router.push("/mainValounter");
else if (appRole === "moderator") router.push("/moderatorMain");
else router.push("/home"); // запасной вариант
} else {
// если роли не достали, всё равно пускаем как обычного пользователя
router.push("/home");
}
} catch (e) {
console.error("Ошибка получения ролей:", e);
router.push("/home");
}
};
const logout = async () => {
try {
if (user?.accessToken) {
await fetch(`${API_BASE}/auth/logout`, {
method: "POST",
headers: {
Authorization: `Bearer ${user.accessToken}`,
Accept: "application/json",
},
});
}
} catch (e) {
console.error("Ошибка logout:", e);
}
setUser(null);
localStorage.removeItem("authUser");
router.push("/login");
};
const value = {
user,
loading,
isAuthenticated: !!user,
login,
logout,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
export const useAuth = () => useContext(AuthContext);