feat: Version 3.5.2 - Configuration Stripe et gestion des immeubles

- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD)
  * DEV: Clés TEST Pierre (mode test)
  * REC: Clés TEST Client (mode test)
  * PROD: Clés LIVE Client (mode live)
- Ajout de la gestion des bases de données immeubles/bâtiments
  * Configuration buildings_database pour DEV/REC/PROD
  * Service BuildingService pour enrichissement des adresses
- Optimisations pages et améliorations ergonomie
- Mises à jour des dépendances Composer
- Nettoyage des fichiers obsolètes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-11-09 18:26:27 +01:00
parent 21657a3820
commit 2f5946a184
812 changed files with 142105 additions and 25992 deletions

View File

@@ -5,6 +5,8 @@ import 'package:geosector_app/core/repositories/operation_repository.dart';
import 'package:geosector_app/core/repositories/user_repository.dart';
import 'package:geosector_app/core/utils/api_exception.dart';
import 'package:geosector_app/presentation/widgets/custom_text_field.dart';
import 'package:geosector_app/presentation/widgets/result_dialog.dart';
import 'package:geosector_app/presentation/widgets/loading_spin_overlay.dart';
class OperationFormDialog extends StatefulWidget {
final OperationModel? operation;
@@ -140,6 +142,12 @@ class _OperationFormDialogState extends State<OperationFormDialog> {
_isSubmitting = true;
});
// Afficher l'overlay de chargement
final overlay = LoadingSpinOverlayUtils.show(
context: context,
message: 'Enregistrement en cours...',
);
try {
// Récupérer l'utilisateur actuel pour le fkEntite
final currentUser = widget.userRepository.getCurrentUser();
@@ -173,45 +181,58 @@ class _OperationFormDialogState extends State<OperationFormDialog> {
final success = await widget.operationRepository.saveOperationFromModel(operationData);
if (success && mounted) {
debugPrint('=== SUCCÈS - AUTO-FERMETURE ===');
debugPrint('=== context.mounted: ${context.mounted} ===');
debugPrint('=== SUCCÈS ===');
// Délai pour laisser le temps à Hive de se synchroniser
Future.delayed(const Duration(milliseconds: 200), () {
if (mounted) {
debugPrint('=== FERMETURE DIFFÉRÉE ===');
// Masquer le loading
LoadingSpinOverlayUtils.hideSpecific(overlay);
// Auto-fermeture de la dialog
try {
debugPrint('=== AVANT Navigator.pop() ===');
Navigator.of(context).pop();
debugPrint('=== APRÈS Navigator.pop() ===');
} catch (e) {
debugPrint('=== ERREUR Navigator.pop(): $e ===');
}
// Afficher le résultat de succès
await ResultDialog.show(
context: context,
success: true,
message: widget.operation == null
? "Nouvelle opération créée avec succès"
: "Opération modifiée avec succès",
);
// Notifier la page parente pour setState()
debugPrint('=== AVANT onSuccess?.call() ===');
// Auto-fermeture de la dialog
if (mounted) {
debugPrint('=== FERMETURE DIALOG ===');
try {
Navigator.of(context).pop();
widget.onSuccess?.call();
debugPrint('=== APRÈS onSuccess?.call() ===');
// Message de succès
Future.delayed(const Duration(milliseconds: 100), () {
if (mounted) {
debugPrint('=== AFFICHAGE MESSAGE SUCCÈS ===');
ApiException.showSuccess(context, widget.operation == null ? "Nouvelle opération créée avec succès" : "Opération modifiée avec succès");
}
});
} catch (e) {
debugPrint('=== ERREUR Navigator.pop(): $e ===');
}
});
}
} else if (mounted) {
debugPrint('=== ÉCHEC - AFFICHAGE ERREUR ===');
ApiException.showError(context, Exception(widget.operation == null ? "Échec de la création de l'opération" : "Échec de la mise à jour de l'opération"));
debugPrint('=== ÉCHEC ===');
// Masquer le loading
LoadingSpinOverlayUtils.hideSpecific(overlay);
// Afficher l'erreur
await ResultDialog.show(
context: context,
success: false,
message: widget.operation == null
? "Échec de la création de l'opération"
: "Échec de la mise à jour de l'opération",
);
}
} catch (e) {
debugPrint('=== ERREUR dans _handleSubmit: $e ===');
// Masquer le loading
LoadingSpinOverlayUtils.hideSpecific(overlay);
// Afficher l'erreur
if (mounted) {
ApiException.showError(context, e);
await ResultDialog.show(
context: context,
success: false,
message: ApiException.fromError(e).message,
);
}
} finally {
// Réinitialiser l'état de soumission seulement si le widget est encore monté
@@ -310,9 +331,9 @@ class _OperationFormDialogState extends State<OperationFormDialog> {
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
border: Border.all(color: theme.colorScheme.outline.withValues(alpha: 0.5)),
border: Border.all(color: theme.colorScheme.outline.withOpacity(0.5)),
borderRadius: BorderRadius.circular(8),
color: theme.colorScheme.surface.withValues(alpha: 0.3),
color: theme.colorScheme.surface.withOpacity(0.3),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -422,10 +443,10 @@ class _OperationFormDialogState extends State<OperationFormDialog> {
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: theme.colorScheme.secondaryContainer.withValues(alpha: 0.3),
color: theme.colorScheme.secondaryContainer.withOpacity(0.3),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: theme.colorScheme.outline.withValues(alpha: 0.3),
color: theme.colorScheme.outline.withOpacity(0.3),
),
),
child: Row(