feat(front): implémenter la page create-password du ticket #118

Ajoute le flux frontend de création initiale du mot de passe via token email (route /create-password, vérification de token et soumission /auth/create-password), avec redirection login en succès et gestion neutre des liens invalides/expirés.

Made-with: Cursor
This commit is contained in:
2026-04-23 11:58:10 +02:00
parent 3716dfe611
commit 29623f33b9
5 changed files with 309 additions and 2 deletions
@@ -44,6 +44,8 @@ class ApiConfig {
static const String refreshToken = '/auth/refresh';
static const String authMe = '/auth/me';
static const String changePasswordRequired = '/auth/change-password-required';
static const String verifyCreatePasswordToken = '/auth/verify-token';
static const String createPassword = '/auth/create-password';
// Users endpoints
static const String users = '/users';
+55
View File
@@ -131,6 +131,61 @@ class AuthService {
}
}
/// Vérifie qu'un token de création de mot de passe est encore valide.
/// Retourne `true` si l'API renvoie 200 ; `false` si 404.
static Future<bool> verifyCreatePasswordToken(String token) async {
final cleaned = token.trim();
if (cleaned.isEmpty) return false;
try {
final uri = Uri.parse(
'${ApiConfig.baseUrl}${ApiConfig.verifyCreatePasswordToken}?token=${Uri.encodeQueryComponent(cleaned)}',
);
final response = await http.get(uri, headers: ApiConfig.headers);
if (response.statusCode == 200) return true;
if (response.statusCode == 404) return false;
final decoded = _tryDecodeJsonMap(response.body);
throw Exception(_extractErrorMessage(decoded, response.statusCode));
} on http.ClientException {
throw Exception(
'Connexion à ${ApiConfig.baseUrl} impossible. Vérifiez votre réseau puis réessayez.',
);
}
}
/// Crée le mot de passe initial via token email.
static Future<void> createPasswordWithToken({
required String token,
required String password,
required String passwordConfirmation,
}) async {
final cleaned = token.trim();
if (cleaned.isEmpty) {
throw Exception('Lien invalide ou expiré.');
}
late final http.Response response;
try {
response = await http.post(
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.createPassword}'),
headers: ApiConfig.headers,
body: jsonEncode({
'token': cleaned,
'password': password,
'password_confirmation': passwordConfirmation,
}),
);
} on http.ClientException {
throw Exception(
'Connexion à ${ApiConfig.baseUrl} impossible. Vérifiez votre réseau puis réessayez.',
);
}
if (response.statusCode == 200 || response.statusCode == 201) {
return;
}
final decoded = _tryDecodeJsonMap(response.body);
throw Exception(_extractErrorMessage(decoded, response.statusCode));
}
/// Déconnexion de l'utilisateur
static Future<void> logout() async {
await TokenService.clearAll();