'use client'; import { useState, useRef, useEffect, FormEvent } from 'react'; type FormData = { name: string; email: string; company: string; phone: string; message: string; }; type FormErrors = Partial>; type SubmitStatus = 'idle' | 'loading' | 'success' | 'error'; const initialData: FormData = { name: '', email: '', company: '', phone: '', message: '', }; function validateForm(data: FormData): FormErrors { const errors: FormErrors = {}; if (!data.name.trim()) errors.name = 'El nombre es requerido'; if (!data.email.trim()) { errors.email = 'El email es requerido'; } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) { errors.email = 'Ingresa un email válido'; } if (!data.company.trim()) errors.company = 'La empresa es requerida'; if (data.phone && !/^[+\d\s\-().]{7,20}$/.test(data.phone)) { errors.phone = 'Ingresa un teléfono válido'; } if (!data.message.trim()) { errors.message = 'El mensaje es requerido'; } else if (data.message.trim().length < 10) { errors.message = 'El mensaje debe tener al menos 10 caracteres'; } return errors; } export default function ContactForm() { const [formData, setFormData] = useState(initialData); const [errors, setErrors] = useState({}); const [touched, setTouched] = useState>>({}); const [status, setStatus] = useState('idle'); 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] })); }; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); const allTouched = Object.keys(formData).reduce( (acc, k) => ({ ...acc, [k]: true }), {} as Record ); setTouched(allTouched); const validationErrors = validateForm(formData); if (Object.keys(validationErrors).length > 0) { setErrors(validationErrors); return; } setStatus('loading'); // Simulate API call await new Promise((resolve) => setTimeout(resolve, 1800)); setStatus('success'); setFormData(initialData); setTouched({}); setErrors({}); }; const handleReset = () => { setStatus('idle'); setFormData(initialData); setErrors({}); setTouched({}); }; return (
{/* Left info panel */}
Contacto

Hablemos de
tu negocio

Cuéntanos qué necesitas. Nuestro equipo responderá en menos de 24 horas con una propuesta personalizada.

{/* Contact details */}
Email
hola@flowsync.io
Teléfono
+1 (800) 123-4567
Respuesta
Menos de 24 horas
{/* Testimonial */}

“FlowSync transformó la forma en que colaboramos. Lo que antes tomaba días, ahora lo hacemos en horas.”

MR
María Rodríguez
CTO en TechLatam
{/* Form panel */}
{status === 'success' ? (

¡Mensaje enviado!

Gracias por contactarnos. Nuestro equipo te responderá en menos de 24 horas.

) : (

Envíanos un mensaje

Todos los campos marcados con * son requeridos

{/* Row: Name + Email */}
{errors.name && touched.name && ( {errors.name} )}
{errors.email && touched.email && ( {errors.email} )}
{/* Row: Company + Phone */}
{errors.company && touched.company && ( {errors.company} )}
{errors.phone && touched.phone && ( {errors.phone} )}
{/* Message */}