feat: validar que kilometraje sea número entero positivo
Deploy / deploy (push) Successful in 4m1s

Muestra error inline si el cliente ingresa letras u otros caracteres,
y bloquea el botón de confirmar hasta que el valor sea válido.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Beldor
2026-06-22 23:52:31 -03:00
parent 221aace9f1
commit 0b769805f9
+19 -5
View File
@@ -77,6 +77,7 @@ function TurnosContent() {
const [diaSeleccionado, setDiaSeleccionado] = useState<string | null>(null); const [diaSeleccionado, setDiaSeleccionado] = useState<string | null>(null);
const [slotSel, setSlotSel] = useState<Slot | null>(null); const [slotSel, setSlotSel] = useState<Slot | null>(null);
const [kilometros, setKilometros] = useState(""); const [kilometros, setKilometros] = useState("");
const [kmError, setKmError] = useState("");
const [reservando, setReservando] = useState(false); const [reservando, setReservando] = useState(false);
const [turnoCreado, setTurnoCreado] = useState<Turno | null>(null); const [turnoCreado, setTurnoCreado] = useState<Turno | null>(null);
@@ -119,10 +120,22 @@ function TurnosContent() {
setDiaSeleccionado(dateStr); setDiaSeleccionado(dateStr);
setSlotSel(null); setSlotSel(null);
setKilometros(""); setKilometros("");
setKmError("");
}
function handleKilometros(val: string) {
setKilometros(val);
if (val === "") {
setKmError("");
} else if (!/^\d+$/.test(val) || Number(val) < 0) {
setKmError("Ingresá solo números enteros positivos");
} else {
setKmError("");
}
} }
async function reservar() { async function reservar() {
if (!slotSel || !servicioSel || !autoId || !kilometros) return; if (!slotSel || !servicioSel || !autoId || !kilometros || kmError) return;
setReservando(true); setReservando(true);
const res = await fetch("/api/cliente/turnos", { const res = await fetch("/api/cliente/turnos", {
method: "POST", method: "POST",
@@ -341,13 +354,14 @@ function TurnosContent() {
Kilometraje actual <span className="text-red-500">*</span> Kilometraje actual <span className="text-red-500">*</span>
</label> </label>
<input <input
type="number" min={0} placeholder="Ej: 85000" type="text" inputMode="numeric" placeholder="Ej: 85000"
value={kilometros} value={kilometros}
onChange={e => setKilometros(e.target.value)} onChange={e => handleKilometros(e.target.value)}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" className={`w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 ${kmError ? "border-red-400 focus:ring-red-400" : "border-gray-300 focus:ring-blue-500"}`}
/> />
{kmError && <p className="text-xs text-red-500 mt-1">{kmError}</p>}
</div> </div>
<Button onClick={reservar} disabled={!kilometros} loading={reservando} className="w-full"> <Button onClick={reservar} disabled={!kilometros || !!kmError} loading={reservando} className="w-full">
Confirmar turno · {horaArg(slotSel.fechaInicio)} – {horaArg(slotSel.fechaFin)} Confirmar turno · {horaArg(slotSel.fechaInicio)} – {horaArg(slotSel.fechaFin)}
</Button> </Button>
</div> </div>