CRITICAL FIX: prevent gallery pages redirecting to admin login
Mirror to GitHub / mirror (push) Successful in 48s
Test and Lint / backend-test (push) Successful in 1m39s
continuous-integration/drone/push Build is passing
Test and Lint / frontend-test (push) Successful in 2m14s
Version and Release / version-bump (push) Successful in 52s
Version and Release / trigger-drone (push) Successful in 3s

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 <noreply@anthropic.com>
This commit is contained in:
2025-07-23 09:29:41 +02:00
parent f147bd6cfb
commit 554bf1d43c
5 changed files with 46 additions and 6 deletions
+4
View File
@@ -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
+1
View File
@@ -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',
+2 -2
View File
@@ -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) {
+5 -4
View File
@@ -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 = () => {
@@ -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<PublicSettings> {
const response = await api.get<PublicSettings>('/public/settings');
return response.data;
}
};