Files
geo/app/lib/presentation/widgets/amicale_table_widget.dart
pierre 599b9fcda0 feat: Gestion des secteurs et migration v3.0.4+304
- Ajout système complet de gestion des secteurs avec contours géographiques
- Import des contours départementaux depuis GeoJSON
- API REST pour la gestion des secteurs (/api/sectors)
- Service de géolocalisation pour déterminer les secteurs
- Migration base de données avec tables x_departements_contours et sectors_adresses
- Interface Flutter pour visualisation et gestion des secteurs
- Ajout thème sombre dans l'application
- Corrections diverses et optimisations

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-07 11:01:45 +02:00

251 lines
8.4 KiB
Dart
Executable File

import 'package:flutter/material.dart';
import 'package:geosector_app/core/services/api_service.dart';
import 'package:geosector_app/core/data/models/amicale_model.dart';
import 'package:geosector_app/core/repositories/user_repository.dart';
import 'package:geosector_app/core/repositories/amicale_repository.dart';
import 'package:geosector_app/presentation/widgets/amicale_row_widget.dart';
import 'package:geosector_app/presentation/widgets/amicale_form.dart';
/// Widget de tableau pour afficher une liste d'amicales
///
/// Ce widget affiche un tableau avec les colonnes :
/// - ID
/// - Nom
/// - Code Postal
/// - Région
/// - Actions (boutons selon les droits de l'utilisateur)
///
/// Lorsqu'on clique sur une ligne, une modale s'affiche avec le formulaire EntiteForm
class AmicaleTableWidget extends StatelessWidget {
final List<AmicaleModel> amicales;
final Function(AmicaleModel)? onEdit;
final Function(AmicaleModel)? onDelete;
final AmicaleRepository amicaleRepository;
final UserRepository userRepository; // Nouveau paramètre
final ApiService? apiService;
final bool isLoading;
final String? emptyMessage;
final bool readOnly;
final bool showActionsColumn;
const AmicaleTableWidget({
super.key,
required this.amicales,
required this.amicaleRepository,
required this.userRepository, // Requis
this.onEdit,
this.onDelete,
this.apiService,
this.isLoading = false,
this.emptyMessage,
this.readOnly = false,
this.showActionsColumn = true,
});
// Ajouter cette nouvelle méthode pour ouvrir directement le formulaire d'édition :
void _showAmicaleEditForm(BuildContext context, AmicaleModel amicale) {
showDialog(
context: context,
barrierDismissible: false,
builder: (dialogContext) => Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Container(
width: MediaQuery.of(dialogContext).size.width * 0.9,
height: MediaQuery.of(dialogContext).size.height * 0.9,
padding: const EdgeInsets.all(16),
child: Column(
children: [
// Header de la dialog
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Modifier l\'amicale',
style: Theme.of(dialogContext).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(dialogContext).colorScheme.primary,
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.of(dialogContext).pop(),
),
],
),
const Divider(),
// Contenu du formulaire
Expanded(
child: AmicaleForm(
amicale: amicale,
readOnly: false,
userRepository: userRepository,
apiService: apiService,
onSubmit: (updatedAmicale) async {
// Sauvegarder l'amicale mise à jour dans le repository
debugPrint('🔄 Sauvegarde de l\'amicale mise à jour: ${updatedAmicale.name}');
await amicaleRepository.saveAmicale(updatedAmicale);
debugPrint('✅ Amicale sauvegardée dans le repository');
Navigator.of(dialogContext).pop();
},
),
),
],
),
),
),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// En-tête du tableau - utiliser AmicaleRowWidget pour l'en-tête
AmicaleRowWidget(
amicale: AmicaleModel(
id: 0,
name: '',
codePostal: '',
ville: '',
libRegion: '',
),
isHeader: true,
onTap: null,
onEdit: null,
onDelete: null,
showActionsColumn: showActionsColumn,
),
// Corps du tableau
Container(
decoration: BoxDecoration(
color: theme.colorScheme.surface,
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
border: Border.all(
color: theme.colorScheme.primary.withOpacity(0.1),
width: 1,
),
),
child: _buildTableContent(context),
),
],
);
}
Widget _buildTableContent(BuildContext context) {
// Afficher un indicateur de chargement si isLoading est true
if (isLoading) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 32.0),
child: Center(child: CircularProgressIndicator()),
);
}
// Afficher un message si la liste est vide
if (amicales.isEmpty) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 32.0),
child: Center(
child: Text(
emptyMessage ?? 'Aucune amicale trouvée',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
),
),
),
);
}
// Afficher la liste des amicales
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: amicales.length,
itemBuilder: (context, index) {
final amicale = amicales[index];
return AmicaleRowWidget(
amicale: amicale,
isAlternate: index % 2 == 1,
onTap: (selectedAmicale) {
// Si pas de colonne Actions, ouvrir directement le formulaire d'édition
if (!showActionsColumn) {
_showAmicaleEditForm(context, selectedAmicale);
} else {
_showAmicaleDetails(context, selectedAmicale);
}
},
onEdit: onEdit,
onDelete: onDelete,
showActionsColumn: showActionsColumn,
);
},
);
}
// Afficher une modale avec le formulaire EntiteForm
void _showAmicaleDetails(BuildContext context, AmicaleModel amicale) {
showDialog(
context: context,
builder: (dialogContext) => Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Container(
width: MediaQuery.of(dialogContext).size.width * 0.6,
padding: const EdgeInsets.all(24),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Détails de l\'amicale',
style: Theme.of(dialogContext).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(dialogContext).colorScheme.primary,
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.of(dialogContext).pop(),
),
],
),
const SizedBox(height: 16),
// Formulaire AmicaleForm en mode lecture seule
AmicaleForm(
amicale: amicale,
readOnly: true,
userRepository: userRepository,
apiService: apiService,
onSubmit: (updatedAmicale) async {
// Sauvegarder l'amicale mise à jour dans le repository
debugPrint('🔄 Sauvegarde de l\'amicale mise à jour: ${updatedAmicale.name}');
await amicaleRepository.saveAmicale(updatedAmicale);
debugPrint('✅ Amicale sauvegardée dans le repository');
Navigator.of(dialogContext).pop();
},
),
],
),
),
),
),
);
}
}