Fix brand theme application and add comprehensive translations

- Fixed theme not being reflected on gallery and admin login pages
- Created GlobalThemeProvider to apply themes globally
- Updated gallery and admin login pages to use dynamic CSS variables
- Added complete translations for all admin sections in English and German:
  - Notifications management
  - Event view and creation
  - Photo upload functionality
  - Category management
  - Archive page view
  - Analytics dashboard
  - Branding and theme settings
  - System settings
  - CMS page management
  - Email configuration
- Fixed admin photo management display issues
- Fixed photo upload category assignment
- Added password reset functionality for galleries
- Improved error handling and user feedback

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-08 17:07:40 +02:00
parent 2012b0bab9
commit d594d00227
79 changed files with 4570 additions and 329 deletions
@@ -54,8 +54,12 @@ export const AuthenticatedImage: React.FC<AuthenticatedImageProps> = ({
}
}
console.log('Fetching authenticated image:', imageUrl);
const response = await fetch(imageUrl, {
// Prepend API URL for absolute paths
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:3001';
const fullImageUrl = imageUrl.startsWith('/') ? `${apiUrl}${imageUrl}` : imageUrl;
console.log('Fetching authenticated image:', fullImageUrl);
const response = await fetch(fullImageUrl, {
headers: {
'Authorization': `Bearer ${token}`
}
@@ -0,0 +1,54 @@
import React, { useEffect, useState } from 'react';
import ReCAPTCHA from 'react-google-recaptcha';
import { useQuery } from '@tanstack/react-query';
interface ReCaptchaProps {
onChange: (token: string | null) => void;
onExpired?: () => void;
size?: 'normal' | 'compact';
}
export const ReCaptcha: React.FC<ReCaptchaProps> = ({
onChange,
onExpired,
size = 'normal'
}) => {
const recaptchaRef = React.useRef<ReCAPTCHA>(null);
const [siteKey, setSiteKey] = useState<string>('');
// Fetch public settings to get reCAPTCHA site key
const { data: settings } = useQuery({
queryKey: ['public-settings'],
queryFn: async () => {
const response = await fetch(`${import.meta.env.VITE_API_URL || 'http://localhost:3001'}/api/public/settings`);
return response.json();
},
staleTime: 5 * 60 * 1000, // Cache for 5 minutes
});
useEffect(() => {
if (settings?.recaptcha_site_key) {
setSiteKey(settings.recaptcha_site_key);
}
}, [settings]);
// If reCAPTCHA is not enabled or site key is not available, return null
if (!settings?.enable_recaptcha || !siteKey) {
return null;
}
return (
<div className="flex justify-center">
<ReCAPTCHA
ref={recaptchaRef}
sitekey={siteKey}
onChange={onChange}
onExpired={onExpired}
size={size}
theme="light"
/>
</div>
);
};
export default ReCaptcha;
+2 -1
View File
@@ -15,4 +15,5 @@ export { OfflineIndicator, useOnlineStatus } from './OfflineIndicator';
export { SkipLink } from './SkipLink';
export { DynamicFavicon } from './DynamicFavicon';
export { LanguageSelector } from './LanguageSelector';
export { AuthenticatedImage } from './AuthenticatedImage';
export { AuthenticatedImage } from './AuthenticatedImage';
export { ReCaptcha } from './ReCaptcha';