feat(cms): redirect legal links to external URL when configured
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { Calendar, Clock, Download, LogOut } from 'lucide-react';
|
import { Calendar, Clock, Download, LogOut } from 'lucide-react';
|
||||||
import { parseISO } from 'date-fns';
|
import { parseISO } from 'date-fns';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -9,6 +10,7 @@ import { DynamicFavicon } from '../common/DynamicFavicon';
|
|||||||
import { useTheme } from '../../contexts/ThemeContext';
|
import { useTheme } from '../../contexts/ThemeContext';
|
||||||
import { useGuestIdentityOptional } from '../../contexts/GuestIdentityContext';
|
import { useGuestIdentityOptional } from '../../contexts/GuestIdentityContext';
|
||||||
import { buildResourceUrl } from '../../utils/url';
|
import { buildResourceUrl } from '../../utils/url';
|
||||||
|
import { cmsService, type PublicCMSPage } from '../../services/cms.service';
|
||||||
import type { HeaderStyleType } from '../../types/theme.types';
|
import type { HeaderStyleType } from '../../types/theme.types';
|
||||||
|
|
||||||
interface GalleryLayoutProps {
|
interface GalleryLayoutProps {
|
||||||
@@ -62,6 +64,22 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
|
|||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const guestIdentity = useGuestIdentityOptional();
|
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'
|
// Determine header style - use prop first (from event data), then theme, then fall back to 'standard'
|
||||||
const headerStyle: HeaderStyleType = headerStyleProp || theme.headerStyle || 'standard';
|
const headerStyle: HeaderStyleType = headerStyleProp || theme.headerStyle || 'standard';
|
||||||
const isHeroHeader = headerStyle === 'hero';
|
const isHeroHeader = headerStyle === 'hero';
|
||||||
@@ -592,19 +610,41 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
|
|||||||
)}
|
)}
|
||||||
{/* Legal Links */}
|
{/* Legal Links */}
|
||||||
<div className="mt-4 flex items-center justify-center gap-4 flex-wrap">
|
<div className="mt-4 flex items-center justify-center gap-4 flex-wrap">
|
||||||
|
{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
|
<Link
|
||||||
to="/impressum"
|
to="/impressum"
|
||||||
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
||||||
>
|
>
|
||||||
{t('legal.impressum')}
|
{t('legal.impressum')}
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
<span className="text-xs text-muted-theme">|</span>
|
<span className="text-xs text-muted-theme">|</span>
|
||||||
|
{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
|
<Link
|
||||||
to="/datenschutz"
|
to="/datenschutz"
|
||||||
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
className="text-xs text-muted-theme hover:text-theme transition-colors"
|
||||||
>
|
>
|
||||||
{t('legal.datenschutz')}
|
{t('legal.datenschutz')}
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
{guestIdentity?.identity && (
|
{guestIdentity?.identity && (
|
||||||
<>
|
<>
|
||||||
<span className="text-xs text-muted-theme">|</span>
|
<span className="text-xs text-muted-theme">|</span>
|
||||||
|
|||||||
@@ -44,7 +44,17 @@ export const LegalPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [page?.title]);
|
}, [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 (
|
return (
|
||||||
<div className="min-h-screen bg-neutral-50 flex items-center justify-center">
|
<div className="min-h-screen bg-neutral-50 flex items-center justify-center">
|
||||||
<Loading size="lg" text="Loading..." />
|
<Loading size="lg" text="Loading..." />
|
||||||
|
|||||||
Reference in New Issue
Block a user