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:
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user