fix(legal): show legal pages in site language with bidirectional toggle

Wire legal pages to LanguageContext, pass locale on footer/booking links,
translate layout chrome, and restore SSR content when switching back to English.
This commit is contained in:
Michilis
2026-06-04 22:51:32 +00:00
parent 22e9254f42
commit a8b72b47b1
6 changed files with 76 additions and 7 deletions

View File

@@ -1,17 +1,74 @@
'use client';
import { useEffect, useState } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import Link from 'next/link';
import { ArrowLeftIcon } from '@heroicons/react/24/outline';
import { useLanguage } from '@/context/LanguageContext';
import { legalPagesApi } from '@/lib/api';
interface LegalPageLayoutProps {
slug: string;
initialLocale: 'en' | 'es';
title: string;
content: string;
lastUpdated?: string;
}
export default function LegalPageLayout({ title, content, lastUpdated }: LegalPageLayoutProps) {
function extractLastUpdated(contentMarkdown: string, updatedAt?: string): string | undefined {
const match = contentMarkdown?.match(/Last updated:\s*(.+)/i);
return match ? match[1].trim() : updatedAt;
}
export default function LegalPageLayout({
slug,
initialLocale,
title: initialTitle,
content: initialContent,
lastUpdated: initialLastUpdated,
}: LegalPageLayoutProps) {
const { locale, t } = useLanguage();
const [title, setTitle] = useState(initialTitle);
const [content, setContent] = useState(initialContent);
const [lastUpdated, setLastUpdated] = useState(initialLastUpdated);
const [loadedLocale, setLoadedLocale] = useState(initialLocale);
useEffect(() => {
if (locale === loadedLocale) {
return;
}
// Returning to the server-rendered language: restore SSR content without a fetch
if (locale === initialLocale) {
setTitle(initialTitle);
setContent(initialContent);
setLastUpdated(initialLastUpdated);
setLoadedLocale(initialLocale);
return;
}
let cancelled = false;
legalPagesApi
.getBySlug(slug, locale)
.then(({ page }) => {
if (cancelled || !page) {
return;
}
setTitle(page.title);
setContent(page.contentMarkdown);
setLastUpdated(extractLastUpdated(page.contentMarkdown, page.updatedAt));
setLoadedLocale(locale);
})
.catch(() => {
// Keep the server-rendered content if the re-fetch fails
});
return () => {
cancelled = true;
};
}, [locale, loadedLocale, initialLocale, slug, initialTitle, initialContent, initialLastUpdated]);
return (
<div className="section-padding">
<div className="container-page max-w-4xl">
@@ -21,7 +78,7 @@ export default function LegalPageLayout({ title, content, lastUpdated }: LegalPa
className="inline-flex items-center text-gray-600 hover:text-primary-dark transition-colors mb-8"
>
<ArrowLeftIcon className="w-4 h-4 mr-2" />
Back to Home
{t('legalPage.backToHome')}
</Link>
{/* Title */}
@@ -31,7 +88,7 @@ export default function LegalPageLayout({ title, content, lastUpdated }: LegalPa
</h1>
{lastUpdated && lastUpdated !== '[Insert Date]' && (
<p className="text-sm text-gray-500">
Last updated: {lastUpdated}
{t('legalPage.lastUpdated', { date: lastUpdated })}
</p>
)}
</div>
@@ -182,7 +239,7 @@ export default function LegalPageLayout({ title, content, lastUpdated }: LegalPa
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
className="text-gray-500 hover:text-primary-dark transition-colors text-sm"
>
Back to top
{t('legalPage.backToTop')}
</button>
</div>
</div>