Fix language setting not being saved to database on admin settings page

- Added default_language field to general settings state in SettingsPage
- Replaced LanguageSelector component with simple select dropdown on settings page
- Fixed public settings endpoint to read general_default_language from database
- Language setting now properly saved when clicking Save Settings button
- Setting is correctly used by gallery login page and legal pages

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
This commit is contained in:
2025-07-08 09:49:45 +02:00
co-authored by Claude
parent cfa0b0da69
commit 2012b0bab9
91 changed files with 6183 additions and 577 deletions
@@ -0,0 +1,171 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Calendar, Clock, Download, LogOut } from 'lucide-react';
import { format, parseISO } from 'date-fns';
import { useTranslation } from 'react-i18next';
import { Button, LanguageSelector } from '../common';
import { DynamicFavicon } from '../common/DynamicFavicon';
interface GalleryLayoutProps {
event: {
event_name: string;
event_type?: string;
event_date?: string;
expires_at?: string;
};
brandingSettings?: {
company_name?: string;
company_tagline?: string;
support_email?: string;
footer_text?: string;
favicon_url?: string;
logo_url?: string;
};
showLogout?: boolean;
onLogout?: () => void;
showDownloadAll?: boolean;
onDownloadAll?: () => void;
isDownloading?: boolean;
headerExtra?: React.ReactNode;
children: React.ReactNode;
}
export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
event,
brandingSettings,
showLogout = false,
onLogout,
showDownloadAll = false,
onDownloadAll,
isDownloading = false,
headerExtra,
children,
}) => {
const { t } = useTranslation();
return (
<div className="min-h-screen bg-neutral-50">
{/* Dynamic Favicon */}
<DynamicFavicon />
{/* Header */}
<header className="bg-white border-b border-neutral-200 sticky top-0 z-40">
<div className="container py-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
{/* Company logo */}
{brandingSettings?.logo_url && (
<div className="pr-4 border-r border-neutral-200">
<img
src={brandingSettings.logo_url}
alt={brandingSettings.company_name || 'Company Logo'}
className="h-12 w-auto object-contain"
/>
</div>
)}
{/* Company branding */}
{!brandingSettings?.logo_url && brandingSettings?.company_name && (
<div className="pr-4 border-r border-neutral-200">
<h2 className="text-lg font-semibold text-neutral-800">{brandingSettings.company_name}</h2>
{brandingSettings.company_tagline && (
<p className="text-xs text-neutral-600">{brandingSettings.company_tagline}</p>
)}
</div>
)}
<div>
<h1 className="text-2xl font-bold text-neutral-900">{event.event_name}</h1>
{(event.event_date || event.expires_at) && (
<div className="flex items-center gap-4 mt-1 text-sm text-neutral-600">
{event.event_date && (
<span className="flex items-center">
<Calendar className="w-4 h-4 mr-1" />
{format(parseISO(event.event_date), 'MMMM d, yyyy')}
</span>
)}
{event.expires_at && (
<span className="flex items-center">
<Clock className="w-4 h-4 mr-1" />
{t('gallery.expires')} {format(parseISO(event.expires_at), 'MMM d')}
</span>
)}
</div>
)}
</div>
</div>
<div className="flex items-center gap-2">
{headerExtra}
<LanguageSelector />
{showDownloadAll && onDownloadAll && (
<Button
variant="primary"
size="md"
leftIcon={<Download className="w-4 h-4" />}
onClick={onDownloadAll}
isLoading={isDownloading}
>
{t('gallery.downloadAll')}
</Button>
)}
{showLogout && onLogout && (
<Button
variant="outline"
size="md"
leftIcon={<LogOut className="w-4 h-4" />}
onClick={onLogout}
>
{t('common.logout')}
</Button>
)}
</div>
</div>
</div>
</header>
{/* Main Content */}
<main className="container">{children}</main>
{/* Footer */}
<footer className="mt-12 py-8 border-t border-neutral-200">
<div className="container text-center">
{brandingSettings?.support_email && (
<p className="text-sm text-neutral-600 mb-2">
{t('gallery.needHelp')}{' '}
<a
href={`mailto:${brandingSettings.support_email}`}
className="text-primary-600 hover:text-primary-700"
>
{brandingSettings.support_email}
</a>
</p>
)}
<p className="text-sm text-neutral-500">
{brandingSettings?.footer_text || '© 2024 Your Company. All rights reserved.'}
</p>
{brandingSettings?.company_name && brandingSettings?.company_tagline && (
<p className="text-xs text-neutral-400 mt-2">
{brandingSettings.company_name} - {brandingSettings.company_tagline}
</p>
)}
{/* Legal Links */}
<div className="mt-4 flex items-center justify-center gap-4">
<Link
to="/impressum"
className="text-xs text-neutral-500 hover:text-neutral-700 transition-colors"
>
{t('legal.impressum')}
</Link>
<span className="text-xs text-neutral-400">|</span>
<Link
to="/datenschutz"
className="text-xs text-neutral-500 hover:text-neutral-700 transition-colors"
>
{t('legal.datenschutz')}
</Link>
</div>
</div>
</footer>
</div>
);
};
GalleryLayout.displayName = 'GalleryLayout';