import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import 'dart:math' as math; import 'dart:io'; import '../models/card_assets.dart'; import 'custom_app_text_field.dart'; import 'app_custom_checkbox.dart'; import 'hover_relief_widget.dart'; /// Données pour le formulaire d'informations professionnelles class ProfessionalInfoData { final String? photoPath; final File? photoFile; final bool photoConsent; final DateTime? dateOfBirth; final String birthCity; final String birthCountry; final String nir; final String agrementNumber; final int? capacity; ProfessionalInfoData({ this.photoPath, this.photoFile, this.photoConsent = false, this.dateOfBirth, this.birthCity = '', this.birthCountry = '', this.nir = '', this.agrementNumber = '', this.capacity, }); } /// Widget générique pour le formulaire d'informations professionnelles /// Utilisé pour l'inscription des Assistantes Maternelles class ProfessionalInfoFormScreen extends StatefulWidget { final String stepText; final String title; final CardColorHorizontal cardColor; final ProfessionalInfoData? initialData; final String previousRoute; final Function(ProfessionalInfoData) onSubmit; final Future Function()? onPickPhoto; const ProfessionalInfoFormScreen({ super.key, required this.stepText, required this.title, required this.cardColor, this.initialData, required this.previousRoute, required this.onSubmit, this.onPickPhoto, }); @override State createState() => _ProfessionalInfoFormScreenState(); } class _ProfessionalInfoFormScreenState extends State { final _formKey = GlobalKey(); final _dateOfBirthController = TextEditingController(); final _birthCityController = TextEditingController(); final _birthCountryController = TextEditingController(); final _nirController = TextEditingController(); final _agrementController = TextEditingController(); final _capacityController = TextEditingController(); DateTime? _selectedDate; String? _photoPathFramework; File? _photoFile; bool _photoConsent = false; @override void initState() { super.initState(); final data = widget.initialData; if (data != null) { _selectedDate = data.dateOfBirth; _dateOfBirthController.text = data.dateOfBirth != null ? DateFormat('dd/MM/yyyy').format(data.dateOfBirth!) : ''; _birthCityController.text = data.birthCity; _birthCountryController.text = data.birthCountry; _nirController.text = data.nir; _agrementController.text = data.agrementNumber; _capacityController.text = data.capacity?.toString() ?? ''; _photoPathFramework = data.photoPath; _photoFile = data.photoFile; _photoConsent = data.photoConsent; } } @override void dispose() { _dateOfBirthController.dispose(); _birthCityController.dispose(); _birthCountryController.dispose(); _nirController.dispose(); _agrementController.dispose(); _capacityController.dispose(); super.dispose(); } Future _selectDate(BuildContext context) async { final DateTime? picked = await showDatePicker( context: context, initialDate: _selectedDate ?? DateTime.now().subtract(const Duration(days: 365 * 25)), firstDate: DateTime(1920, 1), lastDate: DateTime.now().subtract(const Duration(days: 365 * 18)), locale: const Locale('fr', 'FR'), ); if (picked != null && picked != _selectedDate) { setState(() { _selectedDate = picked; _dateOfBirthController.text = DateFormat('dd/MM/yyyy').format(picked); }); } } Future _pickPhoto() async { if (widget.onPickPhoto != null) { await widget.onPickPhoto!(); } else { // Comportement par défaut : utiliser un asset de test setState(() { _photoPathFramework = 'assets/images/icon_assmat.png'; _photoFile = null; }); } } void _submitForm() { if (_formKey.currentState!.validate()) { if (_photoPathFramework != null && !_photoConsent) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Veuillez accepter le consentement photo pour continuer.')), ); return; } final data = ProfessionalInfoData( photoPath: _photoPathFramework, photoFile: _photoFile, photoConsent: _photoConsent, dateOfBirth: _selectedDate, birthCity: _birthCityController.text, birthCountry: _birthCountryController.text, nir: _nirController.text, agrementNumber: _agrementController.text, capacity: int.tryParse(_capacityController.text), ); widget.onSubmit(data); } } @override Widget build(BuildContext context) { final screenSize = MediaQuery.of(context).size; final Color baseCardColorForShadow = Colors.green.shade300; final Color initialPhotoShadow = baseCardColorForShadow.withAlpha(90); final Color hoverPhotoShadow = baseCardColorForShadow.withAlpha(130); ImageProvider? currentImageProvider; if (_photoFile != null) { currentImageProvider = FileImage(_photoFile!); } else if (_photoPathFramework != null && _photoPathFramework!.startsWith('assets/')) { currentImageProvider = AssetImage(_photoPathFramework!); } 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: screenSize.width * 0.6, padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 50), constraints: const BoxConstraints(minHeight: 650), decoration: BoxDecoration( image: DecorationImage(image: AssetImage(widget.cardColor.path), fit: BoxFit.fill), ), child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Colonne Gauche: Photo et Checkbox SizedBox( width: 300, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ HoverReliefWidget( onPressed: _pickPhoto, borderRadius: BorderRadius.circular(10.0), initialShadowColor: initialPhotoShadow, hoverShadowColor: hoverPhotoShadow, child: SizedBox( height: 270, width: 270, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), image: currentImageProvider != null ? DecorationImage(image: currentImageProvider, fit: BoxFit.cover) : null, ), child: currentImageProvider == null ? Image.asset('assets/images/photo.png', fit: BoxFit.contain) : null, ), ), ), const SizedBox(height: 10), AppCustomCheckbox( label: 'J\'accepte l\'utilisation\nde ma photo.', value: _photoConsent, onChanged: (val) => setState(() => _photoConsent = val ?? false), ), ], ), ), const SizedBox(width: 30), // Colonne Droite: Champs de naissance Expanded( child: Column( children: [ CustomAppTextField( controller: _birthCityController, labelText: 'Ville de naissance', hintText: 'Votre ville de naissance', fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0, validator: (v) => v!.isEmpty ? 'Ville requise' : null, ), const SizedBox(height: 32), CustomAppTextField( controller: _birthCountryController, labelText: 'Pays de naissance', hintText: 'Votre pays de naissance', fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0, validator: (v) => v!.isEmpty ? 'Pays requis' : null, ), const SizedBox(height: 32), CustomAppTextField( controller: _dateOfBirthController, labelText: 'Date de naissance', hintText: 'JJ/MM/AAAA', readOnly: true, onTap: () => _selectDate(context), suffixIcon: Icons.calendar_today, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0, validator: (v) => _selectedDate == null ? 'Date requise' : null, ), ], ), ), ], ), const SizedBox(height: 32), CustomAppTextField( controller: _nirController, labelText: 'N° Sécurité Sociale (NIR)', hintText: 'Votre NIR à 13 chiffres', keyboardType: TextInputType.number, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0, validator: (v) { if (v == null || v.isEmpty) return 'NIR requis'; if (v.length != 13) return 'Le NIR doit contenir 13 chiffres'; if (!RegExp(r'^[1-3]').hasMatch(v[0])) return 'Le NIR doit commencer par 1, 2 ou 3'; return null; }, ), const SizedBox(height: 32), Row( children: [ Expanded( child: CustomAppTextField( controller: _agrementController, labelText: 'N° d\'agrément', hintText: 'Votre numéro d\'agrément', fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0, validator: (v) => v!.isEmpty ? 'Agrément requis' : null, ), ), const SizedBox(width: 20), Expanded( child: CustomAppTextField( controller: _capacityController, labelText: 'Capacité d\'accueil', hintText: 'Ex: 3', keyboardType: TextInputType.number, fieldWidth: double.infinity, labelFontSize: 22.0, inputFontSize: 20.0, validator: (v) { if (v == null || v.isEmpty) return 'Capacité requise'; final n = int.tryParse(v); if (n == null || n <= 0) return 'Nombre invalide'; return null; }, ), ), ], ), ], ), ), ), ], ), ), ), // Chevron Gauche (Retour) 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: 'Précédent', ), ), // Chevron Droit (Suivant) Positioned( top: screenSize.height / 2 - 20, right: 40, child: IconButton( icon: Image.asset('assets/images/chevron_right.png', height: 40), onPressed: _submitForm, tooltip: 'Suivant', ), ), ], ), ); } }