Skip to main content

Overview

The system enforces multiple validation rules to ensure data integrity, prevent scheduling conflicts, and maintain business logic. This guide covers all validation rules implemented in the class scheduling system.

Time Limit Validation

18:30 End Time Rule

Critical Rule: Classes cannot end after 18:30 (6:30 PM)
This is one of the most important validation rules in the system.

Examples

// 60-minute class at 17:30 ends at 18:30 ✅
hora: "17:30"
duracion: 60
// End time: 18:30 (valid)

Implementation

validacionesClases.ts
export function validarHorarioLimite(
  hora: string,
  duracion: number,
): { esValido: boolean; mensaje: string } {
  const [horas, minutos] = hora.split(":").map(Number);
  const minutosInicio = horas * 60 + minutos;
  const minutosFin = minutosInicio + duracion;
  const LIMITE_MINUTOS = 18 * 60 + 30; // 18:30

  if (minutosFin > LIMITE_MINUTOS) {
    const horaFin = Math.floor(minutosFin / 60);
    const minFin = minutosFin % 60;
    return {
      esValido: false,
      mensaje: `La clase no puede terminar después de las 18:30. Con duración de ${duracion} minutos a las ${hora} terminaría a las ${horaFin}:${minFin.toString().padStart(2, "0")}.`,
    };
  }

  return { esValido: true, mensaje: "" };
}

Error Message

From the README:
Mensaje de error: “La clase no puede terminar después de las 18:30. Con duración de 60 minutos a las 18:00 terminaría a las 19:00.”
See: ~/workspace/source/README.md:202-203

Form Validation

ClaseForm.tsx
const { esValido: horarioOk, mensaje: mensajeHorario } =
  validarHorarioLimite(hora, duracion);
if (!horarioOk) {
  toast.error(mensajeHorario);
  return;
}
See: ~/workspace/source/src/components/forms/ClaseForm.tsx:237-242

Trial Class Validations

Rule 1: No Existing Classes

Students cannot have a trial class if they already have classes (scheduled or completed) in that specialty.
From the README:
Regla 1: Un alumno NO puede tener clase de prueba si ya tiene clases (programadas o completadas) de esa especialidad
See: ~/workspace/source/README.md:175

Rule 2: No Duplicate Trials

Students cannot repeat trial classes for the same specialty.
From the README:
Regla 2: Un alumno NO puede repetir clase de prueba de la misma especialidad
See: ~/workspace/source/README.md:177

Rule 3: Quota Exemption

Trial classes do not count toward the student’s monthly class quota.
From the README:
Regla 3: Las clases de prueba NO cuentan para la cuota mensual del alumno
See: ~/workspace/source/README.md:179

Implementation

ClaseForm.tsx
if (
  !clase &&
  esPruebaChecked &&
  tipoPrueba === "alumno_existente" &&
  alumno
) {
  const { esValido, mensaje } = validarClasePrueba(
    clases,
    alumno,
    especialidad as Clase["especialidad"],
    clase?.id,
  );
  if (!esValido) {
    toast.error(mensaje);
    return;
  }
}
See: ~/workspace/source/src/components/forms/ClaseForm.tsx:200-216

Edit Restriction Validations

Finalized Class Rule

Classes in COMPLETADA, INICIADA, or CANCELADA states cannot be edited or deleted.
From the README:
No se pueden editar clases con estado:
  • COMPLETADA
  • INICIADA
  • CANCELADA
Razón: Las clases finalizadas son registro histórico
See: ~/workspace/source/README.md:222-227

Implementation

validacionesClases.ts
export function puedeEditarClase(clase: Clase): boolean {
  const estadosNoEditables: EstadoClase[] = [
    "COMPLETADA",
    "INICIADA",
    "CANCELADA",
  ];
  return !estadosNoEditables.includes(clase.estado);
}

UI Indicators

Clases.tsx
<DropdownMenuItem
  onClick={(e) => {
    e.stopPropagation();
    openEdit(row);
  }}
  disabled={!puedeEditar}
>
  <Pencil className="mr-2 h-4 w-4" />
  <div className="flex flex-col">
    <span>Editar</span>
    {!puedeEditar && (
      <span className="text-xs text-muted-foreground">
        Clase finalizada
      </span>
    )}
  </div>
</DropdownMenuItem>
See: ~/workspace/source/src/pages/Clases.tsx:416-432
Disabled buttons show tooltips explaining why editing is not allowed: “No se puede editar una clase finalizada”

Private Horse Validation

Owner-Only Rule

Private horses can only be used by their owners.
From the README:
5. Caballos Privados: Solo pueden ser usados por sus propietarios
See: ~/workspace/source/README.md:542 While the exact validation code isn’t shown in the files, this business rule is enforced in the class creation logic.

Schedule Conflict Validation

Conflict Detection

The system checks for scheduling conflicts:
Validates that the selected horse doesn’t have another class at the same time.
Validates that the selected instructor doesn’t have another class at the same time.
From the README:
3. Validación de Conflictos de Horario Verifica:
  • Que el caballo no tenga otra clase a la misma hora
  • Que el instructor no tenga otra clase a la misma hora
  • Muestra indicadores visuales (⚠️) en celdas con conflicto
See: ~/workspace/source/README.md:215-219
Conflicts are shown with ⚠️ warning indicators in the calendar view.

Required Field Validations

Student Selection

ClaseForm.tsx
// Caso normal: alumno existente
if (!alumnoId) {
  toast.error("Debe seleccionar un alumno");
  return;
}
alumnoIdFinal = Number(alumnoId);
See: ~/workspace/source/src/components/forms/ClaseForm.tsx:188-192
Student selection is required for all classes except MONTA specialty.

Horse Selection

ClaseForm.tsx
if (caballoId) {
  // Caballo seleccionado manualmente
  caballoIdFinal = Number(caballoId);
} else if (alumno?.caballoPropio) {
  // Auto-asignar caballo del alumno
  caballoIdFinal =
    typeof alumno.caballoPropio === "object"
      ? alumno.caballoPropio.id
      : alumno.caballoPropio;
} else {
  // No hay caballo seleccionado ni predeterminado
  toast.error("Debe seleccionar un caballo");
  return;
}
See: ~/workspace/source/src/components/forms/ClaseForm.tsx:219-234

Trial Class Name Validation

ClaseForm.tsx
if (esPruebaChecked && tipoPrueba === "persona_nueva") {
  if (!nombrePrueba.trim() || !apellidoPrueba.trim()) {
    toast.error("Ingresá nombre y apellido de la persona de prueba");
    return;
  }
}
See: ~/workspace/source/src/components/forms/ClaseForm.tsx:168-173

Business Rule Summary

From the README:

✅ Validaciones Críticas:

  1. Horario: Clases no pueden terminar después de las 18:30
  2. DNI: No se permiten DNI duplicados (alumnos e instructores)
  3. Edición: No se pueden editar clases finalizadas (COMPLETADA, INICIADA, CANCELADA)
  4. Clases de Prueba:
    • Solo para alumnos inactivos
    • No se pueden repetir en la misma especialidad
    • No se permiten si el alumno ya tiene clases de esa especialidad
  5. Caballos Privados: Solo pueden ser usados por sus propietarios
  6. Conflictos: No se permite programar dos clases simultáneas con el mismo caballo o instructor
See: ~/workspace/source/README.md:533-543

System Limits

From the README:

📊 Límites del Sistema:

  • Horario de clases: 09:00 a 18:30
  • Franjas horarias: 30 minutos
  • Planes disponibles: 4, 8, 12, 16 clases mensuales
  • Duraciones de clase: 30 o 60 minutos
  • Colores de instructor: 7 colores predefinidos
See: ~/workspace/source/README.md:555-561

Validation Flow Diagram

Validation Messages

All validation errors are displayed using toast notifications:
toast.error("La clase no puede terminar después de las 18:30...");

Best Practices

1

Validate Early

Client-side validations catch errors before API calls, improving user experience
2

Clear Messages

Validation messages clearly explain what went wrong and how to fix it
3

Visual Indicators

Disabled buttons and tooltips prevent invalid actions before they occur
4

Preserve Data

Failed validations don’t clear the form, allowing users to correct errors

Next Steps

Creating Classes

Learn how to create classes with proper validation

Class States

Understand which states allow editing

Trial Classes

Review trial class validation rules

Build docs developers (and LLMs) love