Files
geo/flutt/lib/presentation/widgets/profile_dialog.dart

357 lines
11 KiB
Dart

import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales
import 'package:flutter/material.dart';
import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales
import 'package:geosector_app/core/repositories/user_repository.dart';
/// Widget de profil commun pour toute l'application
/// Affiche une boîte de dialogue modale avec un formulaire de mise à jour
/// des données utilisateur
class ProfileDialog extends StatefulWidget {
/// ID de l'utilisateur dont on veut afficher/modifier le profil
final String userId;
const ProfileDialog({
Key? key,
required this.userId,
}) : super(key: key);
/// Affiche la boîte de dialogue de profil
static void show(BuildContext context, String userId) {
showDialog(
context: context,
builder: (context) => ProfileDialog(userId: userId),
);
}
@override
State<ProfileDialog> createState() => _ProfileDialogState();
}
class _ProfileDialogState extends State<ProfileDialog> {
/// Contrôleurs pour les champs du formulaire
final TextEditingController _firstNameController = TextEditingController();
final TextEditingController _lastNameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _phoneController = TextEditingController();
/// État de chargement
bool _isLoading = true;
/// État d'erreur
String? _errorMessage;
@override
void initState() {
super.initState();
_loadUserData();
}
@override
void dispose() {
_firstNameController.dispose();
_lastNameController.dispose();
_emailController.dispose();
_phoneController.dispose();
super.dispose();
}
/// Charge les données de l'utilisateur depuis l'API
Future<void> _loadUserData() async {
try {
setState(() {
_isLoading = true;
_errorMessage = null;
});
// Utiliser l'instance globale définie dans app.dart
final user = userRepository.currentUser;
// Si l'utilisateur est trouvé, remplir les champs du formulaire
if (user != null) {
_firstNameController.text = user.firstName ?? '';
_lastNameController.text = user.name ?? '';
_emailController.text = user.email ?? '';
// Note: Utiliser la propriété appropriée pour le téléphone si elle existe
// ou laisser vide si elle n'existe pas
_phoneController.text = ''; // Champ laissé vide par défaut
} else {
_errorMessage = 'Utilisateur non trouvé';
}
} catch (e) {
_errorMessage = 'Erreur lors du chargement des données: $e';
} finally {
setState(() {
_isLoading = false;
});
}
}
/// Enregistre les modifications du profil
Future<void> _saveProfile() async {
try {
setState(() {
_isLoading = true;
_errorMessage = null;
});
// Utiliser l'instance globale définie dans app.dart
// Mettre à jour les données de l'utilisateur
// Note: Cette partie dépend de l'implémentation réelle du UserRepository
// et devrait être adaptée en fonction de l'API disponible
// Récupérer l'utilisateur actuel
final user = userRepository.currentUser;
if (user != null) {
// Mettre à jour les propriétés de l'utilisateur
user.firstName = _firstNameController.text;
user.name = _lastNameController.text;
// Sauvegarder les modifications
// Note: Utiliser la méthode appropriée du repository
// Exemple: userRepo.saveUser(user) ou userRepo.updateUser(user)
// Pour l'instant, nous simulons une mise à jour réussie
// Cette partie devra être adaptée à l'API réelle
await Future.delayed(const Duration(milliseconds: 500));
// Fermer la boîte de dialogue
if (mounted) {
Navigator.of(context)
.pop(true); // Retourne true pour indiquer le succès
// Afficher un message de succès
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Profil mis à jour avec succès'),
backgroundColor: Theme.of(context).colorScheme.primary,
),
);
}
} else {
throw Exception('Utilisateur non trouvé');
}
} catch (e) {
setState(() {
_errorMessage = 'Erreur lors de la mise à jour du profil: $e';
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final theme = Theme.of(context);
// Déterminer si nous sommes sur un appareil mobile ou un ordinateur de bureau
final isDesktop = size.width > 900;
// Calculer la largeur de la boîte de dialogue
// 90% de la largeur de l'écran pour les mobiles
// 50% de la largeur de l'écran pour les ordinateurs de bureau (max 600px)
final dialogWidth = isDesktop
? size.width * 0.5 > 600
? 600.0
: size.width * 0.5
: size.width * 0.9;
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
// Définir la largeur de la boîte de dialogue
child: Container(
width: dialogWidth,
padding: const EdgeInsets.all(24),
child: _isLoading
? const Center(
child: CircularProgressIndicator(),
)
: _errorMessage != null
? _buildErrorView()
: _buildProfileForm(),
),
);
}
/// Construit la vue d'erreur
Widget _buildErrorView() {
final theme = Theme.of(context);
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.error_outline,
color: theme.colorScheme.error,
size: 48,
),
const SizedBox(height: 16),
Text(
'Erreur',
style: theme.textTheme.titleLarge?.copyWith(
color: theme.colorScheme.error,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
_errorMessage ?? 'Une erreur inconnue est survenue',
textAlign: TextAlign.center,
style: theme.textTheme.bodyMedium,
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
style: ElevatedButton.styleFrom(
backgroundColor: theme.colorScheme.primary,
foregroundColor: theme.colorScheme.onPrimary,
),
child: const Text('Fermer'),
),
],
);
}
/// Construit le formulaire de profil
Widget _buildProfileForm() {
final theme = Theme.of(context);
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Titre du formulaire
Row(
children: [
Icon(
Icons.person,
color: theme.colorScheme.primary,
size: 28,
),
const SizedBox(width: 12),
Expanded(
child: Text(
'Mon compte',
style: theme.textTheme.titleLarge?.copyWith(
color: theme.colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
tooltip: 'Fermer',
),
],
),
const Divider(height: 32),
// Formulaire
Form(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Prénom
TextFormField(
controller: _firstNameController,
decoration: const InputDecoration(
labelText: 'Prénom',
prefixIcon: Icon(Icons.person_outline),
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer votre prénom';
}
return null;
},
),
const SizedBox(height: 16),
// Nom
TextFormField(
controller: _lastNameController,
decoration: const InputDecoration(
labelText: 'Nom',
prefixIcon: Icon(Icons.person_outline),
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer votre nom';
}
return null;
},
),
const SizedBox(height: 16),
// Email
TextFormField(
controller: _emailController,
decoration: const InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email_outlined),
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer votre email';
}
if (!value.contains('@')) {
return 'Veuillez entrer un email valide';
}
return null;
},
),
const SizedBox(height: 16),
// Téléphone
TextFormField(
controller: _phoneController,
decoration: const InputDecoration(
labelText: 'Téléphone',
prefixIcon: Icon(Icons.phone_outlined),
border: OutlineInputBorder(),
),
),
],
),
),
const SizedBox(height: 24),
// Boutons d'action
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(
'Annuler',
style: TextStyle(
color: theme.colorScheme.error,
),
),
),
const SizedBox(width: 16),
ElevatedButton(
onPressed: _saveProfile,
style: ElevatedButton.styleFrom(
backgroundColor: theme.colorScheme.primary,
foregroundColor: theme.colorScheme.onPrimary,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text('Enregistrer'),
),
],
),
],
);
}
}