diff --git a/frontend/src/app/(public)/book/[eventId]/page.tsx b/frontend/src/app/(public)/book/[eventId]/page.tsx index 959054c..9204ea8 100644 --- a/frontend/src/app/(public)/book/[eventId]/page.tsx +++ b/frontend/src/app/(public)/book/[eventId]/page.tsx @@ -1370,7 +1370,7 @@ export default function BookingPage() { > {t('booking.form.termsAgreePart1')} {t('booking.form.termsAgreePart2')} ( diff --git a/frontend/src/components/layout/LegalPageLayout.tsx b/frontend/src/components/layout/LegalPageLayout.tsx index 8d3de09..026645d 100644 --- a/frontend/src/components/layout/LegalPageLayout.tsx +++ b/frontend/src/components/layout/LegalPageLayout.tsx @@ -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 (
@@ -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" > - Back to Home + {t('legalPage.backToHome')} {/* Title */} @@ -31,7 +88,7 @@ export default function LegalPageLayout({ title, content, lastUpdated }: LegalPa {lastUpdated && lastUpdated !== '[Insert Date]' && (

- Last updated: {lastUpdated} + {t('legalPage.lastUpdated', { date: lastUpdated })}

)}
@@ -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')}
diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 6cd1c1e..d728c65 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -322,6 +322,11 @@ "refund": "Refund Policy" } }, + "legalPage": { + "backToHome": "Back to Home", + "lastUpdated": "Last updated: {date}", + "backToTop": "Back to top" + }, "linktree": { "tagline": "Language Exchange Community", "nextEvent": "Next Event", diff --git a/frontend/src/i18n/locales/es.json b/frontend/src/i18n/locales/es.json index 384c080..c85409a 100644 --- a/frontend/src/i18n/locales/es.json +++ b/frontend/src/i18n/locales/es.json @@ -322,6 +322,11 @@ "refund": "Política de Reembolso" } }, + "legalPage": { + "backToHome": "Volver al inicio", + "lastUpdated": "Última actualización: {date}", + "backToTop": "Volver arriba" + }, "linktree": { "tagline": "Comunidad de Intercambio de Idiomas", "nextEvent": "Próximo Evento",