'use client'; import { useState, useRef, useEffect, FormEvent } from 'react'; import { useRouter } from 'next/navigation'; import { crearLead } from '@/app/solicitud/actions'; type FormData = { name: string; email: string; phone: string; }; type FormErrors = Partial>; type SubmitStatus = 'idle' | 'loading' | 'success' | 'error'; const initialData: FormData = { name: '', email: '', phone: '', }; const initialConsents = { privacy: false, contracting: false, }; function validateForm(data: FormData): FormErrors { const errors: FormErrors = {}; if (!data.name.trim()) errors.name = 'El nombre es obligatorio'; if (!data.email.trim()) { errors.email = 'El email es obligatorio'; } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) { errors.email = 'Introduce un email válido'; } if (!data.phone.trim()) { errors.phone = 'El teléfono es obligatorio'; } else if (!/^[+\d\s\-().]{7,20}$/.test(data.phone)) { errors.phone = 'Introduce un teléfono válido'; } return errors; } export default function ContactForm({ slug }: { slug: string }) { const [formData, setFormData] = useState(initialData); const [consents, setConsents] = useState(initialConsents); const [errors, setErrors] = useState({}); const [touched, setTouched] = useState>>({}); const [status, setStatus] = useState('idle'); const [submitError, setSubmitError] = useState(null); const router = useRouter(); const sectionRef = useRef(null); useEffect(() => { const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add('opacity-100', 'translate-y-0'); entry.target.classList.remove('opacity-0', 'translate-y-6'); } }); }, { threshold: 0.1 } ); const elements = sectionRef.current?.querySelectorAll('.reveal'); elements?.forEach((el) => observer.observe(el)); return () => observer.disconnect(); }, []); const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); if (touched[name as keyof FormData]) { const newErrors = validateForm({ ...formData, [name]: value }); setErrors((prev) => ({ ...prev, [name]: newErrors[name as keyof FormData] })); } }; const handleBlur = (e: React.FocusEvent) => { const { name } = e.target; setTouched((prev) => ({ ...prev, [name]: true })); const newErrors = validateForm(formData); setErrors((prev) => ({ ...prev, [name]: newErrors[name as keyof FormData] })); }; // El submit queda deshabilitado hasta que los dos consentimientos estén marcados (RF-B-04). // La validación de campos se ejecuta on submit/blur para que los errores sean visibles. const consentsGranted = consents.privacy && consents.contracting; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); setTouched({ name: true, email: true, phone: true }); const validationErrors = validateForm(formData); if (Object.keys(validationErrors).length > 0) { setErrors(validationErrors); return; } if (!consentsGranted) return; setStatus('loading'); setSubmitError(null); const result = await crearLead(slug, { nombre: formData.name, email: formData.email, telefono: formData.phone, consentPrivacidad: consents.privacy, consentContratacion: consents.contracting, }); if (!result.ok) { setStatus('error'); setSubmitError(result.error); return; } router.push(`/solicitud/${result.leadId}`); }; const handleReset = () => { setStatus('idle'); setFormData(initialData); setConsents(initialConsents); setErrors({}); setTouched({}); }; return (
{/* Left info panel */}
Empieza tu reforma

Tu presupuesto,
en 5 minutos

Déjanos tu teléfono y te llamamos en menos de 2 minutos. Te enviamos el render y el presupuesto orientativo por WhatsApp.

{/* Contact details */}
Email
hola@reformix.es
Teléfono
+34 900 123 456
Respuesta
Llamada en < 2 min
{/* Testimonial */}

“Reformix me dio un presupuesto en 5 minutos. A la semana ya tenía a los operarios en casa. Mejor reforma que la que pedí.”

LM
Laura Martínez
Reforma de cocina en Madrid
{/* Form panel */}
{status === 'success' ? (

¡Te llamamos enseguida!

En menos de 2 minutos te llamamos al teléfono que nos has dejado. Te enviaremos el render y el presupuesto por WhatsApp.

) : (

Pide tu presupuesto

Los 3 campos son obligatorios.

{/* Name */}
{errors.name && touched.name && ( {errors.name} )}
{/* Email */}
{errors.email && touched.email && ( {errors.email} )}
{/* Phone */}
{errors.phone && touched.phone && ( {errors.phone} )}
{/* Consents */}
Consentimientos
{submitError && (

{submitError}

)} {/* Submit */}
)}
); }