diff --git a/frontend/lib/screens/auth/am_register_step4_screen.dart b/frontend/lib/screens/auth/am_register_step4_screen.dart index 6d97e45..93c0bf7 100644 --- a/frontend/lib/screens/auth/am_register_step4_screen.dart +++ b/frontend/lib/screens/auth/am_register_step4_screen.dart @@ -7,6 +7,7 @@ import 'dart:math' as math; import '../../models/am_registration_data.dart'; import '../../models/card_assets.dart'; import '../../config/display_config.dart'; +import '../../services/auth_service.dart'; import '../../widgets/hover_relief_widget.dart'; import '../../widgets/image_button.dart'; import '../../widgets/custom_navigation_button.dart'; @@ -22,6 +23,28 @@ class AmRegisterStep4Screen extends StatefulWidget { } class _AmRegisterStep4ScreenState extends State { + bool _isSubmitting = false; + + Future _submitAMRegistration(AmRegistrationData registrationData) async { + if (_isSubmitting) return; + setState(() => _isSubmitting = true); + try { + await AuthService.registerAM(registrationData); + if (!mounted) return; + _showConfirmationModal(context); + } catch (e) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(e is Exception ? e.toString().replaceFirst('Exception: ', '') : 'Erreur lors de l\'inscription'), + backgroundColor: Colors.red.shade700, + ), + ); + } finally { + if (mounted) setState(() => _isSubmitting = false); + } + } + @override Widget build(BuildContext context) { final registrationData = Provider.of(context); @@ -90,12 +113,9 @@ class _AmRegisterStep4ScreenState extends State { Expanded( child: HoverReliefWidget( child: CustomNavigationButton( - text: 'Soumettre', + text: _isSubmitting ? 'Envoi...' : 'Soumettre', style: NavigationButtonStyle.green, - onPressed: () { - print("Données AM finales: ${registrationData.firstName} ${registrationData.lastName}"); - _showConfirmationModal(context); - }, + onPressed: () => _submitAMRegistration(registrationData), width: double.infinity, height: 50, fontSize: 16, @@ -106,17 +126,14 @@ class _AmRegisterStep4ScreenState extends State { ), ) else - ImageButton( + ImageButton( bg: 'assets/images/bg_green.png', - text: 'Soumettre ma demande', + text: _isSubmitting ? 'Envoi...' : 'Soumettre ma demande', textColor: const Color(0xFF2D6A4F), width: 350, height: 50, fontSize: 18, - onPressed: () { - print("Données AM finales: ${registrationData.firstName} ${registrationData.lastName}"); - _showConfirmationModal(context); - }, + onPressed: () => _submitAMRegistration(registrationData), ), ], ), diff --git a/frontend/lib/services/auth_service.dart b/frontend/lib/services/auth_service.dart index 7a44678..7a27c64 100644 --- a/frontend/lib/services/auth_service.dart +++ b/frontend/lib/services/auth_service.dart @@ -1,9 +1,12 @@ import 'dart:convert'; +import 'dart:io'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import '../models/user.dart'; +import '../models/am_registration_data.dart'; import 'api/api_config.dart'; import 'api/tokenService.dart'; +import '../utils/nir_utils.dart'; class AuthService { static const String _currentUserKey = 'current_user'; @@ -133,6 +136,58 @@ class AuthService { await prefs.setString(_currentUserKey, jsonEncode(user.toJson())); } + /// Inscription AM complète (POST /auth/register/am). + /// En cas de succès (201), aucune donnée utilisateur retournée ; rediriger vers login. + static Future registerAM(AmRegistrationData data) async { + String? photoBase64; + if (data.photoPath != null && data.photoPath!.isNotEmpty && !data.photoPath!.startsWith('assets/')) { + try { + final file = File(data.photoPath!); + if (await file.exists()) { + final bytes = await file.readAsBytes(); + photoBase64 = 'data:image/jpeg;base64,${base64Encode(bytes)}'; + } + } catch (_) {} + } + + final body = { + 'email': data.email, + 'prenom': data.firstName, + 'nom': data.lastName, + 'telephone': data.phone, + 'adresse': data.streetAddress.isNotEmpty ? data.streetAddress : null, + 'code_postal': data.postalCode.isNotEmpty ? data.postalCode : null, + 'ville': data.city.isNotEmpty ? data.city : null, + if (photoBase64 != null) 'photo_base64': photoBase64, + 'consentement_photo': data.photoConsent, + 'date_naissance': data.dateOfBirth != null + ? '${data.dateOfBirth!.year}-${data.dateOfBirth!.month.toString().padLeft(2, '0')}-${data.dateOfBirth!.day.toString().padLeft(2, '0')}' + : null, + 'lieu_naissance_ville': data.birthCity.isNotEmpty ? data.birthCity : null, + 'lieu_naissance_pays': data.birthCountry.isNotEmpty ? data.birthCountry : null, + 'nir': normalizeNir(data.nir), + 'numero_agrement': data.agrementNumber, + 'capacite_accueil': data.capacity ?? 1, + 'biographie': data.presentationText.isNotEmpty ? data.presentationText : null, + 'acceptation_cgu': data.cguAccepted, + 'acceptation_privacy': data.cguAccepted, + }; + + final response = await http.post( + Uri.parse('${ApiConfig.baseUrl}${ApiConfig.registerAM}'), + headers: ApiConfig.headers, + body: jsonEncode(body), + ); + + if (response.statusCode == 200 || response.statusCode == 201) { + return; + } + + final decoded = response.body.isNotEmpty ? jsonDecode(response.body) : null; + final message = decoded is Map ? (decoded['message'] as String? ?? decoded['error'] as String?) : null; + throw Exception(message ?? 'Erreur lors de l\'inscription (${response.statusCode})'); + } + /// Rafraîchit le profil utilisateur depuis l'API static Future refreshCurrentUser() async { final token = await TokenService.getToken();