diff --git a/.gitignore b/.gitignore index 1269d74..240daab 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,8 @@ coverage/ *.tmp *.temp .cache/ +Archives/** +Xcf/** # Release notes CHANGELOG.md \ No newline at end of file diff --git a/frontend/assets/images/card_rose.png b/frontend/assets/images/card_rose.png new file mode 100644 index 0000000..69754d5 Binary files /dev/null and b/frontend/assets/images/card_rose.png differ diff --git a/frontend/assets/images/card_yellow.png b/frontend/assets/images/card_yellow.png new file mode 100644 index 0000000..f84fec3 Binary files /dev/null and b/frontend/assets/images/card_yellow.png differ diff --git a/frontend/assets/images/chevron_right.png b/frontend/assets/images/chevron_right.png new file mode 100644 index 0000000..0388c71 Binary files /dev/null and b/frontend/assets/images/chevron_right.png differ diff --git a/frontend/assets/images/icon_assmat.png b/frontend/assets/images/icon_assmat.png new file mode 100644 index 0000000..dbfaea5 Binary files /dev/null and b/frontend/assets/images/icon_assmat.png differ diff --git a/frontend/assets/images/icon_parents.png b/frontend/assets/images/icon_parents.png new file mode 100644 index 0000000..8326366 Binary files /dev/null and b/frontend/assets/images/icon_parents.png differ diff --git a/frontend/assets/images/input_field_bg.png b/frontend/assets/images/input_field_bg.png new file mode 100644 index 0000000..21ca755 Binary files /dev/null and b/frontend/assets/images/input_field_bg.png differ diff --git a/frontend/lib/models/child.dart b/frontend/lib/models/child.dart deleted file mode 100644 index be980e5..0000000 --- a/frontend/lib/models/child.dart +++ /dev/null @@ -1,73 +0,0 @@ -class Child { - final String id; - final String firstName; - final String lastName; - final DateTime? birthDate; - final DateTime? expectedBirthDate; - final String? photoUrl; - final bool hasPhotoConsent; - final DateTime? photoConsentDate; - final String status; // 'unborn', 'active', 'schooled' - final List parentIds; - final bool isMultipleBirth; // true pour jumeaux, triplés, etc. - final DateTime createdAt; - final DateTime updatedAt; - - Child({ - required this.id, - required this.firstName, - required this.lastName, - this.birthDate, - this.expectedBirthDate, - this.photoUrl, - required this.hasPhotoConsent, - this.photoConsentDate, - required this.status, - required this.parentIds, - required this.isMultipleBirth, - required this.createdAt, - required this.updatedAt, - }); - - factory Child.fromJson(Map json) { - return Child( - id: json['id'], - firstName: json['firstName'], - lastName: json['lastName'], - birthDate: json['birthDate'] != null - ? DateTime.parse(json['birthDate']) - : null, - expectedBirthDate: json['expectedBirthDate'] != null - ? DateTime.parse(json['expectedBirthDate']) - : null, - photoUrl: json['photoUrl'], - hasPhotoConsent: json['hasPhotoConsent'] ?? false, - photoConsentDate: json['photoConsentDate'] != null - ? DateTime.parse(json['photoConsentDate']) - : null, - status: json['status'] ?? 'unborn', - parentIds: List.from(json['parentIds'] ?? []), - isMultipleBirth: json['isMultipleBirth'] ?? false, - createdAt: DateTime.parse(json['createdAt']), - updatedAt: DateTime.parse(json['updatedAt']), - ); - } - - Map toJson() { - return { - 'id': id, - 'firstName': firstName, - 'lastName': lastName, - 'birthDate': birthDate?.toIso8601String(), - 'expectedBirthDate': expectedBirthDate?.toIso8601String(), - 'photoUrl': photoUrl, - 'hasPhotoConsent': hasPhotoConsent, - 'photoConsentDate': photoConsentDate?.toIso8601String(), - 'status': status, - 'parentIds': parentIds, - 'isMultipleBirth': isMultipleBirth, - 'createdAt': createdAt.toIso8601String(), - 'updatedAt': updatedAt.toIso8601String(), - }; - } -} \ No newline at end of file diff --git a/frontend/lib/models/parent.dart b/frontend/lib/models/parent.dart deleted file mode 100644 index 6bc56bf..0000000 --- a/frontend/lib/models/parent.dart +++ /dev/null @@ -1,63 +0,0 @@ -class Parent { - final String id; - final String userId; - final String firstName; - final String lastName; - final String email; - final String phoneNumber; - final String address; - final String city; - final String postalCode; - final List childrenIds; - final DateTime createdAt; - final DateTime updatedAt; - - Parent({ - required this.id, - required this.userId, - required this.firstName, - required this.lastName, - required this.email, - required this.phoneNumber, - required this.address, - required this.city, - required this.postalCode, - required this.childrenIds, - required this.createdAt, - required this.updatedAt, - }); - - factory Parent.fromJson(Map json) { - return Parent( - id: json['id'], - userId: json['userId'], - firstName: json['firstName'], - lastName: json['lastName'], - email: json['email'], - phoneNumber: json['phoneNumber'], - address: json['address'], - city: json['city'], - postalCode: json['postalCode'], - childrenIds: List.from(json['childrenIds']), - createdAt: DateTime.parse(json['createdAt']), - updatedAt: DateTime.parse(json['updatedAt']), - ); - } - - Map toJson() { - return { - 'id': id, - 'userId': userId, - 'firstName': firstName, - 'lastName': lastName, - 'email': email, - 'phoneNumber': phoneNumber, - 'address': address, - 'city': city, - 'postalCode': postalCode, - 'childrenIds': childrenIds, - 'createdAt': createdAt.toIso8601String(), - 'updatedAt': updatedAt.toIso8601String(), - }; - } -} \ No newline at end of file diff --git a/frontend/lib/navigation/app_router.dart b/frontend/lib/navigation/app_router.dart index 89ac43c..50f455e 100644 --- a/frontend/lib/navigation/app_router.dart +++ b/frontend/lib/navigation/app_router.dart @@ -1,27 +1,23 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import '../screens/auth/login_screen.dart'; -import '../screens/auth/parent_register_screen.dart'; import '../screens/home/home_screen.dart'; class AppRouter { static const String login = '/login'; - static const String parentRegister = '/parent-register'; static const String home = '/home'; static Route generateRoute(RouteSettings settings) { switch (settings.name) { case login: return MaterialPageRoute(builder: (_) => const LoginScreen()); - case parentRegister: - return MaterialPageRoute(builder: (_) => const ParentRegisterScreen()); case home: return MaterialPageRoute(builder: (_) => const HomeScreen()); default: return MaterialPageRoute( builder: (_) => Scaffold( body: Center( - child: Text('Route non définie: ${settings.name}'), + child: Text('Route non définie: ${settings.name}'), ), ), ); diff --git a/frontend/lib/screens/auth/login_screen.dart b/frontend/lib/screens/auth/login_screen.dart index f3d944a..d4588ad 100644 --- a/frontend/lib/screens/auth/login_screen.dart +++ b/frontend/lib/screens/auth/login_screen.dart @@ -197,19 +197,7 @@ class _LoginPageState extends State { const SizedBox(height: 10), // Lien de création de compte Center( - child: TextButton( - onPressed: () { - Navigator.pushNamed(context, '/parent-register'); - }, - child: Text( - 'Créer un compte', - style: GoogleFonts.merienda( - fontSize: 16, - color: const Color(0xFF2D6A4F), - decoration: TextDecoration.underline, - ), - ), - ), + child: Container(), // Suppression du bouton 'Créer un compte' ), const SizedBox(height: 20), // Réduit l'espacement en bas ], diff --git a/frontend/lib/screens/auth/parent_register_screen.dart b/frontend/lib/screens/auth/parent_register_screen.dart deleted file mode 100644 index 00416e3..0000000 --- a/frontend/lib/screens/auth/parent_register_screen.dart +++ /dev/null @@ -1,752 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:go_router/go_router.dart'; -import '../../services/auth_service.dart'; -import '../../theme/app_theme.dart'; -import 'dart:convert'; - -class ChildData { - final TextEditingController firstNameController = TextEditingController(); - final TextEditingController lastNameController = TextEditingController(); - DateTime? birthDate; - DateTime? expectedBirthDate; - XFile? photo; - bool hasPhotoConsent = false; - bool isMultipleBirth = false; - bool isUnborn = false; -} - -class ParentRegisterScreen extends StatefulWidget { - const ParentRegisterScreen({super.key}); - - @override - State createState() => _ParentRegisterScreenState(); -} - -class _ParentRegisterScreenState extends State { - final _formKey = GlobalKey(); - final _authService = AuthService(); - int _currentStep = 0; - bool _isLoading = false; - bool _hasPartner = false; - bool _hasAcceptedCGU = false; - bool _partnerSameAddress = false; - - // Contrôleurs pour le parent 1 - final _emailController = TextEditingController(); - final _passwordController = TextEditingController(); - final _firstNameController = TextEditingController(); - final _lastNameController = TextEditingController(); - final _phoneController = TextEditingController(); - final _addressController = TextEditingController(); - final _cityController = TextEditingController(); - final _postalCodeController = TextEditingController(); - final _presentationController = TextEditingController(); - - // Contrôleurs pour le parent 2 - final _partnerFirstNameController = TextEditingController(); - final _partnerLastNameController = TextEditingController(); - final _partnerEmailController = TextEditingController(); - final _partnerPhoneController = TextEditingController(); - final _partnerAddressController = TextEditingController(); - final _partnerCityController = TextEditingController(); - final _partnerPostalCodeController = TextEditingController(); - - // Liste des enfants - final List _children = [ChildData()]; - - final _motivationController = TextEditingController(); - - @override - void dispose() { - _emailController.dispose(); - _passwordController.dispose(); - _firstNameController.dispose(); - _lastNameController.dispose(); - _phoneController.dispose(); - _addressController.dispose(); - _cityController.dispose(); - _postalCodeController.dispose(); - _presentationController.dispose(); - _partnerFirstNameController.dispose(); - _partnerLastNameController.dispose(); - _partnerEmailController.dispose(); - _partnerPhoneController.dispose(); - _partnerAddressController.dispose(); - _partnerCityController.dispose(); - _partnerPostalCodeController.dispose(); - for (var child in _children) { - child.firstNameController.dispose(); - child.lastNameController.dispose(); - } - _motivationController.dispose(); - super.dispose(); - } - - Future _pickImage(ChildData child) async { - final ImagePicker picker = ImagePicker(); - final XFile? image = await picker.pickImage(source: ImageSource.gallery); - - if (image != null) { - setState(() { - child.photo = image; - }); - } - } - - Future _uploadImage(XFile image, String userId) async { - // En mode démonstration, on retourne juste un chemin local - return image.path; - } - - Future _register() async { - if (!_formKey.currentState!.validate()) return; - - setState(() => _isLoading = true); - - try { - final List> childrenData = []; - - for (var child in _children) { - childrenData.add({ - 'firstName': child.firstNameController.text, - 'lastName': child.lastNameController.text, - 'birthDate': child.isUnborn ? null : child.birthDate, - 'expectedBirthDate': child.isUnborn ? child.expectedBirthDate : null, - 'photo': child.photo != null ? base64Encode(child.photo!.readAsBytesSync()) : null, - 'hasPhotoConsent': child.hasPhotoConsent, - 'isMultipleBirth': child.isMultipleBirth, - }); - } - - await _authService.registerParent( - email: _emailController.text, - password: _passwordController.text, - firstName: _firstNameController.text, - lastName: _lastNameController.text, - phoneNumber: _phoneController.text, - address: _addressController.text, - city: _cityController.text, - postalCode: _postalCodeController.text, - presentation: _presentationController.text, - hasAcceptedCGU: _hasAcceptedCGU, - partnerFirstName: _hasPartner ? _partnerFirstNameController.text : null, - partnerLastName: _hasPartner ? _partnerLastNameController.text : null, - partnerEmail: _hasPartner ? _partnerEmailController.text : null, - partnerPhoneNumber: _hasPartner ? _partnerPhoneController.text : null, - partnerAddress: _hasPartner - ? (_partnerSameAddress - ? _addressController.text - : _partnerAddressController.text) - : null, - partnerCity: _hasPartner - ? (_partnerSameAddress ? _cityController.text : _partnerCityController.text) - : null, - partnerPostalCode: _hasPartner - ? (_partnerSameAddress ? _postalCodeController.text : _partnerPostalCodeController.text) - : null, - children: childrenData, - motivation: _motivationController.text, - ); - - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Inscription réussie ! Votre compte est en attente de validation.'), - backgroundColor: Colors.green, - ), - ); - context.pop(); - } - } catch (e) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Erreur lors de l\'inscription: $e'), - backgroundColor: Colors.red, - ), - ); - } - } finally { - if (mounted) { - setState(() => _isLoading = false); - } - } - } - - Widget _buildChildForm(ChildData child, int index) { - return Card( - margin: const EdgeInsets.symmetric(vertical: 8.0), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Enfant ${index + 1}', - style: Theme.of(context).textTheme.titleMedium, - ), - if (index > 0) - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - setState(() { - _children.removeAt(index); - }); - }, - ), - ], - ), - if (child.photo != null) - CircleAvatar( - radius: 50, - backgroundImage: NetworkImage(child.photo!.path), - ), - TextButton( - onPressed: () => _pickImage(child), - child: const Text('Ajouter une photo'), - ), - SwitchListTile( - title: const Text('Enfant à naître'), - value: child.isUnborn, - onChanged: (value) => setState(() => child.isUnborn = value), - ), - TextFormField( - controller: child.firstNameController, - decoration: const InputDecoration(labelText: 'Prénom de l\'enfant'), - ), - TextFormField( - controller: child.lastNameController, - decoration: const InputDecoration(labelText: 'Nom de l\'enfant'), - ), - if (!child.isUnborn) - ListTile( - title: const Text('Date de naissance'), - subtitle: Text(child.birthDate != null - ? '${child.birthDate!.day}/${child.birthDate!.month}/${child.birthDate!.year}' - : 'Non définie'), - trailing: IconButton( - icon: const Icon(Icons.calendar_today), - onPressed: () async { - final date = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2000), - lastDate: DateTime.now(), - ); - if (date != null) { - setState(() => child.birthDate = date); - } - }, - ), - ), - if (child.isUnborn) - ListTile( - title: const Text('Date prévue'), - subtitle: Text(child.expectedBirthDate != null - ? '${child.expectedBirthDate!.day}/${child.expectedBirthDate!.month}/${child.expectedBirthDate!.year}' - : 'Non définie'), - trailing: IconButton( - icon: const Icon(Icons.calendar_today), - onPressed: () async { - final date = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime.now(), - lastDate: DateTime.now().add(const Duration(days: 365)), - ); - if (date != null) { - setState(() => child.expectedBirthDate = date); - } - }, - ), - ), - SwitchListTile( - title: const Text('Naissance multiple'), - subtitle: const Text('Jumeaux, triplés, etc.'), - value: child.isMultipleBirth, - onChanged: (value) => setState(() => child.isMultipleBirth = value), - ), - if (child.photo != null) - SwitchListTile( - title: const Text('Consentement photo'), - subtitle: const Text('J\'autorise l\'utilisation de la photo de mon enfant'), - value: child.hasPhotoConsent, - onChanged: (value) => setState(() => child.hasPhotoConsent = value), - ), - ], - ), - ), - ); - } - - List _getSteps() { - return [ - // Étape 1 : Parent 1 - Step( - title: const Text('Informations parent 1'), - content: Column( - children: [ - TextFormField( - controller: _emailController, - decoration: const InputDecoration(labelText: 'Email'), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre email'; - } - return null; - }, - ), - TextFormField( - controller: _passwordController, - decoration: const InputDecoration(labelText: 'Mot de passe'), - obscureText: true, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer un mot de passe'; - } - if (value.length < 6) { - return 'Le mot de passe doit contenir au moins 6 caractères'; - } - return null; - }, - ), - TextFormField( - controller: _firstNameController, - decoration: const InputDecoration(labelText: 'Prénom'), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre prénom'; - } - return null; - }, - ), - TextFormField( - controller: _lastNameController, - decoration: const InputDecoration(labelText: 'Nom'), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre nom'; - } - return null; - }, - ), - TextFormField( - controller: _phoneController, - decoration: const InputDecoration(labelText: 'Téléphone'), - keyboardType: TextInputType.phone, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre numéro de téléphone'; - } - return null; - }, - ), - TextFormField( - controller: _addressController, - decoration: const InputDecoration(labelText: 'Adresse'), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre adresse'; - } - return null; - }, - ), - TextFormField( - controller: _cityController, - decoration: const InputDecoration(labelText: 'Ville'), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre ville'; - } - return null; - }, - ), - TextFormField( - controller: _postalCodeController, - decoration: const InputDecoration(labelText: 'Code postal'), - keyboardType: TextInputType.number, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre code postal'; - } - return null; - }, - ), - TextFormField( - controller: _presentationController, - decoration: const InputDecoration(labelText: 'Présentation'), - maxLines: 3, - ), - ], - ), - isActive: _currentStep >= 0, - ), - // Étape 2 : Parent 2 - Step( - title: const Text('Parent 2'), - content: Column( - children: [ - SwitchListTile( - title: const Text('Ajouter un deuxième parent'), - value: _hasPartner, - onChanged: (value) => setState(() => _hasPartner = value), - ), - if (_hasPartner) ...[ - SwitchListTile( - title: const Text('Adresse identique au parent 1'), - value: _partnerSameAddress, - onChanged: (value) { - setState(() { - _partnerSameAddress = value; - if (value) { - _partnerAddressController.text = _addressController.text; - _partnerCityController.text = _cityController.text; - _partnerPostalCodeController.text = _postalCodeController.text; - } else { - _partnerAddressController.clear(); - _partnerCityController.clear(); - _partnerPostalCodeController.clear(); - } - }); - }, - ), - TextFormField( - controller: _partnerFirstNameController, - decoration: const InputDecoration(labelText: 'Prénom du deuxième parent'), - validator: (value) { - if (_hasPartner && (value == null || value.isEmpty)) { - return 'Veuillez entrer le prénom'; - } - return null; - }, - ), - TextFormField( - controller: _partnerLastNameController, - decoration: const InputDecoration(labelText: 'Nom du deuxième parent'), - validator: (value) { - if (_hasPartner && (value == null || value.isEmpty)) { - return 'Veuillez entrer le nom'; - } - return null; - }, - ), - TextFormField( - controller: _partnerEmailController, - decoration: const InputDecoration(labelText: 'Email du deuxième parent'), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (_hasPartner && (value == null || value.isEmpty)) { - return 'Veuillez entrer l\'email'; - } - return null; - }, - ), - TextFormField( - controller: _partnerPhoneController, - decoration: const InputDecoration(labelText: 'Téléphone du deuxième parent'), - keyboardType: TextInputType.phone, - ), - if (!_partnerSameAddress) ...[ - TextFormField( - controller: _partnerAddressController, - decoration: const InputDecoration(labelText: 'Adresse du deuxième parent'), - validator: (value) { - if (_hasPartner && !_partnerSameAddress && (value == null || value.isEmpty)) { - return 'Veuillez entrer l\'adresse'; - } - return null; - }, - ), - TextFormField( - controller: _partnerCityController, - decoration: const InputDecoration(labelText: 'Ville du deuxième parent'), - validator: (value) { - if (_hasPartner && !_partnerSameAddress && (value == null || value.isEmpty)) { - return 'Veuillez entrer la ville'; - } - return null; - }, - ), - TextFormField( - controller: _partnerPostalCodeController, - decoration: const InputDecoration(labelText: 'Code postal du deuxième parent'), - keyboardType: TextInputType.number, - validator: (value) { - if (_hasPartner && !_partnerSameAddress && (value == null || value.isEmpty)) { - return 'Veuillez entrer le code postal'; - } - return null; - }, - ), - ], - ], - ], - ), - isActive: _currentStep >= 1, - ), - // Étape 3 : Enfants - Step( - title: const Text('Enfants'), - content: Column( - children: [ - ..._children.asMap().entries.map((entry) => _buildChildForm(entry.value, entry.key)), - const SizedBox(height: 16), - ElevatedButton.icon( - onPressed: () { - setState(() { - _children.add(ChildData()); - }); - }, - icon: const Icon(Icons.add), - label: const Text('Ajouter un autre enfant'), - ), - ], - ), - isActive: _currentStep >= 2, - ), - // Étape 4 : Description de la situation - Step( - title: const Text('Description de votre situation'), - content: Column( - children: [ - TextFormField( - controller: _motivationController, - decoration: const InputDecoration( - labelText: 'Décrivez votre situation', - hintText: 'Expliquez-nous votre situation familiale et vos besoins...', - ), - maxLines: 5, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez nous décrire votre situation'; - } - return null; - }, - ), - ], - ), - isActive: _currentStep >= 3, - ), - // Étape 5 : CGU - Step( - title: const Text('Conditions générales'), - content: Column( - children: [ - SwitchListTile( - title: const Text('Conditions générales'), - subtitle: const Text('J\'accepte les conditions générales d\'utilisation'), - value: _hasAcceptedCGU, - onChanged: (value) => setState(() => _hasAcceptedCGU = value), - ), - if (!_hasAcceptedCGU) - const Text( - 'Vous devez accepter les conditions générales pour continuer', - style: TextStyle(color: Colors.red), - ), - ], - ), - isActive: _currentStep >= 4, - ), - // Étape 6 : Résumé - Step( - title: const Text('Résumé'), - content: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Veuillez vérifier vos informations avant validation :', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - const SizedBox(height: 16), - // Parent 1 - const Text('Parent 1', style: TextStyle(fontWeight: FontWeight.bold)), - ListTile( - title: const Text('Email'), - subtitle: Text(_emailController.text), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 0), - ), - ), - ListTile( - title: const Text('Nom complet'), - subtitle: Text('${_firstNameController.text} ${_lastNameController.text}'), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 0), - ), - ), - ListTile( - title: const Text('Adresse'), - subtitle: Text('${_addressController.text}\n${_postalCodeController.text} ${_cityController.text}'), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 0), - ), - ), - ListTile( - title: const Text('Téléphone'), - subtitle: Text(_phoneController.text), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 0), - ), - ), - if (_presentationController.text.isNotEmpty) - ListTile( - title: const Text('Présentation'), - subtitle: Text(_presentationController.text), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 0), - ), - ), - - // Parent 2 - if (_hasPartner) ...[ - const SizedBox(height: 16), - const Text('Parent 2', style: TextStyle(fontWeight: FontWeight.bold)), - ListTile( - title: const Text('Email'), - subtitle: Text(_partnerEmailController.text), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 1), - ), - ), - ListTile( - title: const Text('Nom complet'), - subtitle: Text('${_partnerFirstNameController.text} ${_partnerLastNameController.text}'), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 1), - ), - ), - ListTile( - title: const Text('Téléphone'), - subtitle: Text(_partnerPhoneController.text), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 1), - ), - ), - ListTile( - title: const Text('Adresse'), - subtitle: _partnerSameAddress - ? const Text('Identique au parent 1') - : Text('${_partnerAddressController.text}\n${_partnerPostalCodeController.text} ${_partnerCityController.text}'), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 1), - ), - ), - ], - - // Enfants - const SizedBox(height: 16), - const Text('Enfants', style: TextStyle(fontWeight: FontWeight.bold)), - ..._children.asMap().entries.map((entry) { - final child = entry.value; - return ListTile( - title: Text('Enfant ${entry.key + 1}'), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Prénom : ${child.firstNameController.text} ${child.lastNameController.text}'), - if (child.isUnborn) - Text('Date prévue : ${child.expectedBirthDate?.day}/${child.expectedBirthDate?.month}/${child.expectedBirthDate?.year}') - else - Text('Date de naissance : ${child.birthDate?.day}/${child.birthDate?.month}/${child.birthDate?.year}'), - if (child.isMultipleBirth) - const Text('Naissance multiple'), - ], - ), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 2), - ), - ); - }), - - // Motivation - const SizedBox(height: 16), - const Text('Motivation', style: TextStyle(fontWeight: FontWeight.bold)), - ListTile( - title: const Text('Votre message'), - subtitle: Text(_motivationController.text), - trailing: IconButton( - icon: const Icon(Icons.edit), - onPressed: () => setState(() => _currentStep = 3), - ), - ), - ], - ), - ), - isActive: _currentStep >= 5, - ), - ]; - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Inscription Parent'), - ), - body: Form( - key: _formKey, - child: Stepper( - currentStep: _currentStep, - onStepContinue: () { - if (_currentStep < _getSteps().length - 1) { - setState(() => _currentStep++); - } else if (_hasAcceptedCGU) { - _register(); - } - }, - onStepCancel: () { - if (_currentStep > 0) { - setState(() => _currentStep--); - } else { - Navigator.pop(context); - } - }, - controlsBuilder: (context, details) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: Row( - children: [ - if (_currentStep > 0) - OutlinedButton( - onPressed: details.onStepCancel, - child: const Text('Retour'), - ), - const SizedBox(width: 16), - if (_currentStep < _getSteps().length - 1) - ElevatedButton( - onPressed: details.onStepContinue, - child: const Text('Suivant'), - ) - else - ElevatedButton( - onPressed: _hasAcceptedCGU ? details.onStepContinue : null, - child: _isLoading - ? const CircularProgressIndicator() - : const Text('S\'inscrire'), - ), - ], - ), - ); - }, - steps: _getSteps(), - ), - ), - ); - } -} \ No newline at end of file diff --git a/frontend/lib/services/auth_service.dart b/frontend/lib/services/auth_service.dart index 0ff0b67..5234c8e 100644 --- a/frontend/lib/services/auth_service.dart +++ b/frontend/lib/services/auth_service.dart @@ -1,8 +1,6 @@ import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; import '../models/user.dart'; -import '../models/parent.dart'; -import '../models/child.dart'; class AuthService { static const String _usersKey = 'users'; @@ -27,32 +25,6 @@ class AuthService { throw Exception('Mode démonstration - Inscription désactivée'); } - // Méthode pour s'inscrire en tant que parent (mode démonstration) - Future registerParent({ - required String email, - required String password, - required String firstName, - required String lastName, - required String phoneNumber, - required String address, - required String city, - required String postalCode, - String? presentation, - required bool hasAcceptedCGU, - String? partnerFirstName, - String? partnerLastName, - String? partnerEmail, - String? partnerPhoneNumber, - String? partnerAddress, - String? partnerCity, - String? partnerPostalCode, - required List> children, - required String motivation, - }) async { - // En mode démonstration, on ne fait rien - await Future.delayed(const Duration(seconds: 2)); // Simule un délai de traitement - } - // Méthode pour se déconnecter (mode démonstration) static Future logout() async { // Ne fait rien en mode démonstration diff --git a/ressources/cartes.png b/ressources/cartes.png new file mode 100644 index 0000000..75c0bf7 --- /dev/null +++ b/ressources/cartes.png @@ -0,0 +1,3 @@ +AuthenticationFailedServer failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. +RequestId:32300bba-601e-0021-763f-bc1466000000 +Time:2025-05-03T15:21:39.1449044ZSigned expiry time [Sat, 03 May 2025 15:21:15 GMT] must be after signed start time [Sat, 03 May 2025 15:21:39 GMT] \ No newline at end of file diff --git a/ressources/wizard_styles.html b/ressources/wizard_styles.html new file mode 100644 index 0000000..021e26f --- /dev/null +++ b/ressources/wizard_styles.html @@ -0,0 +1,63 @@ + + + + + + +P’titsPas – Propositions UI Wizard + + + + +

Création de compte : idées d’enchaînement de cartes

+ +

Chaque étape s’affiche dans une « carte » pastel. En validant, la carte suivante glisse vers l’avant (animation CSS : transform: translateX(-100%) + opacity). Trois styles proposés :

+ +
+
+

Style 1 : Watercolor

+ watercolor stack +
+
+
+
+
+
#FBC9C4 · #FBD38B · #A9D8C6
+

Bords arrondis 22 px, texture papier sur chaque carte.
Animation : légère rotation (tilt) pour rappeler un paquet de cartes réaliste.

+
+
+

Style 2 : Minimal pastel

+ minimal stack +
+
+
+
+
+
#E3DFFD · #CFEAE3 · #FFE88A
+

Cartes plates, ombre portée subtile (0 2 8 rgba0,05).
Animation : slide horizontal + fondu rapide.

+
+
+

Style 3 : Modern vibrant

+ modern stack +
+
+
+
+
+
#FB86A2 · #F3D468 · #8AC1E3
+

Coins arrondis 12 px pour une touche « app mobile ».
Animation : carte sort par la gauche, nouvelle carte zoome légèrement.

+
+
+ + + +