import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:go_router/go_router.dart'; import 'dart:math' as math; import 'custom_app_text_field.dart'; import 'form_field_wrapper.dart'; import 'hover_relief_widget.dart'; import 'custom_navigation_button.dart'; import '../models/card_assets.dart'; import '../config/display_config.dart'; /// Modèle de données pour le formulaire class PersonalInfoData { String firstName; String lastName; String phone; String email; String address; String postalCode; String city; PersonalInfoData({ this.firstName = '', this.lastName = '', this.phone = '', this.email = '', this.address = '', this.postalCode = '', this.city = '', }); } /// Widget générique pour les formulaires d'informations personnelles /// Supporte mode éditable et readonly, responsive mobile/desktop class PersonalInfoFormScreen extends StatefulWidget { final DisplayMode mode; // editable ou readonly final String stepText; // Ex: "Étape 1/5" final String title; // Ex: "Informations du Parent Principal" final CardColorHorizontal cardColor; final PersonalInfoData initialData; final Function(PersonalInfoData data, {bool? hasSecondPerson, bool? sameAddress}) onSubmit; final String previousRoute; // Options spécifiques pour Parent 2 final bool showSecondPersonToggle; // Afficher "Il y a un 2ème parent" final bool? initialHasSecondPerson; final bool showSameAddressCheckbox; // Afficher "Même adresse que parent 1" final bool? initialSameAddress; final PersonalInfoData? referenceAddressData; // Pour pré-remplir si "même adresse" const PersonalInfoFormScreen({ super.key, this.mode = DisplayMode.editable, required this.stepText, required this.title, required this.cardColor, required this.initialData, required this.onSubmit, required this.previousRoute, this.showSecondPersonToggle = false, this.initialHasSecondPerson, this.showSameAddressCheckbox = false, this.initialSameAddress, this.referenceAddressData, }); @override State createState() => _PersonalInfoFormScreenState(); } class _PersonalInfoFormScreenState extends State { final _formKey = GlobalKey(); late TextEditingController _lastNameController; late TextEditingController _firstNameController; late TextEditingController _phoneController; late TextEditingController _emailController; late TextEditingController _addressController; late TextEditingController _postalCodeController; late TextEditingController _cityController; bool _hasSecondPerson = false; bool _sameAddress = false; bool _fieldsEnabled = true; @override void initState() { super.initState(); _lastNameController = TextEditingController(text: widget.initialData.lastName); _firstNameController = TextEditingController(text: widget.initialData.firstName); _phoneController = TextEditingController(text: widget.initialData.phone); _emailController = TextEditingController(text: widget.initialData.email); _addressController = TextEditingController(text: widget.initialData.address); _postalCodeController = TextEditingController(text: widget.initialData.postalCode); _cityController = TextEditingController(text: widget.initialData.city); if (widget.showSecondPersonToggle) { _hasSecondPerson = widget.initialHasSecondPerson ?? true; _fieldsEnabled = _hasSecondPerson; } if (widget.showSameAddressCheckbox) { _sameAddress = widget.initialSameAddress ?? false; _updateAddressFields(); } } @override void dispose() { _lastNameController.dispose(); _firstNameController.dispose(); _phoneController.dispose(); _emailController.dispose(); _addressController.dispose(); _postalCodeController.dispose(); _cityController.dispose(); super.dispose(); } void _updateAddressFields() { if (_sameAddress && widget.referenceAddressData != null) { _addressController.text = widget.referenceAddressData!.address; _postalCodeController.text = widget.referenceAddressData!.postalCode; _cityController.text = widget.referenceAddressData!.city; } } void _handleSubmit() { if (widget.mode == DisplayMode.readonly || _formKey.currentState!.validate()) { final data = PersonalInfoData( firstName: _firstNameController.text, lastName: _lastNameController.text, phone: _phoneController.text, email: _emailController.text, address: _addressController.text, postalCode: _postalCodeController.text, city: _cityController.text, ); widget.onSubmit( data, hasSecondPerson: widget.showSecondPersonToggle ? _hasSecondPerson : null, sameAddress: widget.showSameAddressCheckbox ? _sameAddress : null, ); } } @override Widget build(BuildContext context) { final screenSize = MediaQuery.of(context).size; final config = DisplayConfig.fromContext(context, mode: widget.mode); return Scaffold( body: Stack( children: [ Positioned.fill( child: Image.asset('assets/images/paper2.png', fit: BoxFit.cover, repeat: ImageRepeat.repeat), ), Center( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(vertical: 40.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( widget.stepText, style: GoogleFonts.merienda( fontSize: config.isMobile ? 13 : 16, color: Colors.black54, ), ), SizedBox(height: config.isMobile ? 6 : 10), Text( widget.title, style: GoogleFonts.merienda( fontSize: config.isMobile ? 18 : 24, fontWeight: FontWeight.bold, color: Colors.black87, ), textAlign: TextAlign.center, ), SizedBox(height: config.isMobile ? 16 : 30), Container( width: config.isMobile ? screenSize.width * 0.9 : screenSize.width * 0.6, padding: EdgeInsets.symmetric( vertical: config.isMobile ? 20 : 50, horizontal: config.isMobile ? 24 : 50, ), decoration: BoxDecoration( image: DecorationImage( image: AssetImage( config.isMobile ? _getVerticalCardAsset() : widget.cardColor.path ), fit: BoxFit.fill, ), ), child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ // Toggles "Ajouter Parent 2" et "Même Adresse" (uniquement en mode éditable) if (config.isEditable && widget.showSecondPersonToggle) _buildToggles(context, config), // Champs du formulaire _buildFormFields(context, config), ], ), ), ), // Boutons mobile sous la carte (dans le scroll) if (config.isMobile) ...[ const SizedBox(height: 20), Padding( padding: EdgeInsets.symmetric( horizontal: screenSize.width * 0.05, // Même marge que la carte (0.9 = 0.05 de chaque côté) ), child: Row( children: [ Expanded( child: HoverReliefWidget( child: CustomNavigationButton( text: 'Précédent', style: NavigationButtonStyle.purple, onPressed: () { if (context.canPop()) { context.pop(); } else { context.go(widget.previousRoute); } }, width: double.infinity, height: 50, fontSize: 16, ), ), ), const SizedBox(width: 16), // Écart entre les boutons Expanded( child: HoverReliefWidget( child: CustomNavigationButton( text: 'Suivant', style: NavigationButtonStyle.green, onPressed: _handleSubmit, width: double.infinity, height: 50, fontSize: 16, ), ), ), ], ), ), const SizedBox(height: 10), ], ], ), ), ), // Chevrons de navigation (desktop uniquement) if (!config.isMobile) ...[ Positioned( top: screenSize.height / 2 - 20, left: 40, child: IconButton( icon: Transform( alignment: Alignment.center, transform: Matrix4.rotationY(math.pi), child: Image.asset('assets/images/chevron_right.png', height: 40), ), onPressed: () { if (context.canPop()) { context.pop(); } else { context.go(widget.previousRoute); } }, tooltip: 'Retour', ), ), Positioned( top: screenSize.height / 2 - 20, right: 40, child: IconButton( icon: Image.asset('assets/images/chevron_right.png', height: 40), onPressed: _handleSubmit, tooltip: 'Suivant', ), ), ], ], ), ); } /// Construit les toggles (Parent 2 / Même adresse) Widget _buildToggles(BuildContext context, DisplayConfig config) { if (config.isMobile) { // Layout vertical sur mobile - toggles compacts return Column( children: [ _buildSecondPersonToggle(context, config), if (widget.showSameAddressCheckbox) ...[ const SizedBox(height: 12), _buildSameAddressToggle(context, config), ], const SizedBox(height: 24), ], ); } else { // Layout horizontal sur desktop return Column( children: [ Row( children: [ Expanded( flex: 12, child: _buildSecondPersonToggle(context, config), ), const Expanded(flex: 1, child: SizedBox()), if (widget.showSameAddressCheckbox) Expanded( flex: 12, child: _buildSameAddressToggle(context, config), ), ], ), const SizedBox(height: 32), ], ); } } Widget _buildSecondPersonToggle(BuildContext context, DisplayConfig config) { return Row( children: [ Icon(Icons.person_add_alt_1, size: config.isMobile ? 18 : 20), SizedBox(width: config.isMobile ? 6 : 8), Expanded( child: Text( 'Ajouter Parent 2 ?', style: GoogleFonts.merienda( fontWeight: FontWeight.bold, fontSize: config.isMobile ? 14 : 16, ), overflow: TextOverflow.ellipsis, ), ), Transform.scale( scale: config.isMobile ? 0.85 : 1.0, child: Switch( value: _hasSecondPerson, onChanged: (value) { setState(() { _hasSecondPerson = value; _fieldsEnabled = value; }); }, activeColor: Theme.of(context).primaryColor, ), ), ], ); } Widget _buildSameAddressToggle(BuildContext context, DisplayConfig config) { return Row( children: [ Icon( Icons.home_work_outlined, size: config.isMobile ? 18 : 20, color: _fieldsEnabled ? null : Colors.grey, ), SizedBox(width: config.isMobile ? 6 : 8), Expanded( child: Text( 'Même Adresse ?', style: GoogleFonts.merienda( color: _fieldsEnabled ? null : Colors.grey, fontSize: config.isMobile ? 14 : 16, ), overflow: TextOverflow.ellipsis, ), ), Transform.scale( scale: config.isMobile ? 0.85 : 1.0, child: Switch( value: _sameAddress, onChanged: _fieldsEnabled ? (value) { setState(() { _sameAddress = value ?? false; _updateAddressFields(); }); } : null, activeColor: Theme.of(context).primaryColor, ), ), ], ); } /// Construit les champs du formulaire avec la nouvelle infrastructure Widget _buildFormFields(BuildContext context, DisplayConfig config) { if (config.isMobile) { return _buildMobileFields(context, config); } else { return _buildDesktopFields(context, config); } } /// Layout DESKTOP : champs côte à côte (horizontal) Widget _buildDesktopFields(BuildContext context, DisplayConfig config) { return Column( children: [ // Nom et Prénom Row( children: [ Expanded( child: _buildField( config: config, label: 'Nom', controller: _lastNameController, hint: 'Votre nom de famille', enabled: _fieldsEnabled, ), ), const SizedBox(width: 20), Expanded( child: _buildField( config: config, label: 'Prénom', controller: _firstNameController, hint: 'Votre prénom', enabled: _fieldsEnabled, ), ), ], ), const SizedBox(height: 32), // Téléphone et Email Row( children: [ Expanded( child: _buildField( config: config, label: 'Téléphone', controller: _phoneController, hint: 'Votre numéro de téléphone', keyboardType: TextInputType.phone, enabled: _fieldsEnabled, ), ), const SizedBox(width: 20), Expanded( child: _buildField( config: config, label: 'Email', controller: _emailController, hint: 'Votre adresse e-mail', keyboardType: TextInputType.emailAddress, enabled: _fieldsEnabled, ), ), ], ), const SizedBox(height: 32), // Adresse _buildField( config: config, label: 'Adresse (N° et Rue)', controller: _addressController, hint: 'Numéro et nom de votre rue', enabled: _fieldsEnabled && !_sameAddress, ), const SizedBox(height: 32), // Code Postal et Ville Row( children: [ Expanded( flex: 2, child: _buildField( config: config, label: 'Code Postal', controller: _postalCodeController, hint: 'Code postal', keyboardType: TextInputType.number, enabled: _fieldsEnabled && !_sameAddress, ), ), const SizedBox(width: 20), Expanded( flex: 5, child: _buildField( config: config, label: 'Ville', controller: _cityController, hint: 'Votre ville', enabled: _fieldsEnabled && !_sameAddress, ), ), ], ), ], ); } /// Layout MOBILE : tous les champs empilés verticalement Widget _buildMobileFields(BuildContext context, DisplayConfig config) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Nom _buildField( config: config, label: 'Nom', controller: _lastNameController, hint: 'Votre nom de famille', enabled: _fieldsEnabled, ), const SizedBox(height: 12), // Prénom _buildField( config: config, label: 'Prénom', controller: _firstNameController, hint: 'Votre prénom', enabled: _fieldsEnabled, ), const SizedBox(height: 12), // Téléphone _buildField( config: config, label: 'Téléphone', controller: _phoneController, hint: 'Votre numéro de téléphone', keyboardType: TextInputType.phone, enabled: _fieldsEnabled, ), const SizedBox(height: 12), // Email _buildField( config: config, label: 'Email', controller: _emailController, hint: 'Votre adresse e-mail', keyboardType: TextInputType.emailAddress, enabled: _fieldsEnabled, ), const SizedBox(height: 12), // Adresse _buildField( config: config, label: 'Adresse (N° et Rue)', controller: _addressController, hint: 'Numéro et nom de votre rue', enabled: _fieldsEnabled && !_sameAddress, ), const SizedBox(height: 12), // Code Postal _buildField( config: config, label: 'Code Postal', controller: _postalCodeController, hint: 'Code postal', keyboardType: TextInputType.number, enabled: _fieldsEnabled && !_sameAddress, ), const SizedBox(height: 12), // Ville _buildField( config: config, label: 'Ville', controller: _cityController, hint: 'Votre ville', enabled: _fieldsEnabled && !_sameAddress, ), ], ); } /// Construit un champ individuel (éditable ou readonly) Widget _buildField({ required DisplayConfig config, required String label, required TextEditingController controller, String? hint, TextInputType? keyboardType, bool enabled = true, }) { if (config.isReadonly) { // Mode readonly : utiliser FormFieldWrapper return FormFieldWrapper( config: config, label: label, value: controller.text, ); } else { // Mode éditable : style adapté mobile/desktop return CustomAppTextField( controller: controller, labelText: label, hintText: hint ?? label, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, fieldHeight: config.isMobile ? 45.0 : 53.0, labelFontSize: config.isMobile ? 15.0 : 22.0, inputFontSize: config.isMobile ? 14.0 : 20.0, keyboardType: keyboardType ?? TextInputType.text, enabled: enabled, ); } } /// Retourne l'asset de carte vertical correspondant à la couleur String _getVerticalCardAsset() { switch (widget.cardColor) { case CardColorHorizontal.blue: return CardColorVertical.blue.path; case CardColorHorizontal.green: return CardColorVertical.green.path; case CardColorHorizontal.lavender: return CardColorVertical.lavender.path; case CardColorHorizontal.lime: return CardColorVertical.lime.path; case CardColorHorizontal.peach: return CardColorVertical.peach.path; case CardColorHorizontal.pink: return CardColorVertical.pink.path; case CardColorHorizontal.red: return CardColorVertical.red.path; } } }