feat(frontend): download responsable history csv
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import "dart:convert";
|
||||
import "dart:typed_data";
|
||||
import "package:http/http.dart" as http;
|
||||
|
||||
/// Erreur levée par le client API (serveur injoignable ou réponse en échec).
|
||||
@@ -11,6 +12,18 @@ class ApiException implements Exception {
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
class ApiFile {
|
||||
const ApiFile({
|
||||
required this.bytes,
|
||||
required this.fileName,
|
||||
required this.contentType,
|
||||
});
|
||||
|
||||
final Uint8List bytes;
|
||||
final String fileName;
|
||||
final String contentType;
|
||||
}
|
||||
|
||||
/// Point d'accès unique au backend : centralise l'URL de base, l'en-tête
|
||||
/// d'authentification (simulée) et la gestion des erreurs.
|
||||
class ApiClient {
|
||||
@@ -44,6 +57,37 @@ class ApiClient {
|
||||
throw ApiException(_messageErreur(reponse));
|
||||
}
|
||||
|
||||
static Future<ApiFile> getFile(
|
||||
String chemin, {
|
||||
required String fallbackFileName,
|
||||
String utilisateurEmail = _utilisateurEmail,
|
||||
}) async {
|
||||
final uri = Uri.parse("$_baseUrl$chemin");
|
||||
|
||||
late final http.Response reponse;
|
||||
try {
|
||||
reponse = await http.get(
|
||||
uri,
|
||||
headers: {"x-user-email": utilisateurEmail},
|
||||
);
|
||||
} catch (_) {
|
||||
throw const ApiException(
|
||||
"Impossible de joindre le serveur. Vérifiez que le backend est démarré.",
|
||||
);
|
||||
}
|
||||
|
||||
if (reponse.statusCode < 200 || reponse.statusCode >= 300) {
|
||||
throw ApiException(_messageErreur(reponse));
|
||||
}
|
||||
|
||||
return ApiFile(
|
||||
bytes: reponse.bodyBytes,
|
||||
fileName: _fileName(reponse, fallbackFileName),
|
||||
contentType:
|
||||
reponse.headers["content-type"] ?? "application/octet-stream",
|
||||
);
|
||||
}
|
||||
|
||||
static Future<dynamic> post(
|
||||
String chemin,
|
||||
Map<String, dynamic> body, {
|
||||
@@ -116,4 +160,15 @@ class ApiClient {
|
||||
}
|
||||
return "Erreur ${reponse.statusCode}";
|
||||
}
|
||||
|
||||
static String _fileName(http.Response reponse, String fallback) {
|
||||
final disposition = reponse.headers["content-disposition"];
|
||||
if (disposition == null) return fallback;
|
||||
|
||||
final match = RegExp(
|
||||
"filename=\"?([^\";]+)\"?",
|
||||
caseSensitive: false,
|
||||
).firstMatch(disposition);
|
||||
return match?.group(1) ?? fallback;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,12 @@ class ResponsableService {
|
||||
static Future<List<Map<String, dynamic>>> historique() =>
|
||||
_liste("/responsable/historique");
|
||||
|
||||
static Future<ApiFile> exporterHistorique() => ApiClient.getFile(
|
||||
"/responsable/historique/export.csv",
|
||||
fallbackFileName: "historique-responsable.csv",
|
||||
utilisateurEmail: _email,
|
||||
);
|
||||
|
||||
static Future<int> marquerNotificationsLues() async {
|
||||
final reponse = await ApiClient.patch(
|
||||
"/responsable/notifications/lu-toutes",
|
||||
|
||||
Reference in New Issue
Block a user