Actualización de título y adición de favicon en landing B2B
This commit is contained in:
@@ -5,9 +5,7 @@ import { useState, useRef, useEffect, FormEvent } from 'react';
|
||||
type FormData = {
|
||||
name: string;
|
||||
email: string;
|
||||
company: string;
|
||||
phone: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
type FormErrors = Partial<Record<keyof FormData, string>>;
|
||||
@@ -16,33 +14,33 @@ type SubmitStatus = 'idle' | 'loading' | 'success' | 'error';
|
||||
const initialData: FormData = {
|
||||
name: '',
|
||||
email: '',
|
||||
company: '',
|
||||
phone: '',
|
||||
message: '',
|
||||
};
|
||||
|
||||
const initialConsents = {
|
||||
privacy: false,
|
||||
contracting: false,
|
||||
};
|
||||
|
||||
function validateForm(data: FormData): FormErrors {
|
||||
const errors: FormErrors = {};
|
||||
if (!data.name.trim()) errors.name = 'El nombre es requerido';
|
||||
if (!data.name.trim()) errors.name = 'El nombre es obligatorio';
|
||||
if (!data.email.trim()) {
|
||||
errors.email = 'El email es requerido';
|
||||
errors.email = 'El email es obligatorio';
|
||||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
|
||||
errors.email = 'Ingresa un email válido';
|
||||
errors.email = 'Introduce 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';
|
||||
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() {
|
||||
const [formData, setFormData] = useState<FormData>(initialData);
|
||||
const [consents, setConsents] = useState(initialConsents);
|
||||
const [errors, setErrors] = useState<FormErrors>({});
|
||||
const [touched, setTouched] = useState<Partial<Record<keyof FormData, boolean>>>({});
|
||||
const [status, setStatus] = useState<SubmitStatus>('idle');
|
||||
@@ -65,9 +63,7 @@ export default function ContactForm() {
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({ ...prev, [name]: value }));
|
||||
if (touched[name as keyof FormData]) {
|
||||
@@ -76,34 +72,33 @@ export default function ContactForm() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlur = (
|
||||
e: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||
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();
|
||||
const allTouched = Object.keys(formData).reduce(
|
||||
(acc, k) => ({ ...acc, [k]: true }),
|
||||
{} as Record<keyof FormData, boolean>
|
||||
);
|
||||
setTouched(allTouched);
|
||||
|
||||
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');
|
||||
// Simulate API call
|
||||
await new Promise((resolve) => setTimeout(resolve, 1800));
|
||||
// TODO: integrar con backend captación (lead -> pending_photos). De momento mock.
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
setStatus('success');
|
||||
setFormData(initialData);
|
||||
setConsents(initialConsents);
|
||||
setTouched({});
|
||||
setErrors({});
|
||||
};
|
||||
@@ -111,6 +106,7 @@ export default function ContactForm() {
|
||||
const handleReset = () => {
|
||||
setStatus('idle');
|
||||
setFormData(initialData);
|
||||
setConsents(initialConsents);
|
||||
setErrors({});
|
||||
setTouched({});
|
||||
};
|
||||
@@ -127,18 +123,19 @@ export default function ContactForm() {
|
||||
{/* Left info panel */}
|
||||
<div className="reveal opacity-0 translate-y-6 transition-all duration-700 ease-out flex flex-col gap-6 lg:sticky lg:top-[104px]">
|
||||
<div className="mb-2">
|
||||
<span className="badge badge-dark">Contacto</span>
|
||||
<span className="badge badge-dark">Empieza tu reforma</span>
|
||||
</div>
|
||||
<h2
|
||||
id="contact-heading"
|
||||
className="text-[clamp(1.875rem,5vw,3rem)] font-black tracking-[-0.04em] leading-[1.05] text-black"
|
||||
>
|
||||
Hablemos de
|
||||
Tu presupuesto,
|
||||
<br />
|
||||
tu reforma
|
||||
en 5 minutos
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 leading-relaxed">
|
||||
Cuéntanos qué tienes en mente. Un asesor de tu provincia te responderá en menos de 24 horas con una propuesta a medida.
|
||||
Déjanos tu teléfono y te llamamos en menos de 2 minutos. Te enviamos el render
|
||||
y el presupuesto orientativo por WhatsApp.
|
||||
</p>
|
||||
|
||||
{/* Contact details */}
|
||||
@@ -185,7 +182,7 @@ export default function ContactForm() {
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs font-semibold uppercase tracking-widest text-gray-400">Respuesta</div>
|
||||
<div className="text-base font-semibold text-black">Menos de 24 horas</div>
|
||||
<div className="text-base font-semibold text-black">Llamada en < 2 min</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -227,17 +224,18 @@ export default function ContactForm() {
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-2xl font-extrabold tracking-tight text-black">
|
||||
¡Mensaje enviado!
|
||||
¡Te llamamos enseguida!
|
||||
</h3>
|
||||
<p className="text-base text-gray-600 max-w-[320px] leading-relaxed mb-4">
|
||||
Gracias por contactarnos. Nuestro equipo te responderá en menos de 24 horas.
|
||||
<p className="text-base text-gray-600 max-w-[340px] leading-relaxed mb-4">
|
||||
En menos de 2 minutos te llamamos al teléfono que nos has dejado.
|
||||
Te enviaremos el render y el presupuesto por WhatsApp.
|
||||
</p>
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
onClick={handleReset}
|
||||
id="contact-send-another-btn"
|
||||
>
|
||||
Enviar otro mensaje
|
||||
Pedir otro presupuesto
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
@@ -245,178 +243,176 @@ export default function ContactForm() {
|
||||
className="flex flex-col gap-5"
|
||||
onSubmit={handleSubmit}
|
||||
noValidate
|
||||
aria-label="Formulario de contacto"
|
||||
aria-label="Formulario de captación de lead"
|
||||
id="contact-form"
|
||||
>
|
||||
<div className="mb-2">
|
||||
<h3 className="text-2xl font-extrabold tracking-tight text-black">
|
||||
Envíanos un mensaje
|
||||
Pide tu presupuesto
|
||||
</h3>
|
||||
<p className="text-sm text-gray-400 mt-1">
|
||||
Todos los campos marcados con * son requeridos
|
||||
Los 3 campos son obligatorios.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Row: Name + Email */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="contact-name" className="text-sm font-semibold text-dark">
|
||||
Nombre completo <span className="text-error">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="contact-name"
|
||||
name="name"
|
||||
type="text"
|
||||
className={`w-full px-4 py-3 text-base font-sans text-dark bg-white border-[1.5px] rounded-lg transition-all duration-150 outline-none placeholder:text-gray-400 focus:border-black focus:shadow-[0_0_0_3px_rgba(0,0,0,0.06)] ${errors.name && touched.name
|
||||
? 'border-error shadow-[0_0_0_3px_rgba(255,59,59,0.08)]'
|
||||
: 'border-gray-200'
|
||||
}`}
|
||||
placeholder="Juan García"
|
||||
value={formData.name}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="name"
|
||||
aria-required="true"
|
||||
aria-describedby={errors.name && touched.name ? 'name-error' : undefined}
|
||||
aria-invalid={!!(errors.name && touched.name)}
|
||||
/>
|
||||
{errors.name && touched.name && (
|
||||
<span id="name-error" className="text-xs text-error font-medium flex items-center gap-1" role="alert">
|
||||
{errors.name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="contact-email" className="text-sm font-semibold text-dark">
|
||||
Email <span className="text-error">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="contact-email"
|
||||
name="email"
|
||||
type="email"
|
||||
className={`w-full px-4 py-3 text-base font-sans text-dark bg-white border-[1.5px] rounded-lg transition-all duration-150 outline-none placeholder:text-gray-400 focus:border-black focus:shadow-[0_0_0_3px_rgba(0,0,0,0.06)] ${errors.email && touched.email
|
||||
? 'border-error shadow-[0_0_0_3px_rgba(255,59,59,0.08)]'
|
||||
: 'border-gray-200'
|
||||
}`}
|
||||
placeholder="juan@empresa.com"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="email"
|
||||
aria-required="true"
|
||||
aria-describedby={errors.email && touched.email ? 'email-error' : undefined}
|
||||
aria-invalid={!!(errors.email && touched.email)}
|
||||
/>
|
||||
{errors.email && touched.email && (
|
||||
<span id="email-error" className="text-xs text-error font-medium flex items-center gap-1" role="alert">
|
||||
{errors.email}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Row: Company + Phone */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="contact-company" className="text-sm font-semibold text-dark">
|
||||
Empresa <span className="text-error">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="contact-company"
|
||||
name="company"
|
||||
type="text"
|
||||
className={`w-full px-4 py-3 text-base font-sans text-dark bg-white border-[1.5px] rounded-lg transition-all duration-150 outline-none placeholder:text-gray-400 focus:border-black focus:shadow-[0_0_0_3px_rgba(0,0,0,0.06)] ${errors.company && touched.company
|
||||
? 'border-error shadow-[0_0_0_3px_rgba(255,59,59,0.08)]'
|
||||
: 'border-gray-200'
|
||||
}`}
|
||||
placeholder="Mi Empresa S.A."
|
||||
value={formData.company}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="organization"
|
||||
aria-required="true"
|
||||
aria-describedby={errors.company && touched.company ? 'company-error' : undefined}
|
||||
aria-invalid={!!(errors.company && touched.company)}
|
||||
/>
|
||||
{errors.company && touched.company && (
|
||||
<span id="company-error" className="text-xs text-error font-medium flex items-center gap-1" role="alert">
|
||||
{errors.company}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="contact-phone" className="text-sm font-semibold text-dark">
|
||||
Teléfono
|
||||
<span className="font-normal text-gray-400"> (opcional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="contact-phone"
|
||||
name="phone"
|
||||
type="tel"
|
||||
className={`w-full px-4 py-3 text-base font-sans text-dark bg-white border-[1.5px] rounded-lg transition-all duration-150 outline-none placeholder:text-gray-400 focus:border-black focus:shadow-[0_0_0_3px_rgba(0,0,0,0.06)] ${errors.phone && touched.phone
|
||||
? 'border-error shadow-[0_0_0_3px_rgba(255,59,59,0.08)]'
|
||||
: 'border-gray-200'
|
||||
}`}
|
||||
placeholder="+52 55 1234 5678"
|
||||
value={formData.phone}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="tel"
|
||||
aria-describedby={errors.phone && touched.phone ? 'phone-error' : undefined}
|
||||
aria-invalid={!!(errors.phone && touched.phone)}
|
||||
/>
|
||||
{errors.phone && touched.phone && (
|
||||
<span id="phone-error" className="text-xs text-error font-medium flex items-center gap-1" role="alert">
|
||||
{errors.phone}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Message */}
|
||||
{/* Name */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="contact-message" className="text-sm font-semibold text-dark">
|
||||
Mensaje <span className="text-error">*</span>
|
||||
<label htmlFor="contact-name" className="text-sm font-semibold text-dark">
|
||||
Nombre <span className="text-error">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="contact-message"
|
||||
name="message"
|
||||
className={`w-full px-4 py-3 text-base font-sans text-dark bg-white border-[1.5px] rounded-lg transition-all duration-150 outline-none placeholder:text-gray-400 focus:border-black focus:shadow-[0_0_0_3px_rgba(0,0,0,0.06)] resize-y min-h-[120px] ${errors.message && touched.message
|
||||
<input
|
||||
id="contact-name"
|
||||
name="name"
|
||||
type="text"
|
||||
className={`w-full px-4 py-3 text-base font-sans text-dark bg-white border-[1.5px] rounded-lg transition-all duration-150 outline-none placeholder:text-gray-400 focus:border-black focus:shadow-[0_0_0_3px_rgba(0,0,0,0.06)] ${errors.name && touched.name
|
||||
? 'border-error shadow-[0_0_0_3px_rgba(255,59,59,0.08)]'
|
||||
: 'border-gray-200'
|
||||
}`}
|
||||
placeholder="Cuéntanos sobre tu reforma: qué espacio quieres reformar, cuál es tu presupuesto aproximado y en qué ciudad vives..."
|
||||
rows={5}
|
||||
value={formData.message}
|
||||
placeholder="Juan García"
|
||||
value={formData.name}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="name"
|
||||
required
|
||||
aria-required="true"
|
||||
aria-describedby={errors.message && touched.message ? 'message-error' : undefined}
|
||||
aria-invalid={!!(errors.message && touched.message)}
|
||||
aria-describedby={errors.name && touched.name ? 'name-error' : undefined}
|
||||
aria-invalid={!!(errors.name && touched.name)}
|
||||
/>
|
||||
<div className="flex justify-between items-center">
|
||||
{errors.message && touched.message ? (
|
||||
<span id="message-error" className="text-xs text-error font-medium flex items-center gap-1" role="alert">
|
||||
{errors.message}
|
||||
</span>
|
||||
) : (
|
||||
<span />
|
||||
)}
|
||||
<span className="text-xs text-gray-400 ml-auto">
|
||||
{formData.message.length} caracteres
|
||||
{errors.name && touched.name && (
|
||||
<span id="name-error" className="text-xs text-error font-medium" role="alert">
|
||||
{errors.name}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Email */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="contact-email" className="text-sm font-semibold text-dark">
|
||||
Email <span className="text-error">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="contact-email"
|
||||
name="email"
|
||||
type="email"
|
||||
className={`w-full px-4 py-3 text-base font-sans text-dark bg-white border-[1.5px] rounded-lg transition-all duration-150 outline-none placeholder:text-gray-400 focus:border-black focus:shadow-[0_0_0_3px_rgba(0,0,0,0.06)] ${errors.email && touched.email
|
||||
? 'border-error shadow-[0_0_0_3px_rgba(255,59,59,0.08)]'
|
||||
: 'border-gray-200'
|
||||
}`}
|
||||
placeholder="juan@email.com"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="email"
|
||||
required
|
||||
aria-required="true"
|
||||
aria-describedby={errors.email && touched.email ? 'email-error' : undefined}
|
||||
aria-invalid={!!(errors.email && touched.email)}
|
||||
/>
|
||||
{errors.email && touched.email && (
|
||||
<span id="email-error" className="text-xs text-error font-medium" role="alert">
|
||||
{errors.email}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Phone */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="contact-phone" className="text-sm font-semibold text-dark">
|
||||
Teléfono <span className="text-error">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="contact-phone"
|
||||
name="phone"
|
||||
type="tel"
|
||||
className={`w-full px-4 py-3 text-base font-sans text-dark bg-white border-[1.5px] rounded-lg transition-all duration-150 outline-none placeholder:text-gray-400 focus:border-black focus:shadow-[0_0_0_3px_rgba(0,0,0,0.06)] ${errors.phone && touched.phone
|
||||
? 'border-error shadow-[0_0_0_3px_rgba(255,59,59,0.08)]'
|
||||
: 'border-gray-200'
|
||||
}`}
|
||||
placeholder="+34 612 345 678"
|
||||
value={formData.phone}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
autoComplete="tel"
|
||||
inputMode="tel"
|
||||
required
|
||||
aria-required="true"
|
||||
aria-describedby={errors.phone && touched.phone ? 'phone-error' : undefined}
|
||||
aria-invalid={!!(errors.phone && touched.phone)}
|
||||
/>
|
||||
{errors.phone && touched.phone && (
|
||||
<span id="phone-error" className="text-xs text-error font-medium" role="alert">
|
||||
{errors.phone}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Consents */}
|
||||
<fieldset className="flex flex-col gap-3 mt-2 pt-4 border-t border-gray-200">
|
||||
<legend className="sr-only">Consentimientos</legend>
|
||||
|
||||
<label
|
||||
htmlFor="consent-privacy"
|
||||
className="flex items-start gap-3 cursor-pointer text-sm text-gray-700 leading-relaxed"
|
||||
>
|
||||
<input
|
||||
id="consent-privacy"
|
||||
type="checkbox"
|
||||
checked={consents.privacy}
|
||||
onChange={(e) =>
|
||||
setConsents((c) => ({ ...c, privacy: e.target.checked }))
|
||||
}
|
||||
className="mt-1 w-4 h-4 accent-black shrink-0 cursor-pointer"
|
||||
required
|
||||
aria-required="true"
|
||||
/>
|
||||
<span>
|
||||
He leído y acepto la{' '}
|
||||
<a
|
||||
href="#"
|
||||
className="text-black underline underline-offset-2 hover:no-underline"
|
||||
>
|
||||
política de privacidad
|
||||
</a>
|
||||
.
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label
|
||||
htmlFor="consent-contracting"
|
||||
className="flex items-start gap-3 cursor-pointer text-sm text-gray-700 leading-relaxed"
|
||||
>
|
||||
<input
|
||||
id="consent-contracting"
|
||||
type="checkbox"
|
||||
checked={consents.contracting}
|
||||
onChange={(e) =>
|
||||
setConsents((c) => ({ ...c, contracting: e.target.checked }))
|
||||
}
|
||||
className="mt-1 w-4 h-4 accent-black shrink-0 cursor-pointer"
|
||||
required
|
||||
aria-required="true"
|
||||
/>
|
||||
<span>
|
||||
He leído y acepto las{' '}
|
||||
<a
|
||||
href="#"
|
||||
className="text-black underline underline-offset-2 hover:no-underline"
|
||||
>
|
||||
condiciones de contratación
|
||||
</a>
|
||||
.
|
||||
</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
{/* Submit */}
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-primary btn-lg w-full justify-center mt-2 disabled:opacity-70 disabled:cursor-not-allowed disabled:transform-none"
|
||||
disabled={status === 'loading'}
|
||||
className="btn btn-primary btn-lg w-full justify-center mt-2 disabled:opacity-60 disabled:cursor-not-allowed disabled:transform-none"
|
||||
disabled={status === 'loading' || !consentsGranted}
|
||||
id="contact-submit-btn"
|
||||
aria-busy={status === 'loading'}
|
||||
aria-disabled={status === 'loading' || !consentsGranted}
|
||||
>
|
||||
{status === 'loading' ? (
|
||||
<>
|
||||
@@ -428,7 +424,7 @@ export default function ContactForm() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Enviar mensaje
|
||||
Pedir presupuesto
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
||||
<path
|
||||
d="M2 8h12M10 4l4 4-4 4"
|
||||
@@ -441,14 +437,6 @@ export default function ContactForm() {
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
|
||||
<p className="text-xs text-gray-400 text-center leading-relaxed">
|
||||
Al enviar, aceptas nuestra{' '}
|
||||
<a href="#" className="text-gray-600 underline underline-offset-2 transition-colors duration-150 hover:text-black">
|
||||
política de privacidad
|
||||
</a>
|
||||
. Nunca compartiremos tu información.
|
||||
</p>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user