feat(#95): implémenter la gestion Relais admin et le rattachement gestionnaire
Ajoute la section Paramètres territoriaux avec CRUD Relais, modale de saisie structurée, états visuels harmonisés, et rattachement d'un relais principal aux gestionnaires via l'API. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -18,11 +18,13 @@ class ApiConfig {
|
||||
static const String gestionnaires = '/gestionnaires';
|
||||
static const String parents = '/parents';
|
||||
static const String assistantesMaternelles = '/assistantes-maternelles';
|
||||
static const String relais = '/relais';
|
||||
|
||||
// Configuration (admin)
|
||||
static const String configuration = '/configuration';
|
||||
static const String configurationSetupStatus = '/configuration/setup/status';
|
||||
static const String configurationSetupComplete = '/configuration/setup/complete';
|
||||
static const String configurationSetupComplete =
|
||||
'/configuration/setup/complete';
|
||||
static const String configurationTestSmtp = '/configuration/test-smtp';
|
||||
static const String configurationBulk = '/configuration/bulk';
|
||||
|
||||
@@ -33,14 +35,14 @@ class ApiConfig {
|
||||
static const String conversations = '/conversations';
|
||||
static const String notifications = '/notifications';
|
||||
|
||||
// Headers
|
||||
// Headers
|
||||
static Map<String, String> get headers => {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
};
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
};
|
||||
|
||||
static Map<String, String> authHeaders(String token) => {
|
||||
...headers,
|
||||
'Authorization': 'Bearer $token',
|
||||
};
|
||||
}
|
||||
...headers,
|
||||
'Authorization': 'Bearer $token',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:p_tits_pas/models/relais_model.dart';
|
||||
import 'package:p_tits_pas/services/api/api_config.dart';
|
||||
import 'package:p_tits_pas/services/api/tokenService.dart';
|
||||
|
||||
class RelaisService {
|
||||
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;
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
static Future<List<RelaisModel>> getRelais() async {
|
||||
final response = await http.get(
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.relais}'),
|
||||
headers: await _headers(),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception(
|
||||
_extractError(response.body, 'Erreur chargement relais'),
|
||||
);
|
||||
}
|
||||
|
||||
final List<dynamic> data = jsonDecode(response.body);
|
||||
return data
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map(RelaisModel.fromJson)
|
||||
.toList();
|
||||
}
|
||||
|
||||
static Future<RelaisModel> createRelais(Map<String, dynamic> payload) async {
|
||||
final response = await http.post(
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.relais}'),
|
||||
headers: await _headers(),
|
||||
body: jsonEncode(payload),
|
||||
);
|
||||
|
||||
if (response.statusCode != 201 && response.statusCode != 200) {
|
||||
throw Exception(
|
||||
_extractError(response.body, 'Erreur création relais'),
|
||||
);
|
||||
}
|
||||
|
||||
return RelaisModel.fromJson(
|
||||
jsonDecode(response.body) as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
static Future<RelaisModel> updateRelais(
|
||||
String id,
|
||||
Map<String, dynamic> payload,
|
||||
) async {
|
||||
final response = await http.patch(
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.relais}/$id'),
|
||||
headers: await _headers(),
|
||||
body: jsonEncode(payload),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception(
|
||||
_extractError(response.body, 'Erreur mise à jour relais'),
|
||||
);
|
||||
}
|
||||
|
||||
return RelaisModel.fromJson(
|
||||
jsonDecode(response.body) as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
static Future<void> deleteRelais(String id) async {
|
||||
final response = await http.delete(
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.relais}/$id'),
|
||||
headers: await _headers(),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 204) {
|
||||
throw Exception(
|
||||
_extractError(response.body, 'Erreur suppression relais'),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,8 @@ class UserService {
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
final err = jsonDecode(response.body) as Map<String, dynamic>?;
|
||||
throw Exception(_toStr(err?['message']) ?? 'Erreur chargement gestionnaires');
|
||||
throw Exception(
|
||||
_toStr(err?['message']) ?? 'Erreur chargement gestionnaires');
|
||||
}
|
||||
|
||||
final List<dynamic> data = jsonDecode(response.body);
|
||||
@@ -53,7 +54,8 @@ class UserService {
|
||||
}
|
||||
|
||||
// Récupérer la liste des assistantes maternelles
|
||||
static Future<List<AssistanteMaternelleModel>> getAssistantesMaternelles() async {
|
||||
static Future<List<AssistanteMaternelleModel>>
|
||||
getAssistantesMaternelles() async {
|
||||
final response = await http.get(
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.assistantesMaternelles}'),
|
||||
headers: await _headers(),
|
||||
@@ -87,8 +89,27 @@ class UserService {
|
||||
.toList();
|
||||
}
|
||||
} catch (e) {
|
||||
print('Erreur chargement admins: $e');
|
||||
// On garde un fallback vide pour ne pas bloquer l'UI admin.
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
static Future<void> updateGestionnaireRelais({
|
||||
required String gestionnaireId,
|
||||
required String? relaisId,
|
||||
}) async {
|
||||
final response = await http.patch(
|
||||
Uri.parse(
|
||||
'${ApiConfig.baseUrl}${ApiConfig.gestionnaires}/$gestionnaireId'),
|
||||
headers: await _headers(),
|
||||
body: jsonEncode(<String, dynamic>{'relaisId': relaisId}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 204) {
|
||||
final err = jsonDecode(response.body) as Map<String, dynamic>?;
|
||||
throw Exception(
|
||||
_toStr(err?['message']) ?? 'Erreur rattachement relais au gestionnaire',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user