feat: sprint 3 — profil utilisateur, badge plan, dropdown Header

- AuthContext.User : plan? { slug, name, level } | null
- UserBadge : nickname + badge plan.slug (fallback free)
- Header : dropdown click (Profil / Déconnexion) + click-outside
- ProfilePage : infos compte, badge plan, edit nickname (PATCH /users/me + re-fetch /auth/me → setUser)
- App : route /profile protégée
- useAuth : réexporte depuis AuthContext, fin de la dérive
This commit is contained in:
2026-03-14 22:33:47 +01:00
parent 30ef7312b5
commit 4e8c1aa849
6 changed files with 209 additions and 44 deletions

View File

@@ -1,38 +1,4 @@
import { useState, useEffect } from 'react';
import { apiFetch } from '../lib/api';
export interface User {
id: string;
email: string | null;
nickname: string;
subscriptionLevel?: number;
}
interface AuthState {
user: User | null;
loading: boolean;
setUser: (u: User | null) => void;
}
interface MeResponse {
success: boolean;
data: { user: User };
}
export function useAuth(): AuthState {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
apiFetch<MeResponse>('/auth/me')
.then((res) => { if (!cancelled) setUser(res.data.user); })
.catch(() => { if (!cancelled) setUser(null); })
.finally(() => { if (!cancelled) setLoading(false); });
return () => { cancelled = true; };
}, []);
return { user, loading, setUser };
}
// Réexporte depuis AuthContext — source unique de vérité auth.
// Ne pas dupliquer User ou la logique de fetch ici.
export type { User } from '../context/AuthContext';
export { useAuthContext as useAuth } from '../context/AuthContext';