feat(cms): redirect legal links to external URL when configured
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Calendar, Clock, Download, LogOut } from 'lucide-react';
|
||||
import { parseISO } from 'date-fns';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -9,6 +10,7 @@ import { DynamicFavicon } from '../common/DynamicFavicon';
|
||||
import { useTheme } from '../../contexts/ThemeContext';
|
||||
import { useGuestIdentityOptional } from '../../contexts/GuestIdentityContext';
|
||||
import { buildResourceUrl } from '../../utils/url';
|
||||
import { cmsService, type PublicCMSPage } from '../../services/cms.service';
|
||||
import type { HeaderStyleType } from '../../types/theme.types';
|
||||
|
||||
interface GalleryLayoutProps {
|
||||
@@ -62,6 +64,22 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
|
||||
const { theme } = useTheme();
|
||||
const guestIdentity = useGuestIdentityOptional();
|
||||
|
||||
// Footer legal-link config. Cached aggressively because the toggle state
|
||||
// changes rarely and the gallery footer renders on every page view.
|
||||
// Failures fall back to the internal /impressum and /datenschutz routes.
|
||||
const { data: impressumPage } = useQuery<PublicCMSPage>({
|
||||
queryKey: ['public-cms', 'impressum'],
|
||||
queryFn: () => cmsService.getPublicPage('impressum'),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
retry: false,
|
||||
});
|
||||
const { data: datenschutzPage } = useQuery<PublicCMSPage>({
|
||||
queryKey: ['public-cms', 'datenschutz'],
|
||||
queryFn: () => cmsService.getPublicPage('datenschutz'),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
retry: false,
|
||||
});
|
||||
|
||||
// Determine header style - use prop first (from event data), then theme, then fall back to 'standard'
|
||||
const headerStyle: HeaderStyleType = headerStyleProp || theme.headerStyle || 'standard';
|
||||
const isHeroHeader = headerStyle === 'hero';
|
||||
@@ -592,19 +610,41 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
|
||||
)}
|
||||
{/* Legal Links */}
|
||||
<div className="mt-4 flex items-center justify-center gap-4 flex-wrap">
|
||||
<Link
|
||||
to="/impressum"
|
||||
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
||||
>
|
||||
{t('legal.impressum')}
|
||||
</Link>
|
||||
{impressumPage?.use_external_url && impressumPage.external_url ? (
|
||||
<a
|
||||
href={impressumPage.external_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
||||
>
|
||||
{t('legal.impressum')}
|
||||
</a>
|
||||
) : (
|
||||
<Link
|
||||
to="/impressum"
|
||||
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
||||
>
|
||||
{t('legal.impressum')}
|
||||
</Link>
|
||||
)}
|
||||
<span className="text-xs text-muted-theme">|</span>
|
||||
<Link
|
||||
to="/datenschutz"
|
||||
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
||||
>
|
||||
{t('legal.datenschutz')}
|
||||
</Link>
|
||||
{datenschutzPage?.use_external_url && datenschutzPage.external_url ? (
|
||||
<a
|
||||
href={datenschutzPage.external_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
||||
>
|
||||
{t('legal.datenschutz')}
|
||||
</a>
|
||||
) : (
|
||||
<Link
|
||||
to="/datenschutz"
|
||||
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
||||
>
|
||||
{t('legal.datenschutz')}
|
||||
</Link>
|
||||
)}
|
||||
{guestIdentity?.identity && (
|
||||
<>
|
||||
<span className="text-xs text-muted-theme">|</span>
|
||||
|
||||
@@ -44,7 +44,17 @@ export const LegalPage: React.FC = () => {
|
||||
}
|
||||
}, [page?.title]);
|
||||
|
||||
if (isLoading) {
|
||||
// External-URL override: full-page redirect so the visitor lands on the
|
||||
// operator's own canonical legal page. Use replace() so the back button
|
||||
// returns to the gallery instead of looping back through the redirect.
|
||||
const willRedirect = !!(page?.use_external_url && page?.external_url);
|
||||
useEffect(() => {
|
||||
if (willRedirect && page?.external_url) {
|
||||
window.location.replace(page.external_url);
|
||||
}
|
||||
}, [willRedirect, page?.external_url]);
|
||||
|
||||
if (isLoading || willRedirect) {
|
||||
return (
|
||||
<div className="min-h-screen bg-neutral-50 flex items-center justify-center">
|
||||
<Loading size="lg" text="Loading..." />
|
||||
|
||||
Reference in New Issue
Block a user