Skip to content

Instantly share code, notes, and snippets.

@gu1llermo
Created September 9, 2025 16:08
Show Gist options
  • Select an option

  • Save gu1llermo/810c899b991a835c6f92406ad4188dac to your computer and use it in GitHub Desktop.

Select an option

Save gu1llermo/810c899b991a835c6f92406ad4188dac to your computer and use it in GitHub Desktop.
Provider para manejar el estado del formulario (Riverpod con anotaciones más Debounce)
import 'package:flutter/material.dart';
import 'package:homerun_club/core/mixins/debounce_mixin.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../../../../core/constants/categories.dart';
import '../../../../shared/inputs/input_form.dart';
import '../../../../shared/inputs/inputs.dart';
import '../../../domain/entities/entities.dart';
import 'admin_agregar_atletas_provider.dart';
part 'admin_nuevo_atleta_provider.g.dart';
class AdminNuevoAtletaState {
final bool isLoading;
final bool hasError;
final String statusMessage;
// Entradas
final SimpleString nombreAtleta;
final SimpleString representante;
final PhoneInput celular;
final FechaInput fechaNacimiento;
final FechaInput fechaInscripcion;
final EquipoInput equipo;
final SimpleStringWOValidation delegado;
final SimpleStringWOValidation tecnico;
final SimpleStringWOValidation manager;
bool get isValidForm => InputForm.isValidInputs([
nombreAtleta,
representante,
celular,
fechaNacimiento,
fechaInscripcion,
equipo,
]);
AdminNuevoAtletaState({
this.isLoading = false,
this.hasError = false,
this.statusMessage = '',
required this.nombreAtleta,
required this.representante,
required this.celular,
required this.fechaNacimiento,
required this.fechaInscripcion,
required this.equipo,
required this.delegado,
required this.tecnico,
required this.manager,
});
AdminNuevoAtletaState copyWith({
bool? isLoading,
bool? hasError,
String? statusMessage,
SimpleString? nombreAtleta,
SimpleString? representante,
PhoneInput? celular,
FechaInput? fechaNacimiento,
FechaInput? fechaInscripcion,
EquipoInput? equipo,
SimpleStringWOValidation? delegado,
SimpleStringWOValidation? tecnico,
SimpleStringWOValidation? manager,
}) => AdminNuevoAtletaState(
isLoading: isLoading ?? this.isLoading,
hasError: hasError ?? this.hasError,
statusMessage: statusMessage ?? this.statusMessage,
nombreAtleta: nombreAtleta ?? this.nombreAtleta,
representante: representante ?? this.representante,
celular: celular ?? this.celular,
fechaNacimiento: fechaNacimiento ?? this.fechaNacimiento,
fechaInscripcion: fechaInscripcion ?? this.fechaInscripcion,
equipo: equipo ?? this.equipo,
delegado: delegado ?? this.delegado,
tecnico: tecnico ?? this.tecnico,
manager: manager ?? this.manager,
);
}
@Riverpod(keepAlive: true, dependencies: [AdminAgregarAtletasNotifier])
class AdminNuevoAtletaNotifier extends _$AdminNuevoAtletaNotifier
with DebounceMixin {
TextEditingController? _nombreAtletaController;
TextEditingController? _representanteController;
TextEditingController? _celularController;
TextEditingController? _delegadoController;
TextEditingController? _tecnicoController;
TextEditingController? _managerController;
@override
AdminNuevoAtletaState build() {
_nombreAtletaController = TextEditingController();
_nombreAtletaController!.addListener(_nombreAtletaListener);
_representanteController = TextEditingController();
_representanteController!.addListener(_representanteListener);
_celularController = TextEditingController();
_celularController!.addListener(_celularListener);
_delegadoController = TextEditingController();
_tecnicoController = TextEditingController();
_managerController = TextEditingController();
ref.onDispose(() {
_nombreAtletaController?.removeListener(_nombreAtletaListener);
_nombreAtletaController?.dispose();
_representanteController?.removeListener(_representanteListener);
_representanteController?.dispose();
_celularController?.removeListener(_celularListener);
_celularController?.dispose();
_delegadoController?.dispose();
_tecnicoController?.dispose();
_managerController?.dispose();
cancelAllDebouncers();
});
return AdminNuevoAtletaState(
nombreAtleta: SimpleString(
value: '',
controller: _nombreAtletaController,
),
representante: SimpleString(
value: '',
controller: _representanteController,
),
celular: PhoneInput(value: '', controller: _celularController),
fechaNacimiento: const FechaInput(value: null),
fechaInscripcion: const FechaInput(value: null),
equipo: const EquipoInput(value: null),
delegado: SimpleStringWOValidation(
value: '',
controller: _delegadoController,
),
tecnico: SimpleStringWOValidation(
value: '',
controller: _tecnicoController,
),
manager: SimpleStringWOValidation(
value: '',
controller: _managerController,
),
);
}
void refreshState() {
state = state.copyWith();
}
void onNombreAtletaChanged() {
final nombreAtleta = state.nombreAtleta;
final value = nombreAtleta.controller?.text ?? '';
final nombreAtletaChanged = nombreAtleta.onChanged(value);
state = state.copyWith(nombreAtleta: nombreAtletaChanged);
}
void _nombreAtletaListener() {
debounce('nombreAtleta', onNombreAtletaChanged);
}
void onNombreAtletaValidate() {
final nombreAtleta = state.nombreAtleta;
final nombreAtletaValidated = nombreAtleta.validate();
state = state.copyWith(nombreAtleta: nombreAtletaValidated);
}
void onRepresentanteChanged() {
final representante = state.representante;
final value = representante.controller?.text ?? '';
final representanteChanged = representante.onChanged(value);
state = state.copyWith(representante: representanteChanged);
}
void _representanteListener() {
debounce('representante', onRepresentanteChanged);
}
void onRepresentanteValidate() {
final representante = state.representante;
final representanteValidated = representante.validate();
state = state.copyWith(representante: representanteValidated);
}
void onCelularChanged() {
final celular = state.celular;
final value = celular.controller?.text ?? '';
final celularChanged = celular.onChanged(value);
state = state.copyWith(celular: celularChanged);
}
void _celularListener() {
debounce('celular', onCelularChanged);
}
void onCelularValidate() {
final celular = state.celular;
final celularValidated = celular.validate();
state = state.copyWith(celular: celularValidated);
}
void onFechaNacimientoChanged(DateTime? value) {
final fechaNacimiento = state.fechaNacimiento;
final fechaNacimientoChanged = fechaNacimiento.onChanged(value);
state = state.copyWith(fechaNacimiento: fechaNacimientoChanged);
}
void onFechaNacimientoValidate() {
final fechaNacimiento = state.fechaNacimiento;
final fechaNacimientoValidated = fechaNacimiento.validate();
state = state.copyWith(fechaNacimiento: fechaNacimientoValidated);
}
void onFechaInscripcionChanged(DateTime? value) {
final fechaInscripcion = state.fechaInscripcion;
final fechaInscripcionChanged = fechaInscripcion.onChanged(value);
state = state.copyWith(fechaInscripcion: fechaInscripcionChanged);
}
void onFechaInscripcionValidate() {
final fechaInscripcion = state.fechaInscripcion;
final fechaInscripcionValidated = fechaInscripcion.validate();
state = state.copyWith(fechaInscripcion: fechaInscripcionValidated);
}
void onEquipoChanged(Equipo? value) {
final equipo = state.equipo;
final equipoChanged = equipo.onChanged(value);
state = state.copyWith(equipo: equipoChanged);
}
void onEquipoValidate() {
final equipo = state.equipo;
final equipoValidated = equipo.validate();
state = state.copyWith(equipo: equipoValidated);
}
void validateInputs() {
onNombreAtletaValidate();
onRepresentanteValidate();
onCelularValidate();
onFechaNacimientoValidate();
onFechaInscripcionValidate();
onEquipoValidate();
}
Future<bool> onFormSubmit() async {
if (state.isLoading) return false;
state = state.copyWith(isLoading: true);
validateInputs();
if (!state.isValidForm) {
state = state.copyWith(isLoading: false);
return false;
}
// si llega aquí es porque todo está bien
try {
final atleta = AtletaEntity(
nombreAtleta: state.nombreAtleta.value,
fechaNacimiento: state.fechaNacimiento.value!,
equipo: state.equipo.value!,
nombreRepresentante: state.representante.value,
celular: int.parse(
'${state.celular.countryCode}${state.celular.value}',
),
fechaInicio: state.fechaInscripcion.value!,
manager: state.manager.controller?.text ?? '',
tecnico: state.tecnico.controller?.text ?? '',
delegado: state.delegado.controller?.text ?? '',
pagos: [],
);
await ref
.read(adminAgregarAtletasNotifierProvider.notifier)
.addAtleta(atleta);
ref.invalidateSelf();
return true;
} catch (e, stackTrace) {
print('$e, $stackTrace');
await setError(e.toString());
return false;
} finally {
state = state.copyWith(isLoading: false);
}
}
Future<void> setError(String error) async {
state = state.copyWith(
statusMessage: error,
isLoading: false,
hasError: true,
);
await Future.delayed(const Duration(seconds: 3));
state = state.copyWith(statusMessage: '', hasError: false);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment