socios-comerciales.skyballo.../src/components/reserva/Paso2Datos.tsx

183 lines
8.2 KiB
TypeScript

import { useState } from "react";
import { CalendarDays, ChevronDown, CircleCheck, Clock, MapPin, Users } from "lucide-react";
import { BuscadorSelect } from "@/components/BuscadorSelect";
import { LUGARES_CITA, VUELO_INCLUYE } from "@/lib/extras-catalogo";
import { HORA_CITA, type PasajeroDatos, type ReservaEstado } from "@/lib/reserva-flujo";
export function Paso2Datos({
estado,
set,
setPasajero,
}: {
estado: ReservaEstado;
set: (parcial: Partial<ReservaEstado>) => void;
setPasajero: (i: number, parcial: Partial<PasajeroDatos>) => void;
}) {
const [resumenAbierto, setResumenAbierto] = useState(true);
return (
<div className="grid gap-6 xl:grid-cols-[1fr_340px]">
<div className="space-y-6">
<section className="rounded-3xl bg-card p-5 shadow-soft">
<h2 className="text-base font-bold">Datos del vuelo</h2>
<div className="mt-4 grid gap-4 sm:grid-cols-2">
<div>
<label htmlFor="fecha" className="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-muted-foreground">
<CalendarDays className="mr-1 inline size-3.5" /> Fecha de vuelo
</label>
<input
id="fecha"
type="date"
value={estado.fecha}
disabled={estado.fechaPorConfirmar}
onChange={(e) => set({ fecha: e.target.value })}
className="w-full rounded-2xl border border-border bg-card px-4 py-3 text-sm transition-all hover:border-primary/60 focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50"
/>
<label className="mt-2 flex cursor-pointer items-center gap-2 text-xs text-muted-foreground">
<input
type="checkbox"
checked={estado.fechaPorConfirmar}
onChange={(e) => set({ fechaPorConfirmar: e.target.checked })}
className="size-4 rounded border-border accent-primary"
/>
Fecha por confirmar
</label>
</div>
<div>
<span className="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-muted-foreground">
<Clock className="mr-1 inline size-3.5" /> Hora de cita
</span>
<div className="rounded-2xl border border-border bg-muted px-4 py-3 text-sm font-semibold">
{HORA_CITA}
</div>
<p className="mt-2 text-xs text-muted-foreground">Horario fijo de recepción de pasajeros.</p>
</div>
<div className="sm:col-span-2">
<label htmlFor="lugar" className="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-muted-foreground">
<MapPin className="mr-1 inline size-3.5" /> Lugar de cita
</label>
<BuscadorSelect
id="lugar"
opciones={LUGARES_CITA}
valor={estado.lugarCita}
onChange={(v) => set({ lugarCita: v })}
placeholder="Busca tu punto de encuentro"
/>
</div>
<div>
<span className="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-muted-foreground">
Tipo de vuelo
</span>
<div className="rounded-2xl border border-border bg-muted px-4 py-3 text-sm font-semibold text-muted-foreground">
Compartidos
</div>
</div>
<div>
<span className="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-muted-foreground">
Idioma del pase de abordar
</span>
<div className="flex gap-2">
{(["Español", "Inglés"] as const).map((idioma) => (
<button
key={idioma}
type="button"
role="radio"
aria-checked={estado.idioma === idioma}
onClick={() => set({ idioma })}
className={`flex-1 rounded-2xl border px-4 py-3 text-sm font-semibold transition-all active:scale-95 ${
estado.idioma === idioma
? "border-primary bg-primary text-primary-foreground shadow-soft"
: "border-border bg-card hover:border-primary/60"
}`}
>
{idioma}
</button>
))}
</div>
</div>
</div>
</section>
<section className="rounded-3xl bg-card p-5 shadow-soft">
<h2 className="flex items-center gap-2 text-base font-bold">
<Users className="size-4 text-secondary" /> Datos de los pasajeros
</h2>
<p className="text-sm text-muted-foreground">
{estado.pasajeros.length} pasajero(s) según tu selección del paso 1.
</p>
<div className="mt-4 space-y-4">
{estado.pasajeros.map((p, i) => (
<div key={i} className="rounded-3xl border border-border p-4 transition-shadow hover:shadow-soft">
<p className="mb-3 text-xs font-bold uppercase tracking-wide text-primary">
Pasajero {i + 1} {i < estado.adultos ? "· Adulto" : "· Niño"}
</p>
<div className="grid gap-3 sm:grid-cols-2">
<input
value={p.nombre}
onChange={(e) => setPasajero(i, { nombre: e.target.value })}
placeholder="Nombre(s)"
className="rounded-2xl border border-border bg-card px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
<input
value={p.apellidos}
onChange={(e) => setPasajero(i, { apellidos: e.target.value })}
placeholder="Apellidos"
className="rounded-2xl border border-border bg-card px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
<input
value={p.telefono}
onChange={(e) => setPasajero(i, { telefono: e.target.value })}
placeholder="Teléfono de contacto"
className="rounded-2xl border border-border bg-card px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
<input
value={p.peso}
onChange={(e) => setPasajero(i, { peso: e.target.value })}
placeholder="Peso aproximado (kg)"
className="rounded-2xl border border-border bg-card px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
</div>
</div>
))}
</div>
</section>
</div>
{/* Resumen del vuelo colapsable */}
<aside className="xl:sticky xl:top-24 xl:h-fit">
<div className="overflow-hidden rounded-3xl bg-ink text-ink-foreground shadow-lift">
<button
type="button"
onClick={() => setResumenAbierto((v) => !v)}
className="flex w-full items-center justify-between gap-3 px-5 py-4 text-left"
>
<div>
<p className="text-sm font-bold">Vuelo Aventura 20% OFF</p>
<p className="text-xs opacity-70">Experiencia compartida · Teotihuacán</p>
</div>
<ChevronDown className={`size-4 transition-transform duration-300 ${resumenAbierto ? "rotate-180" : ""}`} />
</button>
<div
className={`grid transition-all duration-500 ease-out ${resumenAbierto ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"}`}
>
<ul className="overflow-hidden px-5 pb-5 text-sm">
{VUELO_INCLUYE.map((i) => (
<li key={i} className="flex items-start gap-2 py-1.5">
<CircleCheck className="mt-0.5 size-4 shrink-0 text-brand" />
<span className="opacity-90">{i}</span>
</li>
))}
</ul>
</div>
</div>
</aside>
</div>
);
}