feat(auth): minimal login/logout + ProtectedRoute (B-LOGOUT)

- api/client.js: apiFetch подставляет Bearer-токен, выставляет
  Content-Type: application/json для не-FormData тел, ловит 401 -> событие
- context/AuthContext: валидация токена через /auth/me, loading-гейт,
  logout(), подписка на 401
- components/ProtectedRoute: guard с ролями и заглушкой на время проверки
- pages/Login: форма входа (OAuth2 form-urlencoded), редирект на from
- App.js: AuthProvider, /login, ProtectedRoute на /sar /desktop
  /analysis /admin (admin -> roles=[admin]) /mobile
- AdminDashboard/CaseForm/AnalysisResult: переход на apiFetch
- AdminDashboard: кнопка "Выйти" в шапке (useAuth().logout)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2026-08-20 16:04:05 +00:00
parent c2ad5c1915
commit bef93d159c
10 changed files with 443 additions and 25 deletions
@@ -5,6 +5,7 @@ import Step2Health from "./Step2Health";
import Step2bPsychotype from "./Step2bPsychotype";
import Step3Circumstances from "./Step3Circumstances";
import Step4Environment from "./Step4Environment";
import { apiFetch } from "../../api/client";
import "./CaseForm.css";
const INITIAL_DATA = {
@@ -106,9 +107,8 @@ const CaseForm = ({ isMobile = false }) => {
};
// Создаем карточку
const response = await fetch("/api/v1/cases", {
const response = await apiFetch("/api/v1/cases", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});