feat(frontend): Refonte infrastructure formulaires multi-modes
- Support des modes Desktop/Mobile et Édition/Lecture seule - Refactoring des widgets de formulaire (PersonalInfo, ProfessionalInfo, Presentation, ChildCard) - Mise à jour des écrans de récapitulatif (ParentStep5, AmStep4) - Ajout de navigation (Précédent/Soumettre) sur mobile Closes #78 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,41 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../models/am_registration_data.dart';
|
||||
import '../../widgets/image_button.dart';
|
||||
import '../../models/card_assets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
// Méthode helper pour afficher un champ de type "lecture seule" stylisé
|
||||
Widget _buildDisplayFieldValue(BuildContext context, String label, String value, {bool multiLine = false, double fieldHeight = 50.0, double labelFontSize = 18.0}) {
|
||||
const FontWeight labelFontWeight = FontWeight.w600;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: GoogleFonts.merienda(fontSize: labelFontSize, fontWeight: labelFontWeight)),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: multiLine ? null : fieldHeight,
|
||||
constraints: multiLine ? const BoxConstraints(minHeight: 50.0) : null,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 12.0),
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/input_field_bg.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
value.isNotEmpty ? value : '-',
|
||||
style: GoogleFonts.merienda(fontSize: labelFontSize),
|
||||
maxLines: multiLine ? null : 1,
|
||||
overflow: multiLine ? TextOverflow.visible : TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
import '../../models/am_registration_data.dart';
|
||||
import '../../models/card_assets.dart';
|
||||
import '../../config/display_config.dart';
|
||||
import '../../widgets/hover_relief_widget.dart';
|
||||
import '../../widgets/image_button.dart';
|
||||
import '../../widgets/custom_navigation_button.dart';
|
||||
import '../../widgets/personal_info_form_screen.dart';
|
||||
import '../../widgets/professional_info_form_screen.dart';
|
||||
import '../../widgets/presentation_form_screen.dart';
|
||||
|
||||
class AmRegisterStep4Screen extends StatefulWidget {
|
||||
const AmRegisterStep4Screen({super.key});
|
||||
@@ -49,6 +26,7 @@ class _AmRegisterStep4ScreenState extends State<AmRegisterStep4Screen> {
|
||||
Widget build(BuildContext context) {
|
||||
final registrationData = Provider.of<AmRegistrationData>(context);
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final config = DisplayConfig.fromContext(context, mode: DisplayMode.readonly);
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
@@ -60,7 +38,9 @@ class _AmRegisterStep4ScreenState extends State<AmRegisterStep4Screen> {
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width / 4.0),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: config.isMobile ? 0 : screenSize.width / 4.0
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
@@ -70,50 +50,167 @@ class _AmRegisterStep4ScreenState extends State<AmRegisterStep4Screen> {
|
||||
Text('Récapitulatif de votre demande', style: GoogleFonts.merienda(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black87), textAlign: TextAlign.center),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
_buildPersonalInfoCard(context, registrationData),
|
||||
const SizedBox(height: 20),
|
||||
_buildProfessionalInfoCard(context, registrationData),
|
||||
const SizedBox(height: 20),
|
||||
_buildPresentationCard(context, registrationData),
|
||||
// Carte 1: Informations personnelles
|
||||
_buildPersonalInfo(context, registrationData),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// Carte 2: Informations professionnelles
|
||||
_buildProfessionalInfo(context, registrationData),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// Carte 3: Présentation
|
||||
_buildPresentation(context, registrationData),
|
||||
const SizedBox(height: 40),
|
||||
|
||||
ImageButton(
|
||||
bg: 'assets/images/btn_green.png',
|
||||
text: '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);
|
||||
},
|
||||
),
|
||||
// Boutons Mobile (Retour + Soumettre) ou Bouton Soumettre Desktop
|
||||
if (config.isMobile)
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width * 0.05),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: HoverReliefWidget(
|
||||
child: CustomNavigationButton(
|
||||
text: 'Précédent',
|
||||
style: NavigationButtonStyle.purple,
|
||||
onPressed: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/am-register-step3');
|
||||
}
|
||||
},
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: HoverReliefWidget(
|
||||
child: CustomNavigationButton(
|
||||
text: 'Soumettre',
|
||||
style: NavigationButtonStyle.green,
|
||||
onPressed: () {
|
||||
print("Données AM finales: ${registrationData.firstName} ${registrationData.lastName}");
|
||||
_showConfirmationModal(context);
|
||||
},
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
ImageButton(
|
||||
bg: 'assets/images/bg_green.png',
|
||||
text: '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);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: screenSize.height / 2 - 20,
|
||||
left: 40,
|
||||
child: IconButton(
|
||||
icon: Transform.flip(flipX: true, child: Image.asset('assets/images/chevron_right.png', height: 40)),
|
||||
onPressed: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/am-register-step3');
|
||||
}
|
||||
},
|
||||
tooltip: 'Retour',
|
||||
// Chevrons 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('/am-register-step3');
|
||||
}
|
||||
},
|
||||
tooltip: 'Retour',
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPersonalInfo(BuildContext context, AmRegistrationData data) {
|
||||
return PersonalInfoFormScreen(
|
||||
mode: DisplayMode.readonly,
|
||||
embedContentOnly: true,
|
||||
stepText: '',
|
||||
title: 'Informations personnelles',
|
||||
cardColor: CardColorHorizontal.blue,
|
||||
initialData: PersonalInfoData(
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
phone: data.phone,
|
||||
email: data.email,
|
||||
address: data.streetAddress,
|
||||
postalCode: data.postalCode,
|
||||
city: data.city,
|
||||
),
|
||||
onSubmit: (d, {hasSecondPerson, sameAddress}) {}, // No-op en readonly
|
||||
previousRoute: '',
|
||||
onEdit: () => context.go('/am-register-step1'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProfessionalInfo(BuildContext context, AmRegistrationData data) {
|
||||
return ProfessionalInfoFormScreen(
|
||||
mode: DisplayMode.readonly,
|
||||
embedContentOnly: true,
|
||||
stepText: '',
|
||||
title: 'Informations professionnelles',
|
||||
cardColor: CardColorHorizontal.green,
|
||||
initialData: ProfessionalInfoData(
|
||||
// TODO: Gérer photoPath vs photoFile correctement
|
||||
photoPath: null, // Pas d'accès facile au fichier ici, on verra
|
||||
dateOfBirth: data.dateOfBirth,
|
||||
birthCity: data.birthCity,
|
||||
birthCountry: data.birthCountry,
|
||||
nir: data.nir,
|
||||
agrementNumber: data.agrementNumber,
|
||||
capacity: data.capacity,
|
||||
photoConsent: data.photoConsent,
|
||||
),
|
||||
onSubmit: (d) {},
|
||||
previousRoute: '',
|
||||
onEdit: () => context.go('/am-register-step2'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPresentation(BuildContext context, AmRegistrationData data) {
|
||||
return PresentationFormScreen(
|
||||
mode: DisplayMode.readonly,
|
||||
embedContentOnly: true,
|
||||
stepText: '',
|
||||
title: 'Présentation & CGU',
|
||||
cardColor: CardColorHorizontal.peach,
|
||||
textFieldHint: '',
|
||||
initialText: data.presentationText,
|
||||
initialCguAccepted: data.cguAccepted,
|
||||
previousRoute: '',
|
||||
onSubmit: (t, c) {},
|
||||
onEdit: () => context.go('/am-register-step3'),
|
||||
);
|
||||
}
|
||||
|
||||
void _showConfirmationModal(BuildContext context) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
@@ -141,199 +238,4 @@ class _AmRegisterStep4ScreenState extends State<AmRegisterStep4Screen> {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Carte Informations personnelles
|
||||
Widget _buildPersonalInfoCard(BuildContext context, AmRegistrationData data) {
|
||||
const double verticalSpacing = 28.0;
|
||||
const double labelFontSize = 22.0;
|
||||
|
||||
List<Widget> details = [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Nom:", data.lastName, labelFontSize: labelFontSize)),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Prénom:", data.firstName, labelFontSize: labelFontSize)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Téléphone:", data.phone, labelFontSize: labelFontSize)),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Email:", data.email, multiLine: true, labelFontSize: labelFontSize)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
_buildDisplayFieldValue(context, "Adresse:", "${data.streetAddress}\n${data.postalCode} ${data.city}".trim(), multiLine: true, fieldHeight: 80, labelFontSize: labelFontSize),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
_buildDisplayFieldValue(context, "Consentement photo:", data.photoConsent ? "Oui" : "Non", labelFontSize: labelFontSize),
|
||||
];
|
||||
|
||||
return _SummaryCard(
|
||||
backgroundImagePath: CardColorHorizontal.blue.path,
|
||||
title: 'Informations personnelles',
|
||||
content: details,
|
||||
onEdit: () => context.go('/am-register-step1'),
|
||||
);
|
||||
}
|
||||
|
||||
// Carte Informations professionnelles
|
||||
Widget _buildProfessionalInfoCard(BuildContext context, AmRegistrationData data) {
|
||||
const double verticalSpacing = 28.0;
|
||||
const double labelFontSize = 22.0;
|
||||
|
||||
String formattedDate = '-';
|
||||
if (data.dateOfBirth != null) {
|
||||
formattedDate = '${data.dateOfBirth!.day.toString().padLeft(2, '0')}/${data.dateOfBirth!.month.toString().padLeft(2, '0')}/${data.dateOfBirth!.year}';
|
||||
}
|
||||
String birthPlace = '${data.birthCity}, ${data.birthCountry}'.trim();
|
||||
if (birthPlace == ',') birthPlace = '-';
|
||||
|
||||
List<Widget> details = [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Date de naissance:", formattedDate, labelFontSize: labelFontSize)),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Lieu de naissance:", birthPlace, labelFontSize: labelFontSize, multiLine: true)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: _buildDisplayFieldValue(context, "N° Sécurité Sociale:", data.nir, labelFontSize: labelFontSize)),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(child: _buildDisplayFieldValue(context, "N° Agrément:", data.agrementNumber, labelFontSize: labelFontSize)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
_buildDisplayFieldValue(context, "Capacité d'accueil:", data.capacity?.toString() ?? '-', labelFontSize: labelFontSize),
|
||||
];
|
||||
|
||||
return _SummaryCard(
|
||||
backgroundImagePath: CardColorHorizontal.green.path,
|
||||
title: 'Informations professionnelles',
|
||||
content: details,
|
||||
onEdit: () => context.go('/am-register-step2'),
|
||||
);
|
||||
}
|
||||
|
||||
// Carte Présentation & CGU
|
||||
Widget _buildPresentationCard(BuildContext context, AmRegistrationData data) {
|
||||
const double labelFontSize = 22.0;
|
||||
|
||||
List<Widget> details = [
|
||||
Text(
|
||||
'Votre présentation (facultatif) :',
|
||||
style: GoogleFonts.merienda(fontSize: labelFontSize, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
constraints: const BoxConstraints(minHeight: 80.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 12.0),
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/input_field_bg.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
data.presentationText.isNotEmpty ? data.presentationText : 'Aucune présentation rédigée.',
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: 18,
|
||||
fontStyle: data.presentationText.isNotEmpty ? FontStyle.normal : FontStyle.italic,
|
||||
color: data.presentationText.isNotEmpty ? Colors.black87 : Colors.black54,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
data.cguAccepted ? Icons.check_circle : Icons.cancel,
|
||||
color: data.cguAccepted ? Colors.green : Colors.red,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
data.cguAccepted ? 'CGU acceptées' : 'CGU non acceptées',
|
||||
style: GoogleFonts.merienda(fontSize: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
return _SummaryCard(
|
||||
backgroundImagePath: CardColorHorizontal.peach.path,
|
||||
title: 'Présentation & CGU',
|
||||
content: details,
|
||||
onEdit: () => context.go('/am-register-step3'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Widget générique _SummaryCard
|
||||
class _SummaryCard extends StatelessWidget {
|
||||
final String backgroundImagePath;
|
||||
final String title;
|
||||
final List<Widget> content;
|
||||
final VoidCallback onEdit;
|
||||
|
||||
const _SummaryCard({
|
||||
super.key,
|
||||
required this.backgroundImagePath,
|
||||
required this.title,
|
||||
required this.content,
|
||||
required this.onEdit,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AspectRatio(
|
||||
aspectRatio: 2.0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 25.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(backgroundImagePath),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
title,
|
||||
style: GoogleFonts.merienda(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black87),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
...content,
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 28),
|
||||
onPressed: onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:p_tits_pas/services/bug_report_service.dart';
|
||||
import '../../widgets/image_button.dart';
|
||||
import '../../widgets/custom_app_text_field.dart';
|
||||
@@ -241,7 +242,7 @@ class _LoginPageState extends State<LoginScreen> {
|
||||
child: _isLoading
|
||||
? const CircularProgressIndicator()
|
||||
: ImageButton(
|
||||
bg: 'assets/images/btn_green.png',
|
||||
bg: 'assets/images/bg_green.png',
|
||||
width: 300,
|
||||
height: 40,
|
||||
text: 'Se connecter',
|
||||
|
||||
@@ -5,9 +5,11 @@ import 'package:image_picker/image_picker.dart';
|
||||
import 'dart:io' show File;
|
||||
import '../../widgets/hover_relief_widget.dart';
|
||||
import '../../widgets/child_card_widget.dart';
|
||||
import '../../widgets/custom_navigation_button.dart';
|
||||
import '../../models/user_registration_data.dart';
|
||||
import '../../utils/data_generator.dart';
|
||||
import '../../models/card_assets.dart';
|
||||
import '../../config/display_config.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@@ -204,14 +206,157 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
|
||||
Widget build(BuildContext context) {
|
||||
final registrationData = Provider.of<UserRegistrationData>(context /*, listen: true par défaut */);
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final config = DisplayConfig.fromContext(context, mode: DisplayMode.editable);
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Image.asset('assets/images/paper2.png', fit: BoxFit.cover, repeat: ImageRepeat.repeat),
|
||||
),
|
||||
Center(
|
||||
config.isMobile
|
||||
? _buildMobileLayout(context, config, screenSize, registrationData)
|
||||
: _buildDesktopLayout(context, config, screenSize, registrationData),
|
||||
// Chevrons 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('/parent-register-step2');
|
||||
}
|
||||
},
|
||||
tooltip: 'Retour',
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: screenSize.height / 2 - 20,
|
||||
right: 40,
|
||||
child: IconButton(
|
||||
icon: Image.asset('assets/images/chevron_right.png', height: 40),
|
||||
onPressed: () {
|
||||
context.go('/parent-register-step4');
|
||||
},
|
||||
tooltip: 'Suivant',
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Layout MOBILE : Cartes empilées verticalement
|
||||
Widget _buildMobileLayout(BuildContext context, DisplayConfig config, Size screenSize, UserRegistrationData registrationData) {
|
||||
return Column(
|
||||
children: [
|
||||
// Header fixe
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'Étape 3/5',
|
||||
style: GoogleFonts.merienda(fontSize: 13, color: Colors.black54),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
'Informations Enfants',
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Liste scrollable des cartes + boutons
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width * 0.05),
|
||||
child: Column(
|
||||
children: [
|
||||
// Générer les cartes enfants
|
||||
for (int index = 0; index < registrationData.children.length; index++) ...[
|
||||
ChildCardWidget(
|
||||
key: ValueKey(registrationData.children[index].hashCode),
|
||||
childData: registrationData.children[index],
|
||||
childIndex: index,
|
||||
onPickImage: () => _pickImage(index, registrationData),
|
||||
onDateSelect: () => _selectDate(context, index, registrationData),
|
||||
onFirstNameChanged: (value) => setState(() => registrationData.updateChild(index, ChildData(
|
||||
firstName: value, lastName: registrationData.children[index].lastName, dob: registrationData.children[index].dob, photoConsent: registrationData.children[index].photoConsent,
|
||||
multipleBirth: registrationData.children[index].multipleBirth, isUnbornChild: registrationData.children[index].isUnbornChild, imageFile: registrationData.children[index].imageFile, cardColor: registrationData.children[index].cardColor
|
||||
))),
|
||||
onLastNameChanged: (value) => setState(() => registrationData.updateChild(index, ChildData(
|
||||
firstName: registrationData.children[index].firstName, lastName: value, dob: registrationData.children[index].dob, photoConsent: registrationData.children[index].photoConsent,
|
||||
multipleBirth: registrationData.children[index].multipleBirth, isUnbornChild: registrationData.children[index].isUnbornChild, imageFile: registrationData.children[index].imageFile, cardColor: registrationData.children[index].cardColor
|
||||
))),
|
||||
onTogglePhotoConsent: (newValue) {
|
||||
final oldChild = registrationData.children[index];
|
||||
registrationData.updateChild(index, ChildData(
|
||||
firstName: oldChild.firstName, lastName: oldChild.lastName, dob: oldChild.dob, photoConsent: newValue,
|
||||
multipleBirth: oldChild.multipleBirth, isUnbornChild: oldChild.isUnbornChild, imageFile: oldChild.imageFile, cardColor: oldChild.cardColor
|
||||
));
|
||||
},
|
||||
onToggleMultipleBirth: (newValue) {
|
||||
final oldChild = registrationData.children[index];
|
||||
registrationData.updateChild(index, ChildData(
|
||||
firstName: oldChild.firstName, lastName: oldChild.lastName, dob: oldChild.dob, photoConsent: oldChild.photoConsent,
|
||||
multipleBirth: newValue, isUnbornChild: oldChild.isUnbornChild, imageFile: oldChild.imageFile, cardColor: oldChild.cardColor
|
||||
));
|
||||
},
|
||||
onToggleIsUnborn: (newValue) {
|
||||
final oldChild = registrationData.children[index];
|
||||
registrationData.updateChild(index, ChildData(
|
||||
firstName: oldChild.firstName, lastName: oldChild.lastName, dob: DataGenerator.dob(isUnborn: newValue),
|
||||
photoConsent: oldChild.photoConsent, multipleBirth: oldChild.multipleBirth, isUnbornChild: newValue,
|
||||
imageFile: oldChild.imageFile, cardColor: oldChild.cardColor
|
||||
));
|
||||
},
|
||||
onRemove: () => _removeChild(index, registrationData),
|
||||
canBeRemoved: registrationData.children.length > 1,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
|
||||
// Bouton "+" carré à la fin de la liste
|
||||
Center(
|
||||
child: HoverReliefWidget(
|
||||
onPressed: () => _addChild(registrationData),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: Image.asset('assets/images/plus.png', fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 30),
|
||||
// Boutons navigation en bas du scroll
|
||||
_buildMobileButtons(context, config, screenSize),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Layout DESKTOP : Scroll horizontal avec fondu
|
||||
Widget _buildDesktopLayout(BuildContext context, DisplayConfig config, Size screenSize, UserRegistrationData registrationData) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Étape 3/5', style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54)),
|
||||
@@ -288,12 +433,12 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Bouton Ajouter
|
||||
// Bouton Ajouter Desktop (Gros bouton)
|
||||
return Center(
|
||||
child: HoverReliefWidget(
|
||||
onPressed: () => _addChild(registrationData),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: Image.asset('assets/images/plus.png', height: 80, width: 80),
|
||||
child: Image.asset('assets/images/plus.png', height: 100, width: 100, fit: BoxFit.contain),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -306,13 +451,18 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Chevrons de navigation
|
||||
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)),
|
||||
);
|
||||
}
|
||||
|
||||
/// Boutons navigation mobile
|
||||
Widget _buildMobileButtons(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: HoverReliefWidget(
|
||||
child: CustomNavigationButton(
|
||||
text: 'Précédent',
|
||||
style: NavigationButtonStyle.purple,
|
||||
onPressed: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
@@ -320,22 +470,28 @@ class _ParentRegisterStep3ScreenState extends State<ParentRegisterStep3Screen> {
|
||||
context.go('/parent-register-step2');
|
||||
}
|
||||
},
|
||||
tooltip: 'Retour',
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: screenSize.height / 2 - 20,
|
||||
right: 40,
|
||||
child: IconButton(
|
||||
icon: Image.asset('assets/images/chevron_right.png', height: 40),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: HoverReliefWidget(
|
||||
child: CustomNavigationButton(
|
||||
text: 'Suivant',
|
||||
style: NavigationButtonStyle.green,
|
||||
onPressed: () {
|
||||
context.go('/parent-register-step4');
|
||||
context.go('/parent-register-step4');
|
||||
},
|
||||
tooltip: 'Suivant',
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../models/user_registration_data.dart'; // Utilisation du vrai modèle
|
||||
import '../../widgets/image_button.dart'; // Import du ImageButton
|
||||
import '../../models/card_assets.dart'; // Import des enums de cartes
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
// Nouvelle méthode helper pour afficher un champ de type "lecture seule" stylisé
|
||||
Widget _buildDisplayFieldValue(BuildContext context, String label, String value, {bool multiLine = false, double fieldHeight = 50.0, double labelFontSize = 18.0}) {
|
||||
const FontWeight labelFontWeight = FontWeight.w600;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: GoogleFonts.merienda(fontSize: labelFontSize, fontWeight: labelFontWeight)),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: double.infinity, // Prendra la largeur allouée par son parent (Expanded)
|
||||
height: multiLine ? null : fieldHeight, // Hauteur flexible pour multiligne, sinon fixe
|
||||
constraints: multiLine ? const BoxConstraints(minHeight: 50.0) : null, // Hauteur min pour multiligne
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 12.0), // Ajuster au besoin
|
||||
decoration: BoxDecoration(
|
||||
image: const DecorationImage(
|
||||
image: AssetImage('assets/images/input_field_bg.png'), // Image de fond du champ
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
// Si votre image input_field_bg.png a des coins arrondis intrinsèques, ce borderRadius n'est pas nécessaire
|
||||
// ou doit correspondre. Sinon, pour une image rectangulaire, vous pouvez l'ajouter.
|
||||
// borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
value.isNotEmpty ? value : '-',
|
||||
style: GoogleFonts.merienda(fontSize: labelFontSize),
|
||||
maxLines: multiLine ? null : 1, // Permet plusieurs lignes si multiLine est true
|
||||
overflow: multiLine ? TextOverflow.visible : TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
import '../../models/user_registration_data.dart';
|
||||
import '../../models/card_assets.dart';
|
||||
import '../../config/display_config.dart';
|
||||
import '../../widgets/hover_relief_widget.dart';
|
||||
import '../../widgets/image_button.dart';
|
||||
import '../../widgets/custom_navigation_button.dart';
|
||||
import '../../widgets/personal_info_form_screen.dart';
|
||||
import '../../widgets/child_card_widget.dart';
|
||||
import '../../widgets/presentation_form_screen.dart';
|
||||
|
||||
class ParentRegisterStep5Screen extends StatefulWidget {
|
||||
const ParentRegisterStep5Screen({super.key});
|
||||
@@ -53,9 +26,7 @@ class _ParentRegisterStep5ScreenState extends State<ParentRegisterStep5Screen> {
|
||||
Widget build(BuildContext context) {
|
||||
final registrationData = Provider.of<UserRegistrationData>(context);
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final cardWidth = screenSize.width / 2.0; // Largeur de la carte (50% de l'écran)
|
||||
final double imageAspectRatio = 2.0; // Ratio corrigé (1024/512 = 2.0)
|
||||
final cardHeight = cardWidth / imageAspectRatio;
|
||||
final config = DisplayConfig.fromContext(context, mode: DisplayMode.readonly);
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
@@ -65,9 +36,11 @@ class _ParentRegisterStep5ScreenState extends State<ParentRegisterStep5Screen> {
|
||||
),
|
||||
Center(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0), // Padding horizontal supprimé ici
|
||||
child: Padding( // Ajout du Padding horizontal externe
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width / 4.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: config.isMobile ? 0 : screenSize.width / 4.0
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
@@ -77,52 +50,202 @@ class _ParentRegisterStep5ScreenState extends State<ParentRegisterStep5Screen> {
|
||||
Text('Récapitulatif de votre demande', style: GoogleFonts.merienda(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black87), textAlign: TextAlign.center),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
_buildParent1Card(context, registrationData.parent1),
|
||||
// Carte Parent 1
|
||||
_buildParent1(context, registrationData),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Carte Parent 2 (si présent)
|
||||
if (registrationData.parent2 != null) ...[
|
||||
_buildParent2Card(context, registrationData.parent2!),
|
||||
_buildParent2(context, registrationData),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
..._buildChildrenCards(context, registrationData.children),
|
||||
_buildMotivationCard(context, registrationData.motivationText),
|
||||
const SizedBox(height: 40),
|
||||
ImageButton(
|
||||
bg: 'assets/images/btn_green.png',
|
||||
text: 'Soumettre ma demande',
|
||||
textColor: const Color(0xFF2D6A4F),
|
||||
width: 350,
|
||||
height: 50,
|
||||
fontSize: 18,
|
||||
onPressed: () {
|
||||
print("Données finales: ${registrationData.parent1.firstName}, Enfant(s): ${registrationData.children.length}");
|
||||
_showConfirmationModal(context);
|
||||
},
|
||||
|
||||
// Cartes Enfants
|
||||
...registrationData.children.asMap().entries.map((entry) =>
|
||||
Column(
|
||||
children: [
|
||||
_buildChildCard(context, entry.value, entry.key),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
)
|
||||
),
|
||||
|
||||
// Carte Motivation
|
||||
_buildMotivation(context, registrationData),
|
||||
const SizedBox(height: 40),
|
||||
|
||||
// Boutons Mobile (Retour + Soumettre) ou Bouton Soumettre Desktop
|
||||
if (config.isMobile)
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width * 0.05),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: HoverReliefWidget(
|
||||
child: CustomNavigationButton(
|
||||
text: 'Précédent',
|
||||
style: NavigationButtonStyle.purple,
|
||||
onPressed: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/parent-register-step4');
|
||||
}
|
||||
},
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: HoverReliefWidget(
|
||||
child: CustomNavigationButton(
|
||||
text: 'Soumettre',
|
||||
style: NavigationButtonStyle.green,
|
||||
onPressed: () {
|
||||
print("Données finales: ${registrationData.parent1.firstName}, Enfant(s): ${registrationData.children.length}");
|
||||
_showConfirmationModal(context);
|
||||
},
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
ImageButton(
|
||||
bg: 'assets/images/bg_green.png',
|
||||
text: 'Soumettre ma demande',
|
||||
textColor: const Color(0xFF2D6A4F),
|
||||
width: 350,
|
||||
height: 50,
|
||||
fontSize: 18,
|
||||
onPressed: () {
|
||||
print("Données finales: ${registrationData.parent1.firstName}, Enfant(s): ${registrationData.children.length}");
|
||||
_showConfirmationModal(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: screenSize.height / 2 - 20,
|
||||
left: 40,
|
||||
child: IconButton(
|
||||
icon: Transform.flip(flipX: true, child: Image.asset('assets/images/chevron_right.png', height: 40)),
|
||||
onPressed: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/parent-register-step4');
|
||||
}
|
||||
},
|
||||
tooltip: 'Retour',
|
||||
// Chevrons 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('/parent-register-step4');
|
||||
}
|
||||
},
|
||||
tooltip: 'Retour',
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildParent1(BuildContext context, UserRegistrationData data) {
|
||||
return PersonalInfoFormScreen(
|
||||
mode: DisplayMode.readonly,
|
||||
embedContentOnly: true,
|
||||
stepText: '',
|
||||
title: 'Informations du Parent Principal',
|
||||
cardColor: CardColorHorizontal.peach,
|
||||
initialData: PersonalInfoData(
|
||||
firstName: data.parent1.firstName,
|
||||
lastName: data.parent1.lastName,
|
||||
phone: data.parent1.phone,
|
||||
email: data.parent1.email,
|
||||
address: data.parent1.address,
|
||||
postalCode: data.parent1.postalCode,
|
||||
city: data.parent1.city,
|
||||
),
|
||||
onSubmit: (d, {hasSecondPerson, sameAddress}) {},
|
||||
previousRoute: '',
|
||||
onEdit: () => context.go('/parent-register-step1'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildParent2(BuildContext context, UserRegistrationData data) {
|
||||
if (data.parent2 == null) return const SizedBox();
|
||||
return PersonalInfoFormScreen(
|
||||
mode: DisplayMode.readonly,
|
||||
embedContentOnly: true,
|
||||
stepText: '',
|
||||
title: 'Informations du Deuxième Parent',
|
||||
cardColor: CardColorHorizontal.blue,
|
||||
initialData: PersonalInfoData(
|
||||
firstName: data.parent2!.firstName,
|
||||
lastName: data.parent2!.lastName,
|
||||
phone: data.parent2!.phone,
|
||||
email: data.parent2!.email,
|
||||
address: data.parent2!.address,
|
||||
postalCode: data.parent2!.postalCode,
|
||||
city: data.parent2!.city,
|
||||
),
|
||||
onSubmit: (d, {hasSecondPerson, sameAddress}) {},
|
||||
previousRoute: '',
|
||||
onEdit: () => context.go('/parent-register-step2'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildChildCard(BuildContext context, ChildData child, int index) {
|
||||
// Note: Le titre est maintenant intégré dans la carte ChildCardWidget en mode readonly
|
||||
return Column(
|
||||
children: [
|
||||
ChildCardWidget(
|
||||
key: ValueKey('child_readonly_$index'),
|
||||
childData: child,
|
||||
childIndex: index,
|
||||
mode: DisplayMode.readonly,
|
||||
onPickImage: () {},
|
||||
onDateSelect: () {},
|
||||
onFirstNameChanged: (v) {},
|
||||
onLastNameChanged: (v) {},
|
||||
onTogglePhotoConsent: (v) {},
|
||||
onToggleMultipleBirth: (v) {},
|
||||
onToggleIsUnborn: (v) {},
|
||||
onRemove: () {},
|
||||
canBeRemoved: false,
|
||||
onEdit: () => context.go('/parent-register-step3', extra: {'childIndex': index}),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMotivation(BuildContext context, UserRegistrationData data) {
|
||||
return PresentationFormScreen(
|
||||
mode: DisplayMode.readonly,
|
||||
embedContentOnly: true,
|
||||
stepText: '',
|
||||
title: 'Votre Motivation',
|
||||
cardColor: CardColorHorizontal.green, // Changé de pink à green
|
||||
textFieldHint: '',
|
||||
initialText: data.motivationText,
|
||||
initialCguAccepted: true, // Toujours true ici car déjà passé
|
||||
previousRoute: '',
|
||||
onSubmit: (t, c) {},
|
||||
onEdit: () => context.go('/parent-register-step4'),
|
||||
);
|
||||
}
|
||||
|
||||
void _showConfirmationModal(BuildContext context) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
@@ -141,8 +264,7 @@ class _ParentRegisterStep5ScreenState extends State<ParentRegisterStep5Screen> {
|
||||
TextButton(
|
||||
child: Text('OK', style: GoogleFonts.merienda(fontWeight: FontWeight.bold)),
|
||||
onPressed: () {
|
||||
Navigator.of(dialogContext).pop(); // Ferme la modale
|
||||
// Utiliser go_router pour la navigation
|
||||
Navigator.of(dialogContext).pop();
|
||||
context.go('/login');
|
||||
},
|
||||
),
|
||||
@@ -151,294 +273,5 @@ class _ParentRegisterStep5ScreenState extends State<ParentRegisterStep5Screen> {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Méthode pour construire la carte Parent 1
|
||||
Widget _buildParent1Card(BuildContext context, ParentData data) {
|
||||
const double verticalSpacing = 28.0; // Espacement vertical augmenté
|
||||
const double labelFontSize = 22.0; // Taille de label augmentée
|
||||
|
||||
List<Widget> details = [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Nom:", data.lastName, labelFontSize: labelFontSize)),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Prénom:", data.firstName, labelFontSize: labelFontSize)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Téléphone:", data.phone, labelFontSize: labelFontSize)),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Email:", data.email, multiLine: true, labelFontSize: labelFontSize)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
_buildDisplayFieldValue(context, "Adresse:", "${data.address}\n${data.postalCode} ${data.city}".trim(), multiLine: true, fieldHeight: 80, labelFontSize: labelFontSize),
|
||||
];
|
||||
return _SummaryCard(
|
||||
backgroundImagePath: CardColorHorizontal.peach.path,
|
||||
title: 'Parent Principal',
|
||||
content: details,
|
||||
onEdit: () => context.go('/parent-register-step1'),
|
||||
);
|
||||
}
|
||||
|
||||
// Méthode pour construire la carte Parent 2
|
||||
Widget _buildParent2Card(BuildContext context, ParentData data) {
|
||||
const double verticalSpacing = 28.0;
|
||||
const double labelFontSize = 22.0;
|
||||
List<Widget> details = [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Nom:", data.lastName, labelFontSize: labelFontSize)),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Prénom:", data.firstName, labelFontSize: labelFontSize)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Téléphone:", data.phone, labelFontSize: labelFontSize)),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(child: _buildDisplayFieldValue(context, "Email:", data.email, multiLine: true, labelFontSize: labelFontSize)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
_buildDisplayFieldValue(context, "Adresse:", "${data.address}\n${data.postalCode} ${data.city}".trim(), multiLine: true, fieldHeight: 80, labelFontSize: labelFontSize),
|
||||
];
|
||||
return _SummaryCard(
|
||||
backgroundImagePath: CardColorHorizontal.blue.path,
|
||||
title: 'Deuxième Parent',
|
||||
content: details,
|
||||
onEdit: () => context.go('/parent-register-step2'),
|
||||
);
|
||||
}
|
||||
|
||||
// Méthode pour construire les cartes Enfants
|
||||
List<Widget> _buildChildrenCards(BuildContext context, List<ChildData> children) {
|
||||
return children.asMap().entries.map((entry) {
|
||||
int index = entry.key;
|
||||
ChildData child = entry.value;
|
||||
|
||||
CardColorHorizontal cardColorHorizontal = CardColorHorizontal.values.firstWhere(
|
||||
(e) => e.name == child.cardColor.name,
|
||||
orElse: () => CardColorHorizontal.lavender,
|
||||
);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20.0),
|
||||
child: Stack(
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: 2.0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 25.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(cardColorHorizontal.path),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Titre centré dans la carte
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Enfant ${index + 1}' + (child.isUnbornChild ? ' (à naître)' : ''),
|
||||
style: GoogleFonts.merienda(fontSize: 28, fontWeight: FontWeight.w600),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 28),
|
||||
onPressed: () {
|
||||
context.go('/parent-register-step3', extra: {'childIndex': index});
|
||||
},
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
// IMAGE SANS CADRE BLANC, PREND LA HAUTEUR
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Center(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: (child.imageFile != null)
|
||||
? (kIsWeb
|
||||
? Image.network(child.imageFile!.path, fit: BoxFit.cover)
|
||||
: Image.file(child.imageFile!, fit: BoxFit.cover))
|
||||
: Image.asset('assets/images/photo.png', fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 32),
|
||||
// INFOS À DROITE (2/3)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_buildDisplayFieldValue(context, 'Prénom :', child.firstName, labelFontSize: 22.0),
|
||||
const SizedBox(height: 12),
|
||||
_buildDisplayFieldValue(context, 'Nom :', child.lastName, labelFontSize: 22.0),
|
||||
const SizedBox(height: 12),
|
||||
_buildDisplayFieldValue(context, child.isUnbornChild ? 'Date de naissance :' : 'Date de naissance :', child.dob, labelFontSize: 22.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
// Ligne des consentements
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: child.photoConsent,
|
||||
onChanged: null,
|
||||
),
|
||||
Text('Consentement photo', style: GoogleFonts.merienda(fontSize: 16)),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 32),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: child.multipleBirth,
|
||||
onChanged: null,
|
||||
),
|
||||
Text('Naissance multiple', style: GoogleFonts.merienda(fontSize: 16)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// Méthode pour construire la carte Motivation
|
||||
Widget _buildMotivationCard(BuildContext context, String motivation) {
|
||||
List<Widget> details = [
|
||||
Text(motivation.isNotEmpty ? motivation : 'Aucune motivation renseignée.',
|
||||
style: GoogleFonts.merienda(fontSize: 18),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.ellipsis)
|
||||
];
|
||||
return _SummaryCard(
|
||||
backgroundImagePath: CardColorHorizontal.pink.path,
|
||||
title: 'Votre Motivation',
|
||||
content: details,
|
||||
onEdit: () => context.go('/parent-register-step4'),
|
||||
);
|
||||
}
|
||||
|
||||
// Helper pour afficher une ligne de détail (police et agencement amélioré)
|
||||
Widget _buildDetailRow(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"$label: ",
|
||||
style: GoogleFonts.merienda(fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value.isNotEmpty ? value : '-',
|
||||
style: GoogleFonts.merienda(fontSize: 18),
|
||||
softWrap: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Widget générique _SummaryCard (ajusté)
|
||||
class _SummaryCard extends StatelessWidget {
|
||||
final String backgroundImagePath;
|
||||
final String title;
|
||||
final List<Widget> content;
|
||||
final VoidCallback onEdit;
|
||||
|
||||
const _SummaryCard({
|
||||
super.key,
|
||||
required this.backgroundImagePath,
|
||||
required this.title,
|
||||
required this.content,
|
||||
required this.onEdit,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AspectRatio(
|
||||
aspectRatio: 2.0, // Le ratio largeur/hauteur de nos images de fond
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 25.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(backgroundImagePath),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min, // Pour que la colonne prenne la hauteur du contenu
|
||||
children: [
|
||||
Align( // Centrer le titre
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
title,
|
||||
style: GoogleFonts.merienda(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black87), // Police légèrement augmentée
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12), // Espacement ajusté après le titre
|
||||
...content,
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 28), // Icône un peu plus grande
|
||||
onPressed: onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user