feat: création branche singletons - début refactorisation

- Sauvegarde des fichiers critiques
- Préparation transformation ApiService en singleton
- Préparation création CurrentUserService et CurrentAmicaleService
- Objectif: renommer Box users -> user
This commit is contained in:
d6soft
2025-06-05 15:22:29 +02:00
parent 2aa2706179
commit e5ab857913
48 changed files with 131679 additions and 128324 deletions

View File

@@ -6,20 +6,23 @@ import 'package:geosector_app/core/repositories/user_repository.dart';
import 'package:geosector_app/core/services/api_service.dart';
import 'package:geosector_app/presentation/widgets/mapbox_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart';
import 'custom_text_field.dart';
class AmicaleForm extends StatefulWidget {
final AmicaleModel? amicale;
final Function(AmicaleModel)? onSubmit;
final bool readOnly;
final UserRepository userRepository; // Nouveau paramètre
final ApiService? apiService; // Nouveau paramètre optionnel
const AmicaleForm({
Key? key,
super.key,
this.amicale,
this.onSubmit,
this.readOnly = false,
}) : super(key: key);
required this.userRepository, // Requis
this.apiService, // Optionnel
});
@override
State<AmicaleForm> createState() => _AmicaleFormState();
@@ -59,8 +62,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
_nameController = TextEditingController(text: amicale?.name ?? '');
_adresse1Controller = TextEditingController(text: amicale?.adresse1 ?? '');
_adresse2Controller = TextEditingController(text: amicale?.adresse2 ?? '');
_codePostalController =
TextEditingController(text: amicale?.codePostal ?? '');
_codePostalController = TextEditingController(text: amicale?.codePostal ?? '');
_villeController = TextEditingController(text: amicale?.ville ?? '');
_phoneController = TextEditingController(text: amicale?.phone ?? '');
_mobileController = TextEditingController(text: amicale?.mobile ?? '');
@@ -125,9 +127,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
};
// Ajouter les champs réservés aux administrateurs si l'utilisateur est admin
final userRepository =
Provider.of<UserRepository>(context, listen: false);
final userRole = userRepository.getUserRole();
final userRole = widget.userRepository.getUserRole();
if (userRole > 2) {
data['gps_lat'] = amicale.gpsLat;
data['gps_lng'] = amicale.gpsLng;
@@ -136,56 +136,71 @@ class _AmicaleFormState extends State<AmicaleForm> {
data['chk_active'] = amicale.chkActive;
}
// Appeler l'API
try {
// Obtenir l'instance du service API
final apiService = Provider.of<ApiService>(context, listen: false);
// Fermer l'indicateur de chargement
Navigator.of(context).pop();
// Appeler la méthode post du service API
await apiService.post('/entite/update', data: data);
// Appeler l'API si le service est disponible
if (widget.apiService != null) {
try {
await widget.apiService!.post('/entite/update', data: data);
// Fermer l'indicateur de chargement
Navigator.of(context).pop();
// Afficher un message de succès
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Amicale mise à jour avec succès'),
backgroundColor: Colors.green,
),
);
// Appeler la fonction onSubmit si elle existe
if (widget.onSubmit != null) {
widget.onSubmit!(amicale);
// Afficher un message de succès
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Amicale mise à jour avec succès'),
backgroundColor: Colors.green,
),
);
}
} catch (error) {
// Afficher un message d'erreur
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Erreur lors de la mise à jour de l\'amicale: $error'),
backgroundColor: Colors.red,
),
);
}
return; // Sortir de la fonction en cas d'erreur
}
} else {
// Pas d'API service, afficher un message d'information
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Modifications enregistrées localement'),
backgroundColor: Colors.blue,
),
);
}
}
// Fermer le formulaire
Navigator.of(context).pop();
} catch (error) {
// Fermer l'indicateur de chargement
Navigator.of(context).pop();
// Appeler la fonction onSubmit si elle existe
if (widget.onSubmit != null) {
widget.onSubmit!(amicale);
}
// Afficher un message d'erreur
// Fermer le formulaire
if (mounted) {
Navigator.of(context).pop();
}
} catch (e) {
// Fermer l'indicateur de chargement si encore ouvert
if (Navigator.of(context).canPop()) {
Navigator.of(context).pop();
}
// Afficher un message d'erreur
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Erreur lors de la mise à jour de l\'amicale: $error'),
content: Text('Erreur: ${e.toString()}'),
backgroundColor: Colors.red,
),
);
}
} catch (e) {
// Fermer l'indicateur de chargement
Navigator.of(context).pop();
// Afficher un message d'erreur
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Erreur: ${e.toString()}'),
backgroundColor: Colors.red,
),
);
}
}
@@ -195,13 +210,13 @@ class _AmicaleFormState extends State<AmicaleForm> {
if (_phoneController.text.isEmpty && _mobileController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content:
Text('Veuillez renseigner au moins un numéro de téléphone'),
content: Text('Veuillez renseigner au moins un numéro de téléphone'),
backgroundColor: Colors.red,
),
);
return;
}
final amicale = widget.amicale?.copyWith(
name: _nameController.text,
adresse1: _adresse1Controller.text,
@@ -246,10 +261,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
// Appeler l'API pour mettre à jour l'amicale
_updateAmicale(amicale);
// Appeler la fonction onSubmit si elle existe (pour la compatibilité avec le code existant)
if (widget.onSubmit != null) {
widget.onSubmit!(amicale);
}
// Ne pas appeler widget.onSubmit ici car c'est fait dans _updateAmicale
}
}
@@ -293,8 +305,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
// TODO: Implémenter la sélection d'image
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Fonctionnalité de modification du logo à venir'),
content: Text('Fonctionnalité de modification du logo à venir'),
),
);
},
@@ -447,7 +458,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
child: Text(
label,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onBackground,
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w500,
),
),
@@ -481,7 +492,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
"Adresse",
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: theme.colorScheme.onBackground,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 8),
@@ -566,7 +577,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
"Région",
style: theme.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w500,
color: theme.colorScheme.onBackground,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 8),
@@ -580,7 +591,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
"Contact",
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: theme.colorScheme.onBackground,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 8),
@@ -657,7 +668,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
"Informations avancées",
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: theme.colorScheme.onBackground,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 8),
@@ -671,8 +682,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
child: CustomTextField(
controller: _gpsLatController,
label: "GPS Latitude",
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
readOnly: restrictedFieldsReadOnly,
),
),
@@ -682,8 +692,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
child: CustomTextField(
controller: _gpsLngController,
label: "GPS Longitude",
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
readOnly: restrictedFieldsReadOnly,
),
),
@@ -749,7 +758,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
Text(
"Accepte les règlements en CB",
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onBackground,
color: theme.colorScheme.onSurface,
fontWeight: FontWeight.w500,
),
),
@@ -760,8 +769,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
controller: _stripeIdController,
label: "ID Stripe Paiements CB",
readOnly: restrictedFieldsReadOnly,
helperText:
"Les règlements par CB sont taxés d'une commission de 1.4%",
helperText: "Les règlements par CB sont taxés d'une commission de 1.4%",
),
),
],
@@ -774,7 +782,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
"Options",
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: theme.colorScheme.onBackground,
color: theme.colorScheme.onSurface,
),
),
const SizedBox(height: 8),
@@ -849,8 +857,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
style: OutlinedButton.styleFrom(
foregroundColor: const Color(0xFF20335E),
side: const BorderSide(color: Color(0xFF20335E)),
padding: const EdgeInsets.symmetric(
horizontal: 24, vertical: 16),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
@@ -871,8 +878,7 @@ class _AmicaleFormState extends State<AmicaleForm> {
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF20335E),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24, vertical: 16),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
@@ -895,70 +901,73 @@ class _AmicaleFormState extends State<AmicaleForm> {
// Vérifier si les informations avancées doivent être affichées
bool _shouldShowAdvancedInfo() {
final userRepository = Provider.of<UserRepository>(context, listen: false);
final userRole = userRepository.getUserRole();
final userRole = widget.userRepository.getUserRole();
final bool canEditRestrictedFields = userRole > 2;
return canEditRestrictedFields ||
_gpsLatController.text.isNotEmpty ||
_gpsLngController.text.isNotEmpty ||
_stripeIdController.text.isNotEmpty;
return canEditRestrictedFields || _gpsLatController.text.isNotEmpty || _gpsLngController.text.isNotEmpty || _stripeIdController.text.isNotEmpty;
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final userRepository = Provider.of<UserRepository>(context, listen: false);
final userRole = userRepository.getUserRole();
final userRole = widget.userRepository.getUserRole();
// Déterminer si l'utilisateur peut modifier les champs restreints
final bool canEditRestrictedFields = userRole > 2;
// Lecture seule pour les champs restreints si l'utilisateur n'a pas les droits
final bool restrictedFieldsReadOnly =
widget.readOnly || !canEditRestrictedFields;
final bool restrictedFieldsReadOnly = widget.readOnly || !canEditRestrictedFields;
// Calculer la largeur maximale du formulaire pour les écrans larges
final screenWidth = MediaQuery.of(context).size.width;
final maxFormWidth = screenWidth > 800 ? 800.0 : screenWidth;
return Scaffold(
appBar: AppBar(
title: Text(
widget.readOnly ? 'Détails de l\'amicale' : 'Modifier l\'amicale'),
backgroundColor: theme.appBarTheme.backgroundColor,
foregroundColor: theme.appBarTheme.foregroundColor,
),
body: Center(
child: Container(
width: maxFormWidth,
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
final formContent = Container(
width: maxFormWidth,
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header avec logo et minimap
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Header avec logo et minimap
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Section Logo
_buildLogoSection(),
// Section MiniMap
_buildMiniMap(),
],
),
const SizedBox(height: 24),
// Formulaire principal
_buildMainForm(theme, restrictedFieldsReadOnly),
// Section Logo
_buildLogoSection(),
// Section MiniMap
_buildMiniMap(),
],
),
),
const SizedBox(height: 24),
// Formulaire principal
_buildMainForm(theme, restrictedFieldsReadOnly),
],
),
),
),
);
// Vérifier si on est dans une Dialog en regardant le type du widget parent
final route = ModalRoute.of(context);
final isInDialog = route?.settings.name == null;
// Si on est dans une Dialog, ne pas utiliser Scaffold
if (isInDialog) {
return Center(child: formContent);
}
// Sinon, utiliser Scaffold pour les pages complètes
return Scaffold(
appBar: AppBar(
title: Text(widget.readOnly ? 'Détails de l\'amicale' : 'Modifier l\'amicale'),
backgroundColor: theme.appBarTheme.backgroundColor,
foregroundColor: theme.appBarTheme.foregroundColor,
),
body: Center(child: formContent),
);
}
}