fix(vacaciones): edit and delete vacation ranges
Vacaciones ranges could be created but never edited or removed -- EstadoAlarmas already had crearRangoVacaciones/eliminarRangoVacaciones with no UI affordance reaching them, and no update path at all. Add EstadoAlarmas.editarRangoVacaciones and wire tap-to-edit / swipe-to-delete (with confirmation) onto every range card, mirroring the alarm list's own Dismissible + confirm-dialog pattern exactly. This covers the active-range hero too: a freshly created range is active immediately and only ever renders there, never in the scheduled/past lists, so it needed the same affordances or a user's very first range could never be fixed.
This commit is contained in:
@@ -445,4 +445,173 @@ void main() {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('issue 1 (feedback-pruebas): editar y eliminar rangos', () {
|
||||
testWidgets(
|
||||
'tocar la tarjeta de un rango programado abre el editor precargado '
|
||||
'con su nombre y fechas',
|
||||
(tester) async {
|
||||
final estado = await _crearEstado(
|
||||
vacaciones: [
|
||||
RangoVacaciones(
|
||||
id: 'f2',
|
||||
nombre: 'Verano',
|
||||
inicio: _hoyDia.add(const Duration(days: 20)),
|
||||
fin: _hoyDia.add(const Duration(days: 25)),
|
||||
),
|
||||
],
|
||||
);
|
||||
addTearDown(estado.dispose);
|
||||
|
||||
await tester.pumpWidget(_buildScreen(estado));
|
||||
await _pumpEstable(tester);
|
||||
final l10n = AppLocalizations.of(
|
||||
tester.element(find.byType(PantallaVacaciones)),
|
||||
);
|
||||
|
||||
await tester.tap(find.byKey(const ValueKey('vacaciones-tarjeta-f2')));
|
||||
await _pumpEstable(tester);
|
||||
|
||||
expect(find.text(l10n.editVacationRangeTitle), findsOneWidget);
|
||||
// Scoped to the TextField specifically -- the original card's OWN
|
||||
// "Verano" label is still (offstage, behind the modal) in the tree,
|
||||
// so a bare `find.text('Verano')` would ambiguously match both.
|
||||
expect(find.widgetWithText(TextField, 'Verano'), findsOneWidget);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'guardar el editor abierto por tap actualiza el rango existente (no '
|
||||
'crea uno nuevo)',
|
||||
(tester) async {
|
||||
final estado = await _crearEstado(
|
||||
vacaciones: [
|
||||
RangoVacaciones(
|
||||
id: 'f2',
|
||||
nombre: 'Verano',
|
||||
inicio: _hoyDia.add(const Duration(days: 20)),
|
||||
fin: _hoyDia.add(const Duration(days: 25)),
|
||||
),
|
||||
],
|
||||
);
|
||||
addTearDown(estado.dispose);
|
||||
|
||||
await tester.pumpWidget(_buildScreen(estado));
|
||||
await _pumpEstable(tester);
|
||||
final l10n = AppLocalizations.of(
|
||||
tester.element(find.byType(PantallaVacaciones)),
|
||||
);
|
||||
|
||||
await tester.tap(find.byKey(const ValueKey('vacaciones-tarjeta-f2')));
|
||||
await _pumpEstable(tester);
|
||||
|
||||
await tester.enterText(find.byType(TextField), 'Verano renombrado');
|
||||
final boton = tester.widget<FilledButton>(
|
||||
find.widgetWithText(FilledButton, l10n.saveRangeAction),
|
||||
);
|
||||
boton.onPressed!();
|
||||
await _pumpEstable(tester);
|
||||
|
||||
expect(estado.vacaciones, hasLength(1));
|
||||
expect(estado.vacaciones.single.id, 'f2');
|
||||
expect(estado.vacaciones.single.nombre, 'Verano renombrado');
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'deslizar la tarjeta de un rango pide confirmacion; cancelar la '
|
||||
'conserva y confirmar la elimina',
|
||||
(tester) async {
|
||||
final estado = await _crearEstado(
|
||||
vacaciones: [
|
||||
RangoVacaciones(
|
||||
id: 'f2',
|
||||
nombre: 'Verano',
|
||||
inicio: _hoyDia.add(const Duration(days: 20)),
|
||||
fin: _hoyDia.add(const Duration(days: 25)),
|
||||
),
|
||||
],
|
||||
);
|
||||
addTearDown(estado.dispose);
|
||||
|
||||
await tester.pumpWidget(_buildScreen(estado));
|
||||
await _pumpEstable(tester);
|
||||
final l10n = AppLocalizations.of(
|
||||
tester.element(find.byType(PantallaVacaciones)),
|
||||
);
|
||||
|
||||
// Cancelar: el rango se conserva.
|
||||
await tester.drag(
|
||||
find.byKey(const ValueKey('vacaciones-tarjeta-f2')),
|
||||
const Offset(-600, 0),
|
||||
);
|
||||
await _pumpEstable(tester);
|
||||
expect(find.text(l10n.vacationDeleteConfirmTitle), findsOneWidget);
|
||||
await tester.tap(find.text(l10n.cancelAction));
|
||||
await _pumpEstable(tester);
|
||||
expect(estado.vacaciones, hasLength(1));
|
||||
|
||||
// Confirmar: el rango se elimina.
|
||||
await tester.drag(
|
||||
find.byKey(const ValueKey('vacaciones-tarjeta-f2')),
|
||||
const Offset(-600, 0),
|
||||
);
|
||||
await _pumpEstable(tester);
|
||||
expect(find.text(l10n.vacationDeleteConfirmTitle), findsOneWidget);
|
||||
await tester.tap(find.text(l10n.deleteAction));
|
||||
await _pumpEstable(tester);
|
||||
|
||||
expect(estado.vacaciones, isEmpty);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'el rango ACTIVO (mostrado en el hero) tambien se puede editar (tap) '
|
||||
'y eliminar (swipe) -- un rango recien creado siempre esta activo y '
|
||||
'nunca aparece en las listas programado/pasado',
|
||||
(tester) async {
|
||||
final estado = await _crearEstado(
|
||||
vacaciones: [
|
||||
RangoVacaciones(
|
||||
id: 'v1',
|
||||
nombre: 'Julio activo',
|
||||
inicio: _hoyDia.subtract(const Duration(days: 3)),
|
||||
fin: _hoyDia.add(const Duration(days: 5)),
|
||||
),
|
||||
],
|
||||
);
|
||||
addTearDown(estado.dispose);
|
||||
|
||||
await tester.pumpWidget(_buildScreen(estado));
|
||||
await _pumpEstable(tester);
|
||||
final l10n = AppLocalizations.of(
|
||||
tester.element(find.byType(PantallaVacaciones)),
|
||||
);
|
||||
|
||||
await tester.tap(find.byKey(const ValueKey('vacaciones-tarjeta-v1')));
|
||||
await _pumpEstable(tester);
|
||||
expect(find.text(l10n.editVacationRangeTitle), findsOneWidget);
|
||||
// Scoped to the TextField specifically -- the hero's OWN "Julio
|
||||
// activo" label is still (offstage, behind the modal) in the tree.
|
||||
expect(find.widgetWithText(TextField, 'Julio activo'), findsOneWidget);
|
||||
// Dismiss the editor sheet (no explicit close button -- same as the
|
||||
// pre-existing "Anadir rango" sheet, dismissible via the standard
|
||||
// modal-bottom-sheet Navigator.pop) before interacting with the
|
||||
// list underneath it.
|
||||
Navigator.of(tester.element(find.byType(PantallaVacaciones))).pop();
|
||||
await _pumpEstable(tester);
|
||||
|
||||
await tester.drag(
|
||||
find.byKey(const ValueKey('vacaciones-tarjeta-v1')),
|
||||
const Offset(-600, 0),
|
||||
);
|
||||
await _pumpEstable(tester);
|
||||
await tester.tap(find.text(l10n.deleteAction));
|
||||
await _pumpEstable(tester);
|
||||
|
||||
expect(estado.vacaciones, isEmpty);
|
||||
expect(find.text(l10n.vacationNoActiveRangeHint), findsOneWidget);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user