Affiche la file d’attention pastel (assets card_*_h) filtrée par couple courant, avec accept / refus motivé / ack. Co-authored-by: Cursor <cursoragent@cursor.com>
88 lines
2.7 KiB
Dart
88 lines
2.7 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:p_tits_pas/models/carte_bulle.dart';
|
|
import 'package:p_tits_pas/services/api/api_config.dart';
|
|
import 'package:p_tits_pas/services/api/tokenService.dart';
|
|
|
|
/// Accès API Cartes (file d'attention) — tickets #173 / #194.
|
|
/// - GET /cards?placementId=
|
|
/// - POST /cards/:id/respond
|
|
class CardsService {
|
|
static Future<Map<String, String>> _headers() async {
|
|
final token = await TokenService.getToken();
|
|
return token != null
|
|
? ApiConfig.authHeaders(token)
|
|
: Map<String, String>.from(ApiConfig.headers);
|
|
}
|
|
|
|
static String _extractError(String body, String fallback) {
|
|
try {
|
|
final decoded = jsonDecode(body);
|
|
if (decoded is Map<String, dynamic>) {
|
|
final message = decoded['message'];
|
|
if (message is String && message.trim().isNotEmpty) {
|
|
return message;
|
|
}
|
|
if (message is Map && message['message'] is String) {
|
|
return message['message'] as String;
|
|
}
|
|
}
|
|
} catch (_) {}
|
|
return fallback;
|
|
}
|
|
|
|
/// Feed de bulles pour l'utilisateur (filtré par couple / placement).
|
|
static Future<List<CarteBulle>> lister({String? placementId}) async {
|
|
final query = <String, String>{};
|
|
if (placementId != null && placementId.isNotEmpty) {
|
|
query['placementId'] = placementId;
|
|
}
|
|
final uri = Uri.parse(
|
|
'${ApiConfig.baseUrl}${ApiConfig.cards}',
|
|
).replace(queryParameters: query.isEmpty ? null : query);
|
|
|
|
final response = await http.get(uri, headers: await _headers());
|
|
if (response.statusCode != 200) {
|
|
throw Exception(
|
|
_extractError(response.body, 'Erreur chargement des cartes'),
|
|
);
|
|
}
|
|
|
|
final decoded = jsonDecode(response.body);
|
|
final list = (decoded is Map ? decoded['items'] as List? : null) ?? const [];
|
|
return list
|
|
.whereType<Map>()
|
|
.map((e) => CarteBulle.fromJson(Map<String, dynamic>.from(e)))
|
|
.toList();
|
|
}
|
|
|
|
/// Répondre : accept | refuse | ack.
|
|
static Future<CarteBulle> repondre({
|
|
required String cardId,
|
|
required String action,
|
|
String? comment,
|
|
}) async {
|
|
final response = await http.post(
|
|
Uri.parse(
|
|
'${ApiConfig.baseUrl}${ApiConfig.cards}/$cardId/respond',
|
|
),
|
|
headers: await _headers(),
|
|
body: jsonEncode({
|
|
'action': action,
|
|
if (comment != null && comment.trim().isNotEmpty)
|
|
'comment': comment.trim(),
|
|
}),
|
|
);
|
|
|
|
if (response.statusCode != 200) {
|
|
throw Exception(
|
|
_extractError(response.body, 'Erreur lors de la réponse'),
|
|
);
|
|
}
|
|
|
|
final decoded = jsonDecode(response.body);
|
|
return CarteBulle.fromJson(Map<String, dynamic>.from(decoded as Map));
|
|
}
|
|
}
|