Frontend : connexion (mot de passe + lien magique) et onglets par rôle
Authentification alignée sur le back-end (Étapes 7/8) : - src/api : schema auth (AccountRead, TokenResponse…), session.ts (jeton Bearer partagé + callback 401), méthodes auth du client HTTP (POST .../auth/login, .../auth/magic-link, .../auth/verify, GET /auth/me) et du mock (comptes coordination + référents + bénévoles, tokens magiques, sessions). - src/auth : AuthProvider/useAuth (jeton en localStorage, réhydratation via /auth/me, déconnexion sur 401), RequireAuth (garde + contrôle de rôle), HomeRedirect, table ROUTE_ROLES. - Pages : /connexion (lien magique, avec lien de démo affiché en mode mock), /connexion/coordination (email + mot de passe). - Router : toutes les routes métier passées derrière <RequireAuth> ; redirection vers l'accueil du rôle. - AppShell : onglets filtrés par rôle (01/02/03/06 coordination, 04 bénévole, 05 référent), email + rôle + bouton Déconnexion. - Mobile bénévole : cible le bénévole du compte connecté ; dégradation propre quand l'API refuse le détail des créneaux à un bénévole. - Mobile référent : cible le poste dont le compte est référent. - i18n : clés auth / rôles. - Vérifs : build tsc + vite, eslint (0 problème), npm run smoke (flux login / lien magique + rendu des 6 écrans par rôle et des pages publiques). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AwswqSChc3Rwtu61pRXiY2
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
464635656a
commit
6e16db4b7e
@@ -2,21 +2,30 @@ import type {
|
||||
AssignmentCreate,
|
||||
AssignmentUpdate,
|
||||
AssignmentValidateRequest,
|
||||
LoginRequest,
|
||||
MagicLinkRequest,
|
||||
PositionCreate,
|
||||
PositionUpdate,
|
||||
ShiftCreate,
|
||||
ShiftUpdate,
|
||||
VerifyRequest,
|
||||
VolunteerCreate,
|
||||
VolunteerUpdate,
|
||||
} from './schema';
|
||||
import { getAuthToken, notifyUnauthorized } from './session';
|
||||
import { ApiError, type PlanningApi } from './types';
|
||||
|
||||
// Implémentation HTTP réelle. En dev, Vite proxifie `/api` vers le back-end.
|
||||
export function createHttpApi(baseUrl: string): PlanningApi {
|
||||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const token = getAuthToken();
|
||||
const res = await fetch(`${baseUrl}${path}`, {
|
||||
...init,
|
||||
headers: { 'Content-Type': 'application/json', ...init?.headers },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
...init?.headers,
|
||||
},
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
@@ -38,6 +47,7 @@ export function createHttpApi(baseUrl: string): PlanningApi {
|
||||
detail && typeof detail === 'object' && 'violations' in detail
|
||||
? ((detail as { violations: [] }).violations ?? [])
|
||||
: [];
|
||||
if (res.status === 401 && !path.includes('/auth/')) notifyUnauthorized();
|
||||
throw new ApiError(res.status, code, violations);
|
||||
}
|
||||
return body as T;
|
||||
@@ -109,5 +119,14 @@ export function createHttpApi(baseUrl: string): PlanningApi {
|
||||
matrix: {
|
||||
get: (editionId) => request(`${base(editionId)}/matrix`),
|
||||
},
|
||||
auth: {
|
||||
login: (editionId, body: LoginRequest) =>
|
||||
request(`${base(editionId)}/auth/login`, { method: 'POST', body: JSON.stringify(body) }),
|
||||
requestMagicLink: (editionId, body: MagicLinkRequest) =>
|
||||
request(`${base(editionId)}/auth/magic-link`, { method: 'POST', body: JSON.stringify(body) }),
|
||||
verifyMagicLink: (editionId, body: VerifyRequest) =>
|
||||
request(`${base(editionId)}/auth/verify`, { method: 'POST', body: JSON.stringify(body) }),
|
||||
me: () => request(`/auth/me`),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user