petitspas/frontend/lib/services/configuration_service.dart
Julien Martin 31857ec891 docs(#14): note back config/setup + frontend parsing erreurs
- docs/14_NOTE-BACKEND-CONFIG-SETUP.md : modifs à faire côté back (UUID system)
- configuration_service : parsing défensif des réponses d'erreur (évite JSNull)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 16:10:04 +01:00

143 lines
4.9 KiB
Dart

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'api/api_config.dart';
import 'api/tokenService.dart';
/// Réponse GET /configuration (liste complète)
class ConfigItem {
final String cle;
final String? valeur;
final String type;
final String? categorie;
final String? description;
ConfigItem({
required this.cle,
this.valeur,
required this.type,
this.categorie,
this.description,
});
factory ConfigItem.fromJson(Map<String, dynamic> json) {
return ConfigItem(
cle: json['cle'] as String,
valeur: json['valeur'] as String?,
type: json['type'] as String? ?? 'string',
categorie: json['categorie'] as String?,
description: json['description'] as String?,
);
}
}
/// Réponse GET /configuration/:category (objet clé -> { value, type, description })
class ConfigValueItem {
final dynamic value;
final String type;
final String? description;
ConfigValueItem({required this.value, required this.type, this.description});
factory ConfigValueItem.fromJson(Map<String, dynamic> json) {
return ConfigValueItem(
value: json['value'],
type: json['type'] as String? ?? 'string',
description: json['description'] as String?,
);
}
}
class ConfigurationService {
static Future<Map<String, String>> _headers() async {
final token = await TokenService.getToken();
return token != null
? ApiConfig.authHeaders(token)
: Map<String, String>.from(ApiConfig.headers);
}
/// GET /api/v1/configuration/setup/status
static Future<bool> getSetupStatus() async {
final response = await http.get(
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.configurationSetupStatus}'),
headers: await _headers(),
);
if (response.statusCode != 200) return true;
final data = jsonDecode(response.body);
return data['data']?['setupCompleted'] as bool? ?? true;
}
/// GET /api/v1/configuration (toutes les configs)
static Future<List<ConfigItem>> getAll() async {
final response = await http.get(
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.configuration}'),
headers: await _headers(),
);
if (response.statusCode != 200) {
throw Exception(
(jsonDecode(response.body) as Map)['message'] ?? 'Erreur chargement configuration',
);
}
final data = jsonDecode(response.body);
final list = data['data'] as List<dynamic>? ?? [];
return list.map((e) => ConfigItem.fromJson(e as Map<String, dynamic>)).toList();
}
/// GET /api/v1/configuration/:category
static Future<Map<String, ConfigValueItem>> getByCategory(String category) async {
final response = await http.get(
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.configuration}/$category'),
headers: await _headers(),
);
if (response.statusCode != 200) {
throw Exception(
(jsonDecode(response.body) as Map)['message'] ?? 'Erreur chargement configuration',
);
}
final data = jsonDecode(response.body);
final map = data['data'] as Map<String, dynamic>? ?? {};
return map.map((k, v) => MapEntry(k, ConfigValueItem.fromJson(v as Map<String, dynamic>)));
}
/// PATCH /api/v1/configuration/bulk
static Future<void> updateBulk(Map<String, dynamic> body) async {
final response = await http.patch(
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.configurationBulk}'),
headers: await _headers(),
body: jsonEncode(body),
);
if (response.statusCode != 200) {
final err = jsonDecode(response.body) as Map<String, dynamic>?;
final msg = err != null ? (err['message'] as String? ?? err['error'] as String?) : null;
throw Exception(msg ?? 'Erreur lors de la sauvegarde');
}
}
/// POST /api/v1/configuration/test-smtp
static Future<String> testSmtp(String testEmail) async {
final response = await http.post(
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.configurationTestSmtp}'),
headers: await _headers(),
body: jsonEncode({'testEmail': testEmail}),
);
final data = jsonDecode(response.body) as Map<String, dynamic>?;
if (response.statusCode == 200 && (data?['success'] == true)) {
return data!['message'] as String? ?? 'Test SMTP réussi.';
}
final msg = data != null ? (data['error'] as String? ?? data['message'] as String?) : null;
throw Exception(msg ?? 'Échec du test SMTP');
}
/// POST /api/v1/configuration/setup/complete (après première config)
static Future<void> completeSetup() async {
final response = await http.post(
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.configurationSetupComplete}'),
headers: await _headers(),
);
if (response.statusCode != 200) {
final err = jsonDecode(response.body) as Map<String, dynamic>?;
final msg = err != null ? (err['message'] as String? ?? err['error'] as String?) : null;
throw Exception(msg ?? 'Erreur finalisation configuration');
}
}
}