From 9dc377798572e21db8ed98743c2235c351ff3008 Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 23 Jul 2025 09:29:41 +0200 Subject: [PATCH] CRITICAL FIX: prevent gallery pages redirecting to admin login MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users were being redirected from gallery pages to admin login due to useLocalizedDate hook trying to fetch admin settings. Fixed by: 1. Added general_date_format to public settings endpoint 2. Created publicSettingsService for unauthenticated access 3. Updated useLocalizedDate to use public settings instead of admin 4. Fixed API interceptor to not redirect on public endpoint 401s 5. Added backups/ and test-archiver/ to .gitignore This restores gallery access for all users. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .gitignore | 4 +++ backend/src/routes/publicSettings.js | 1 + frontend/src/config/api.ts | 4 +-- frontend/src/hooks/useLocalizedDate.ts | 9 ++--- .../src/services/publicSettings.service.ts | 34 +++++++++++++++++++ 5 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 frontend/src/services/publicSettings.service.ts diff --git a/.gitignore b/.gitignore index 76b7fdd..22bdbc6 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,10 @@ coverage/ *.tmp *.temp +# Backup and test directories +backups/ +test-archiver/ + # Keep directory structure !storage/events/active/.gitkeep !storage/events/archived/.gitkeep diff --git a/backend/src/routes/publicSettings.js b/backend/src/routes/publicSettings.js index 1a8c5ba..388268f 100644 --- a/backend/src/routes/publicSettings.js +++ b/backend/src/routes/publicSettings.js @@ -45,6 +45,7 @@ router.get('/', async (req, res) => { theme_config: settingsObject.theme_config || null, default_language: settingsObject.general_default_language || 'en', enable_analytics: settingsObject.general_enable_analytics !== false, + general_date_format: settingsObject.general_date_format || 'PPP', enable_recaptcha: settingsObject.security_enable_recaptcha === true || settingsObject.security_enable_recaptcha === 'true', recaptcha_site_key: settingsObject.security_recaptcha_site_key || null, maintenance_mode: settingsObject.general_maintenance_mode === true || settingsObject.general_maintenance_mode === 'true', diff --git a/frontend/src/config/api.ts b/frontend/src/config/api.ts index 1539c44..f565956 100644 --- a/frontend/src/config/api.ts +++ b/frontend/src/config/api.ts @@ -83,8 +83,8 @@ api.interceptors.response.use( } if (error.response?.status === 401) { - // Check if it's an admin route - const isAdminRoute = error.config?.url?.includes('/admin'); + // Check if it's an admin route (but not public endpoints) + const isAdminRoute = error.config?.url?.includes('/admin') && !error.config?.url?.includes('/public/'); const currentPath = window.location.pathname; if (isAdminRoute) { diff --git a/frontend/src/hooks/useLocalizedDate.ts b/frontend/src/hooks/useLocalizedDate.ts index 4ba5af3..1f16d64 100644 --- a/frontend/src/hooks/useLocalizedDate.ts +++ b/frontend/src/hooks/useLocalizedDate.ts @@ -2,16 +2,17 @@ import { useTranslation } from 'react-i18next'; import { format as dateFnsFormat, formatDistanceToNow as dateFnsFormatDistanceToNow } from 'date-fns'; import { de, enUS } from 'date-fns/locale'; import { useQuery } from '@tanstack/react-query'; -import { settingsService } from '../services/settings.service'; +import { publicSettingsService } from '../services/publicSettings.service'; export const useLocalizedDate = () => { const { i18n } = useTranslation(); - // Fetch admin settings to get the date format + // Fetch public settings to get the date format const { data: settings } = useQuery({ - queryKey: ['admin-settings-general'], - queryFn: () => settingsService.getSettingsByType('general'), + queryKey: ['public-settings'], + queryFn: () => publicSettingsService.getPublicSettings(), staleTime: 5 * 60 * 1000, // Cache for 5 minutes + retry: 1, // Only retry once to avoid blocking the UI }); const getLocale = () => { diff --git a/frontend/src/services/publicSettings.service.ts b/frontend/src/services/publicSettings.service.ts new file mode 100644 index 0000000..eba2821 --- /dev/null +++ b/frontend/src/services/publicSettings.service.ts @@ -0,0 +1,34 @@ +import { api } from '../config/api'; + +export interface PublicSettings { + branding_company_name: string; + branding_company_tagline: string; + branding_support_email: string; + branding_footer_text: string; + branding_watermark_enabled: boolean; + branding_watermark_logo_url: string; + branding_watermark_position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'center'; + branding_watermark_opacity: number; + branding_watermark_size: number; + branding_favicon_url: string; + branding_logo_url: string; + theme_config: any; + default_language: string; + enable_analytics: boolean; + general_date_format: string; + enable_recaptcha: boolean; + recaptcha_site_key: string | null; + maintenance_mode: boolean; + umami_enabled: boolean; + umami_url: string | null; + umami_website_id: string | null; + umami_share_url: string | null; +} + +export const publicSettingsService = { + // Get public settings (no authentication required) + async getPublicSettings(): Promise { + const response = await api.get('/public/settings'); + return response.data; + } +}; \ No newline at end of file