152 lines
5.0 KiB
JavaScript
152 lines
5.0 KiB
JavaScript
"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);
|