- Dossiers unifiés #119, pending-families enrichi, validation admin (wizards) - Front: modèles dossier_unifie / pending_family, NIR, auth - Migrations dossier_famille, scripts de test API - Résolution conflits: parents.*, docs tickets, auth_service, nir_utils Made-with: Cursor
131 lines
3.9 KiB
Dart
131 lines
3.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'admin_detail_modal.dart';
|
|
|
|
/// Bloc type formulaire (titre de section + champs read-only) pour les modales de validation.
|
|
/// [rowLayout] : même disposition que la création de compte, ex. [2, 2, 1, 2] = ligne de 2, ligne de 2, plein largeur, ligne de 2.
|
|
/// [rowFlex] : flex par index de ligne (optionnel). Ex. {3: [2, 5]} = 4e ligne : code postal étroit (2), ville large (5).
|
|
class ValidationDetailSection extends StatelessWidget {
|
|
final String title;
|
|
final List<AdminDetailField> fields;
|
|
|
|
/// Nombre de champs par ligne (1 = plein largeur, 2 = deux côte à côte). Ex. [2, 2, 1, 2] pour identité.
|
|
final List<int>? rowLayout;
|
|
|
|
/// Flex par ligne (index de ligne -> [flex1, flex2, ...]). Ex. {3: [2, 5]} pour Code postal | Ville.
|
|
final Map<int, List<int>>? rowFlex;
|
|
|
|
const ValidationDetailSection({
|
|
super.key,
|
|
required this.title,
|
|
required this.fields,
|
|
this.rowLayout,
|
|
this.rowFlex,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final layout = rowLayout ?? List.filled(fields.length, 1);
|
|
int index = 0;
|
|
int rowIndex = 0;
|
|
final rows = <Widget>[];
|
|
for (final count in layout) {
|
|
if (index >= fields.length) break;
|
|
final rowFields = fields.skip(index).take(count).toList();
|
|
index += count;
|
|
if (rowFields.isEmpty) continue;
|
|
final flexForRow = rowFlex?[rowIndex];
|
|
rowIndex++;
|
|
if (count == 1) {
|
|
rows.add(Padding(
|
|
padding: const EdgeInsets.only(bottom: 12),
|
|
child: _buildFieldCell(rowFields.first),
|
|
));
|
|
} else {
|
|
rows.add(Padding(
|
|
padding: const EdgeInsets.only(bottom: 12),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
for (int i = 0; i < rowFields.length; i++) ...[
|
|
if (i > 0) const SizedBox(width: 16),
|
|
Expanded(
|
|
flex: (flexForRow != null && i < flexForRow.length)
|
|
? flexForRow[i]
|
|
: 1,
|
|
child: _buildFieldCell(rowFields[i]),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
));
|
|
}
|
|
}
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
title,
|
|
style: const TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
...rows,
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildFieldCell(AdminDetailField field) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
field.label,
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.grey.shade700,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
ValidationReadOnlyField(value: field.value),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Champ texte en lecture seule, style formulaire (fond gris léger, bordure). Réutilisable en éditable plus tard.
|
|
class ValidationReadOnlyField extends StatelessWidget {
|
|
final String value;
|
|
final int? maxLines;
|
|
|
|
const ValidationReadOnlyField({
|
|
super.key,
|
|
required this.value,
|
|
this.maxLines = 1,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade50,
|
|
borderRadius: BorderRadius.circular(6),
|
|
border: Border.all(color: Colors.grey.shade300),
|
|
),
|
|
child: Text(
|
|
value,
|
|
style: const TextStyle(color: Colors.black87, fontSize: 14),
|
|
maxLines: maxLines,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
);
|
|
}
|
|
}
|