feat(admin): panneau Paramètres - sauvegarde config + test SMTP
- Onglet Paramètres dans l'admin avec 3 sections (Email, Personnalisation, Avancé) - Service ConfigurationService (GET config, PATCH bulk, POST test-smtp) - Bouton Sauvegarder et bouton Tester SMTP (sauvegarde avant test) - Endpoints api_config pour configuration Closes #15 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,6 +14,13 @@ class ApiConfig {
|
||||
static const String userProfile = '/users/profile';
|
||||
static const String userChildren = '/users/children';
|
||||
|
||||
// Configuration (admin)
|
||||
static const String configuration = '/configuration';
|
||||
static const String configurationSetupStatus = '/configuration/setup/status';
|
||||
static const String configurationSetupComplete = '/configuration/setup/complete';
|
||||
static const String configurationTestSmtp = '/configuration/test-smtp';
|
||||
static const String configurationBulk = '/configuration/bulk';
|
||||
|
||||
// Dashboard endpoints
|
||||
static const String dashboard = '/dashboard';
|
||||
static const String events = '/events';
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
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;
|
||||
throw Exception(err['message'] ?? '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;
|
||||
if (response.statusCode == 200 && data['success'] == true) {
|
||||
return data['message'] as String? ?? 'Test SMTP réussi.';
|
||||
}
|
||||
throw Exception(data['error'] ?? data['message'] ?? 'É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;
|
||||
throw Exception(err['message'] ?? 'Erreur finalisation configuration');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user