feat(#135): mode édition dossier (PATCH fiche, co-parent, enfants).
Wizard edit famille/AM depuis la liste Dossiers ; save parents + co-parent ; enfants existants en PATCH (photo multipart) sans POST doublon. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -525,17 +525,58 @@ class UserService {
|
||||
return enfant.copyWith(parentLinks: enriched);
|
||||
}
|
||||
|
||||
/// Mise à jour enfant. Avec [photoBytes] : multipart (champ `photo`), sinon JSON.
|
||||
static Future<EnfantAdminModel> updateEnfant({
|
||||
required String enfantId,
|
||||
required Map<String, dynamic> body,
|
||||
List<int>? photoBytes,
|
||||
String? photoFilename,
|
||||
}) async {
|
||||
final response = await http.patch(
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.enfants}/$enfantId'),
|
||||
headers: await _headers(),
|
||||
body: jsonEncode(body),
|
||||
);
|
||||
final id = enfantId.trim();
|
||||
if (id.isEmpty) {
|
||||
throw Exception('Identifiant enfant manquant.');
|
||||
}
|
||||
final hasPhoto = photoBytes != null && photoBytes.isNotEmpty;
|
||||
final http.Response response;
|
||||
if (hasPhoto) {
|
||||
final token = await TokenService.getToken();
|
||||
final req = http.MultipartRequest(
|
||||
'PATCH',
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.enfants}/$id'),
|
||||
);
|
||||
req.headers['Accept'] = 'application/json';
|
||||
if (token != null) {
|
||||
req.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
body.forEach((key, value) {
|
||||
if (value == null) return;
|
||||
req.fields[key] = value is bool
|
||||
? (value ? 'true' : 'false')
|
||||
: value.toString();
|
||||
});
|
||||
final name = (photoFilename ?? '').trim();
|
||||
final filename = name.isNotEmpty ? name : 'photo.jpg';
|
||||
req.files.add(
|
||||
http.MultipartFile.fromBytes(
|
||||
'photo',
|
||||
photoBytes,
|
||||
filename: filename,
|
||||
contentType: _imageMediaType(filename, photoBytes),
|
||||
),
|
||||
);
|
||||
final streamed = await req.send();
|
||||
response = await http.Response.fromStream(streamed);
|
||||
} else {
|
||||
response = await http.patch(
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.enfants}/$id'),
|
||||
headers: await _headers(),
|
||||
body: jsonEncode(body),
|
||||
);
|
||||
}
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception(_extractErrorMessage(response.body, 'Erreur mise à jour enfant'));
|
||||
throw Exception(
|
||||
_extractErrorMessage(response.body, 'Erreur mise à jour enfant'),
|
||||
);
|
||||
}
|
||||
final enfant = EnfantAdminModel.fromJson(
|
||||
jsonDecode(response.body) as Map<String, dynamic>,
|
||||
@@ -645,6 +686,57 @@ class UserService {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/// Ajout d’un co-parent sur foyer mono-parent (staff, #135).
|
||||
/// `POST /parents/:pivotUserId/co-parent` — succès 201.
|
||||
static Future<Map<String, dynamic>> addCoParent(
|
||||
String pivotUserId, {
|
||||
required Map<String, dynamic> body,
|
||||
}) async {
|
||||
final id = pivotUserId.trim();
|
||||
if (id.isEmpty) {
|
||||
throw Exception('Identifiant du parent pivot manquant.');
|
||||
}
|
||||
final http.Response response;
|
||||
try {
|
||||
response = await http.post(
|
||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.parents}/$id/co-parent'),
|
||||
headers: await _headers(),
|
||||
body: jsonEncode(body),
|
||||
);
|
||||
} on http.ClientException {
|
||||
throw Exception(
|
||||
'Connexion au serveur impossible. Vérifiez votre réseau puis réessayez.',
|
||||
);
|
||||
}
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
if (response.body.trim().isEmpty) return <String, dynamic>{};
|
||||
try {
|
||||
final decoded = jsonDecode(response.body);
|
||||
if (decoded is Map) {
|
||||
return Map<String, dynamic>.from(decoded);
|
||||
}
|
||||
} catch (_) {}
|
||||
return <String, dynamic>{};
|
||||
}
|
||||
|
||||
final message = _extractErrorMessage(
|
||||
response.body,
|
||||
'Erreur ajout co-parent',
|
||||
);
|
||||
if (response.statusCode == 409) {
|
||||
throw Exception(
|
||||
message.isNotEmpty ? message : 'Conflit : e-mail déjà utilisé.',
|
||||
);
|
||||
}
|
||||
if (response.statusCode == 400) {
|
||||
throw Exception(
|
||||
message.isNotEmpty ? message : 'Données invalides (400).',
|
||||
);
|
||||
}
|
||||
throw Exception(message);
|
||||
}
|
||||
|
||||
/// Création dossier famille actif côté staff (#129).
|
||||
/// `POST /parents/dossier` — body aligné sur register parent complet.
|
||||
/// Succès 201 : dossier actif + `numero_dossier` (mail MDP côté serveur, par parent créé).
|
||||
|
||||
Reference in New Issue
Block a user