Files
petitspas/frontend/lib/widgets/dashboard/validation_dossier_modal.dart
jmartin 5b83102a59 feat(#152/#155): cleanup est_multiple + dashboard sans préfixe Admin (squash develop).
Suppression complète grossesse multiple / est_multiple (BDD, API, front).
Rename option C : widgets partagés et panels staff sous widgets/dashboard/,
AdminManagementWidget seul restant dans widgets/admin/.
2026-09-14 12:52:22 +02:00

201 lines
5.9 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:p_tits_pas/models/dossier_unifie.dart';
import 'package:p_tits_pas/services/user_service.dart';
import 'package:p_tits_pas/widgets/dashboard/am_dossier_wizard.dart';
import 'package:p_tits_pas/widgets/dashboard/parent_dossier_wizard.dart';
import 'package:p_tits_pas/widgets/dashboard/validation_am_wizard.dart';
import 'package:p_tits_pas/widgets/dashboard/validation_family_wizard.dart';
/// Modale (dialog) : charge le dossier par numéro puis affiche le wizard AM ou Famille.
/// Ticket #107 / #119 (review), #135 (`openAsEdit`).
class ValidationDossierModal extends StatefulWidget {
final String numeroDossier;
final VoidCallback onClose;
final VoidCallback? onSuccess;
/// Liste Dossiers actifs → mode edit (#135). Pending reste en review (défaut).
final bool openAsEdit;
const ValidationDossierModal({
super.key,
required this.numeroDossier,
required this.onClose,
this.onSuccess,
this.openAsEdit = false,
});
@override
State<ValidationDossierModal> createState() => _ValidationDossierModalState();
}
class _ValidationDossierModalState extends State<ValidationDossierModal> {
bool _loading = true;
String? _error;
DossierUnifie? _dossier;
int? _stepIndex;
int? _stepTotal;
void _onStepChanged(int step, int total) {
// step = 0-based dans les wizards, affichage 1-based dans l'en-tête.
if (!mounted) return;
setState(() {
_stepIndex = step;
_stepTotal = total;
});
}
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
setState(() {
_loading = true;
_error = null;
_dossier = null;
_stepIndex = null;
_stepTotal = null;
});
try {
final d = await UserService.getDossier(widget.numeroDossier);
if (!mounted) return;
setState(() {
_dossier = d;
_loading = false;
});
} catch (e) {
if (!mounted) return;
setState(() {
_error = e is Exception
? e.toString().replaceFirst('Exception: ', '')
: 'Erreur inconnue';
_loading = false;
});
}
}
void _onSuccess() {
widget.onSuccess?.call();
// La modale est fermée par lappelant dans onSuccess (Navigator.pop).
}
/// Largeur modale = 1,5 × 620.
static const double _modalWidth = 930; // 620 * 1.5
double get _bodyHeight {
final d = _dossier;
if (d != null && d.isAm) return AmDossierWizard.shellBodyHeight;
// Aligné create (#129) / edit (#135) — évite overflow IdentityBlock (8px).
return ParentDossierWizard.shellBodyHeight;
}
@override
Widget build(BuildContext context) {
final maxH = MediaQuery.of(context).size.height * 0.85;
final showStep =
_stepIndex != null && _stepTotal != null && (_stepTotal ?? 0) > 0;
return Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: _modalWidth, maxHeight: maxH),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(18, 18, 0, 12),
child: Text(
'Dossier ${widget.numeroDossier}',
style: const TextStyle(
fontSize: 18, fontWeight: FontWeight.w700),
),
),
const Spacer(),
if (showStep) ...[
Text(
'Étape ${(_stepIndex ?? 0) + 1}/${_stepTotal ?? 1}',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: Colors.black54,
fontStyle: FontStyle.italic,
),
),
const SizedBox(width: 8),
],
IconButton(
icon: const Icon(Icons.close),
onPressed: widget.onClose,
tooltip: 'Fermer',
),
],
),
const Divider(height: 1),
SizedBox(
height: _bodyHeight,
child: _buildBody(),
),
],
),
),
);
}
Widget _buildBody() {
if (_loading) {
return const Padding(
padding: EdgeInsets.all(48),
child: Center(child: CircularProgressIndicator()),
);
}
if (_error != null && _error!.isNotEmpty) {
return Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(_error!,
style: const TextStyle(color: Colors.red),
textAlign: TextAlign.center),
const SizedBox(height: 16),
ElevatedButton(onPressed: _load, child: const Text('Réessayer')),
const SizedBox(height: 8),
TextButton(onPressed: widget.onClose, child: const Text('Fermer')),
],
),
);
}
final d = _dossier!;
if (d.isAm) {
if (widget.openAsEdit) {
return AmDossierWizard.edit(
dossier: d.asAm,
onClose: widget.onClose,
onSuccess: _onSuccess,
onStepChanged: _onStepChanged,
);
}
return ValidationAmWizard(
dossier: d.asAm,
onClose: widget.onClose,
onSuccess: _onSuccess,
onStepChanged: _onStepChanged,
);
}
if (widget.openAsEdit) {
return ParentDossierWizard.edit(
dossier: d.asFamily,
onClose: widget.onClose,
onSuccess: _onSuccess,
onStepChanged: _onStepChanged,
);
}
return ValidationFamilyWizard(
dossier: d.asFamily,
onClose: widget.onClose,
onSuccess: _onSuccess,
onStepChanged: _onStepChanged,
);
}
}