Add full SEO optimization for Spanglish social and language events

- Add comprehensive metadata to root layout with Open Graph, Twitter cards
- Create dynamic sitemap.ts for all pages and events
- Create robots.ts with proper allow/disallow rules
- Add JSON-LD Event structured data to event detail pages
- Add page-specific metadata to events, community, contact, FAQ pages
- Add FAQ structured data schema
- Update footer with local SEO text for Asunción, Paraguay
- Add web manifest for mobile SEO
- Create 404 page with proper noindex
- Optimize image alt text and add lazy loading
- Add NEXT_PUBLIC_SITE_URL env variable
- Add about/ folder to gitignore
This commit is contained in:
root
2026-01-30 21:05:25 +00:00
parent d0ea55dc5b
commit 47ba754f05
40 changed files with 2659 additions and 420 deletions

View File

@@ -225,16 +225,18 @@ export default function BookingPage() {
newErrors.firstName = t('booking.form.errors.firstNameRequired');
}
if (!formData.lastName.trim() || formData.lastName.length < 2) {
newErrors.lastName = t('booking.form.errors.lastNameRequired');
// lastName is optional - only validate if provided
if (formData.lastName.trim() && formData.lastName.length < 2) {
newErrors.lastName = t('booking.form.errors.lastNameTooShort');
}
if (!formData.email.trim() || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = t('booking.form.errors.emailInvalid');
}
if (!formData.phone.trim() || formData.phone.length < 6) {
newErrors.phone = t('booking.form.errors.phoneRequired');
// phone is optional - only validate if provided
if (formData.phone.trim() && formData.phone.length < 6) {
newErrors.phone = t('booking.form.errors.phoneTooShort');
}
// RUC validation (optional field - only validate if filled)
@@ -915,14 +917,22 @@ export default function BookingPage() {
error={errors.firstName}
required
/>
<Input
label={t('booking.form.lastName')}
value={formData.lastName}
onChange={(e) => setFormData({ ...formData, lastName: e.target.value })}
placeholder={t('booking.form.lastNamePlaceholder')}
error={errors.lastName}
required
/>
<div>
<div className="flex items-center gap-2 mb-1">
<label className="block text-sm font-medium text-gray-700">
{t('booking.form.lastName')}
</label>
<span className="text-xs text-gray-400">
({locale === 'es' ? 'Opcional' : 'Optional'})
</span>
</div>
<Input
value={formData.lastName}
onChange={(e) => setFormData({ ...formData, lastName: e.target.value })}
placeholder={t('booking.form.lastNamePlaceholder')}
error={errors.lastName}
/>
</div>
</div>
<div>
@@ -938,14 +948,20 @@ export default function BookingPage() {
</div>
<div>
<div className="flex items-center gap-2 mb-1">
<label className="block text-sm font-medium text-gray-700">
{t('booking.form.phone')}
</label>
<span className="text-xs text-gray-400">
({locale === 'es' ? 'Opcional' : 'Optional'})
</span>
</div>
<Input
label={t('booking.form.phone')}
type="tel"
value={formData.phone}
onChange={(e) => setFormData({ ...formData, phone: e.target.value })}
placeholder={t('booking.form.phonePlaceholder')}
error={errors.phone}
required
/>
</div>