Agrego frontend app
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:gimnasio_soma/features/turnos/data/repositories/turnos_repository_impl.dart';
|
||||
import 'package:gimnasio_soma/features/turnos/domain/entities/turno.dart';
|
||||
import 'package:gimnasio_soma/features/turnos/domain/repositories/turnos_repository.dart';
|
||||
|
||||
String _errorMessage(Object e) {
|
||||
if (e is PostgrestException) return e.message;
|
||||
return e.toString().replaceFirst('Exception: ', '');
|
||||
}
|
||||
|
||||
DateTime _normalizeWeekStart(DateTime d) {
|
||||
final monday = DateTime(d.year, d.month, d.day - (d.weekday - 1));
|
||||
return monday;
|
||||
}
|
||||
|
||||
final turnosRepositoryProvider = Provider<TurnosRepository>((ref) {
|
||||
return TurnosRepositoryImpl();
|
||||
});
|
||||
|
||||
final turnosProvider =
|
||||
StateNotifierProvider<TurnosNotifier, AsyncValue<SemanaTurnos?>>((ref) {
|
||||
return TurnosNotifier(ref.read(turnosRepositoryProvider));
|
||||
});
|
||||
|
||||
class TurnosNotifier extends StateNotifier<AsyncValue<SemanaTurnos?>> {
|
||||
final TurnosRepository _repository;
|
||||
DateTime? _currentWeek;
|
||||
|
||||
TurnosNotifier(this._repository) : super(const AsyncValue.data(null));
|
||||
|
||||
DateTime? get semanaActual => _currentWeek;
|
||||
|
||||
/// Carga la semana que contiene [referencia] (se normaliza al lunes).
|
||||
/// Si ya estamos en esa semana, no recarga (a menos que [force] sea true).
|
||||
Future<String?> cargarSemana(
|
||||
DateTime referencia, {
|
||||
bool force = false,
|
||||
}) async {
|
||||
final weekStart = _normalizeWeekStart(referencia);
|
||||
if (!force && _currentWeek == weekStart && state.value != null) {
|
||||
return null;
|
||||
}
|
||||
_currentWeek = weekStart;
|
||||
state = const AsyncValue.loading();
|
||||
try {
|
||||
final semana = await _repository.obtenerSemana(weekStart);
|
||||
if (_currentWeek != weekStart) return null; // semana cambió mientras cargaba
|
||||
state = AsyncValue.data(semana);
|
||||
return null;
|
||||
} catch (e, st) {
|
||||
if (_currentWeek != weekStart) return null;
|
||||
state = AsyncValue.error(e, st);
|
||||
return _errorMessage(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Refresca la semana actual en segundo plano, sin parpadeo: mantiene los
|
||||
/// datos visibles mientras recarga y solo los reemplaza cuando llegan. Evita
|
||||
/// el "corte" de volver a estado loading, que vaciaría la grilla a un spinner
|
||||
/// (se nota, por ejemplo, al cerrar el diálogo de inscriptos).
|
||||
Future<String?> refrescar() async {
|
||||
final week = _currentWeek;
|
||||
if (week == null) return null;
|
||||
try {
|
||||
final semana = await _repository.obtenerSemana(week);
|
||||
if (_currentWeek != week) return null; // semana cambió mientras cargaba
|
||||
state = AsyncValue.data(semana);
|
||||
return null;
|
||||
} catch (e) {
|
||||
if (_currentWeek != week) return null;
|
||||
// No pisamos los datos visibles con un error: los dejamos en pantalla y
|
||||
// devolvemos el mensaje para que la pantalla muestre un toast.
|
||||
return _errorMessage(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> crearTurnoManual({
|
||||
required DateTime fecha,
|
||||
required int actividadId,
|
||||
required String horaInicio,
|
||||
required String horaFin,
|
||||
required int capacidad,
|
||||
}) async {
|
||||
try {
|
||||
await _repository.crearTurnoManual(
|
||||
fecha: fecha,
|
||||
actividadId: actividadId,
|
||||
horaInicio: horaInicio,
|
||||
horaFin: horaFin,
|
||||
capacidad: capacidad,
|
||||
);
|
||||
await refrescar();
|
||||
return null;
|
||||
} catch (e) {
|
||||
return _errorMessage(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> limpiarAntiguos({int dias = 30}) async {
|
||||
try {
|
||||
final result =
|
||||
await _repository.limpiarTurnosAntiguos(diasAntiguedad: dias);
|
||||
final eliminados = result['turnos_eliminados'] ?? 0;
|
||||
return 'Se eliminaron $eliminados turnos antiguos';
|
||||
} catch (e) {
|
||||
return _errorMessage(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lista de reservas de un turno (incluye canceladas; filtrar en UI).
|
||||
final inscriptosTurnoProvider =
|
||||
FutureProvider.autoDispose.family<List<InscriptoTurno>, String>(
|
||||
(ref, turnoId) =>
|
||||
ref.read(turnosRepositoryProvider).obtenerInscriptos(turnoId),
|
||||
);
|
||||
|
||||
/// Cupo semanal del cliente para la fecha pedida (usados/disponibles/total).
|
||||
final estadoCupoProvider = FutureProvider.autoDispose
|
||||
.family<EstadoCupo, ({String clienteId, DateTime fecha})>(
|
||||
(ref, params) => ref.read(turnosRepositoryProvider).obtenerEstadoCupo(
|
||||
clienteId: params.clienteId,
|
||||
fecha: params.fecha,
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user