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 '../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: 16, color: Colors.black54)), const SizedBox(height: 10), Text( widget.title, style: GoogleFonts.merienda( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black87, ), textAlign: TextAlign.center, ), const SizedBox(height: 30), Container( width: config.isMobile ? screenSize.width * 0.9 : screenSize.width * 0.6, padding: EdgeInsets.symmetric( vertical: config.isMobile ? 30 : 50, horizontal: config.isMobile ? 20 : 50, ), constraints: BoxConstraints(minHeight: config.isMobile ? 400 : 570), 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), ], ), ), ), ], ), ), ), // Chevrons de navigation 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', ), ), ], // Boutons mobile en bas if (config.isMobile) Positioned( bottom: 20, left: 20, right: 20, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( onPressed: () { if (context.canPop()) { context.pop(); } else { context.go(widget.previousRoute); } }, child: const Text('Précédent'), ), ElevatedButton( onPressed: _handleSubmit, child: const Text('Suivant'), ), ], ), ), ], ), ); } /// Construit les toggles (Parent 2 / Même adresse) Widget _buildToggles(BuildContext context, DisplayConfig config) { if (config.isMobile) { // Layout vertical sur mobile return Column( children: [ _buildSecondPersonToggle(context), if (widget.showSameAddressCheckbox) ...[ const SizedBox(height: 16), _buildSameAddressToggle(context), ], const SizedBox(height: 32), ], ); } else { // Layout horizontal sur desktop return Column( children: [ Row( children: [ Expanded( flex: 12, child: _buildSecondPersonToggle(context), ), const Expanded(flex: 1, child: SizedBox()), if (widget.showSameAddressCheckbox) Expanded( flex: 12, child: _buildSameAddressToggle(context), ), ], ), const SizedBox(height: 32), ], ); } } Widget _buildSecondPersonToggle(BuildContext context) { return Row( children: [ const Icon(Icons.person_add_alt_1, size: 20), const SizedBox(width: 8), Flexible( child: Text( 'Ajouter Parent 2 ?', style: GoogleFonts.merienda(fontWeight: FontWeight.bold), overflow: TextOverflow.ellipsis, ), ), const Spacer(), Switch( value: _hasSecondPerson, onChanged: (value) { setState(() { _hasSecondPerson = value; _fieldsEnabled = value; }); }, activeColor: Theme.of(context).primaryColor, ), ], ); } Widget _buildSameAddressToggle(BuildContext context) { return Row( children: [ Icon( Icons.home_work_outlined, size: 20, color: _fieldsEnabled ? null : Colors.grey, ), const SizedBox(width: 8), Flexible( child: Text( 'Même Adresse ?', style: GoogleFonts.merienda( color: _fieldsEnabled ? null : Colors.grey, ), overflow: TextOverflow.ellipsis, ), ), const Spacer(), 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) { return Column( children: [ // Nom et Prénom FormFieldRow( config: config, fields: [ _buildField( config: config, label: 'Nom', controller: _lastNameController, hint: 'Votre nom de famille', enabled: _fieldsEnabled, ), _buildField( config: config, label: 'Prénom', controller: _firstNameController, hint: 'Votre prénom', enabled: _fieldsEnabled, ), ], ), SizedBox(height: config.isMobile ? 16 : 32), // Téléphone et Email FormFieldRow( config: config, fields: [ _buildField( config: config, label: 'Téléphone', controller: _phoneController, hint: 'Votre numéro de téléphone', keyboardType: TextInputType.phone, enabled: _fieldsEnabled, ), _buildField( config: config, label: 'Email', controller: _emailController, hint: 'Votre adresse e-mail', keyboardType: TextInputType.emailAddress, enabled: _fieldsEnabled, ), ], ), SizedBox(height: config.isMobile ? 16 : 32), // Adresse _buildField( config: config, label: 'Adresse (N° et Rue)', controller: _addressController, hint: 'Numéro et nom de votre rue', enabled: _fieldsEnabled && !_sameAddress, ), SizedBox(height: config.isMobile ? 16 : 32), // Code Postal et Ville FormFieldRow( config: config, fields: [ Flexible( flex: 1, child: _buildField( config: config, label: 'Code Postal', controller: _postalCodeController, hint: 'Code postal', keyboardType: TextInputType.number, enabled: _fieldsEnabled && !_sameAddress, ), ), Flexible( flex: 4, child: _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 : utiliser CustomAppTextField existant pour garder le style return CustomAppTextField( controller: controller, labelText: label, hintText: hint ?? label, style: CustomAppTextFieldStyle.beige, fieldWidth: double.infinity, labelFontSize: config.isMobile ? 18.0 : 22.0, inputFontSize: config.isMobile ? 16.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; } } }