feat(mobile): implémentation feedback + correction URLs inscriptions

Connecte le frontend mobile aux nouveaux endpoints backend événements.

## Repository Interface (evenement_repository.dart)
-  Ajout submitFeedback(evenementId, note, commentaire)
-  Ajout getFeedbacks(evenementId) → retourne feedbacks + stats

## Repository Impl (evenement_repository_impl.dart)
-  Correction inscrireEvenement : /inscrire → /inscriptions (POST)
-  Correction desinscrireEvenement : /desinscrire → /inscriptions (DELETE)
-  Implémentation submitFeedback : POST /api/evenements/{id}/feedback
-  Implémentation getFeedbacks : GET /api/evenements/{id}/feedbacks
- Gestion erreurs 400 (déjà soumis, pas participant, etc.)

## Use Case (submit_event_feedback.dart)
-  Remplacement UnimplementedError par appel repository
-  Validation note 1-5
-  Transmission note + commentaire optionnel

## Fonctionnalités débloquées
- Inscription/désinscription événements  (URLs corrigées)
- Soumission feedback post-événement 
- Consultation feedbacks + note moyenne 

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dahoud
2026-03-16 20:15:35 +00:00
parent df1e8f417d
commit 2639850861
3 changed files with 68 additions and 6 deletions

View File

@@ -270,7 +270,7 @@ class EvenementRepositoryImpl implements IEvenementRepository {
@override @override
Future<void> inscrireEvenement(String evenementId) async { Future<void> inscrireEvenement(String evenementId) async {
try { try {
final response = await _apiClient.post('$_baseUrl/$evenementId/inscrire'); final response = await _apiClient.post('$_baseUrl/$evenementId/inscriptions');
if (response.statusCode != 200 && response.statusCode != 201) { if (response.statusCode != 200 && response.statusCode != 201) {
throw Exception('Erreur lors de l\'inscription à l\'événement: ${response.statusCode}'); throw Exception('Erreur lors de l\'inscription à l\'événement: ${response.statusCode}');
@@ -285,7 +285,7 @@ class EvenementRepositoryImpl implements IEvenementRepository {
@override @override
Future<void> desinscrireEvenement(String evenementId) async { Future<void> desinscrireEvenement(String evenementId) async {
try { try {
final response = await _apiClient.delete('$_baseUrl/$evenementId/desinscrire'); final response = await _apiClient.delete('$_baseUrl/$evenementId/inscriptions');
if (response.statusCode != 200 && response.statusCode != 204) { if (response.statusCode != 200 && response.statusCode != 204) {
throw Exception('Erreur lors de la désinscription de l\'événement: ${response.statusCode}'); throw Exception('Erreur lors de la désinscription de l\'événement: ${response.statusCode}');
@@ -348,5 +348,52 @@ class EvenementRepositoryImpl implements IEvenementRepository {
throw Exception('Erreur inattendue lors de la récupération des statistiques: $e'); throw Exception('Erreur inattendue lors de la récupération des statistiques: $e');
} }
} }
@override
Future<void> submitFeedback({
required String evenementId,
required int note,
String? commentaire,
}) async {
try {
final response = await _apiClient.post(
'$_baseUrl/$evenementId/feedback',
data: {
'note': note,
if (commentaire != null) 'commentaire': commentaire,
},
);
if (response.statusCode != 200 && response.statusCode != 201) {
throw Exception('Erreur lors de la soumission du feedback: ${response.statusCode}');
}
} on DioException catch (e) {
if (e.response?.statusCode == 400) {
// Erreur métier (déjà soumis, pas participant, etc.)
final errorMsg = e.response?.data['error'] ?? 'Erreur lors de la soumission du feedback';
throw Exception(errorMsg);
}
throw Exception('Erreur réseau lors de la soumission du feedback: ${e.message}');
} catch (e) {
throw Exception('Erreur inattendue lors de la soumission du feedback: $e');
}
}
@override
Future<Map<String, dynamic>> getFeedbacks(String evenementId) async {
try {
final response = await _apiClient.get('$_baseUrl/$evenementId/feedbacks');
if (response.statusCode == 200) {
return response.data as Map<String, dynamic>;
} else {
throw Exception('Erreur lors de la récupération des feedbacks: ${response.statusCode}');
}
} on DioException catch (e) {
throw Exception('Erreur réseau lors de la récupération des feedbacks: ${e.message}');
} catch (e) {
throw Exception('Erreur inattendue lors de la récupération des feedbacks: $e');
}
}
} }

View File

@@ -49,4 +49,14 @@ abstract class IEvenementRepository {
/// Récupère les statistiques des événements /// Récupère les statistiques des événements
Future<Map<String, dynamic>> getEvenementsStats(); Future<Map<String, dynamic>> getEvenementsStats();
/// Soumet un feedback pour un événement
Future<void> submitFeedback({
required String evenementId,
required int note,
String? commentaire,
});
/// Récupère les feedbacks d'un événement
Future<Map<String, dynamic>> getFeedbacks(String evenementId);
} }

View File

@@ -21,19 +21,24 @@ class SubmitEventFeedback {
/// Soumet un feedback pour l'événement /// Soumet un feedback pour l'événement
/// Réservé aux participants de l'événement /// Réservé aux participants de l'événement
/// ///
/// TODO: Ajouter endpoint backend POST /api/evenements/{id}/feedback
/// Lève une exception si: /// Lève une exception si:
/// - L'événement n'existe pas /// - L'événement n'existe pas
/// - Le membre n'a pas participé /// - Le membre n'a pas participé
/// - L'événement n'est pas terminé /// - L'événement n'est pas terminé
/// - Un feedback a déjà été soumis
Future<void> call({ Future<void> call({
required String evenementId, required String evenementId,
required int note, required int note,
String? commentaire, String? commentaire,
}) async { }) async {
// TODO: Implémenter quand endpoint backend sera disponible if (note < 1 || note > 5) {
throw UnimplementedError( throw ArgumentError('La note doit être entre 1 et 5');
'Endpoint POST /api/evenements/{id}/feedback non implémenté côté backend', }
await _repository.submitFeedback(
evenementId: evenementId,
note: note,
commentaire: commentaire,
); );
} }
} }