import React, { useState } from 'react'; import { Save, Database, Globe, Key, AlertCircle, Image, Server, CheckCircle, Clock, HardDrive, Activity } from 'lucide-react'; import { toast } from 'react-toastify'; import { Button, Card, Input, Loading } from '../../components/common'; import { CategoryManager } from '../../components/admin/CategoryManager'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { settingsService } from '../../services/settings.service'; import { useTranslation } from 'react-i18next'; export const SettingsPage: React.FC = () => { const [activeTab, setActiveTab] = useState<'general' | 'status' | 'security' | 'categories' | 'analytics'>('general'); const queryClient = useQueryClient(); const { t, i18n } = useTranslation(); // Fetch settings const { data: settings, isLoading } = useQuery({ queryKey: ['admin-settings'], queryFn: () => settingsService.getAllSettings(), }); // Fetch storage info const { data: storageInfo } = useQuery({ queryKey: ['admin-storage-info'], queryFn: () => settingsService.getStorageInfo(), enabled: activeTab === 'status' }); // Fetch system status const { data: systemStatus } = useQuery({ queryKey: ['system-status'], queryFn: () => settingsService.getSystemStatus(), enabled: activeTab === 'status', refetchInterval: 30000 // Refresh every 30 seconds }); // General settings state const [generalSettings, setGeneralSettings] = useState({ site_url: '', default_expiration_days: 30, max_file_size_mb: 50, allowed_file_types: 'jpg,jpeg,png,gif,webp', enable_watermark: false, enable_analytics: true, enable_registration: false, maintenance_mode: false, default_language: 'en', date_format: { format: 'DD/MM/YYYY', locale: 'en-GB' } }); // Security settings state const [securitySettings, setSecuritySettings] = useState({ require_password: true, password_min_length: 8, enable_2fa: false, session_timeout_minutes: 60, max_login_attempts: 5, enable_recaptcha: false, recaptcha_site_key: '', recaptcha_secret_key: '' }); // Analytics settings state const [analyticsSettings, setAnalyticsSettings] = useState({ umami_enabled: false, umami_url: '', umami_website_id: '', umami_share_url: '' }); React.useEffect(() => { if (settings) { // Set the language if it's different from current if (settings.general_default_language && settings.general_default_language !== i18n.language) { i18n.changeLanguage(settings.general_default_language); } // Extract general settings setGeneralSettings({ site_url: settings.general_site_url || '', default_expiration_days: settings.general_default_expiration_days || 30, max_file_size_mb: settings.general_max_file_size_mb || 50, allowed_file_types: settings.general_allowed_file_types || 'jpg,jpeg,png,gif,webp', enable_watermark: settings.general_enable_watermark || false, enable_analytics: settings.general_enable_analytics || true, enable_registration: settings.general_enable_registration || false, maintenance_mode: settings.general_maintenance_mode || false, default_language: settings.general_default_language || 'en', date_format: settings.general_date_format || { format: 'DD/MM/YYYY', locale: 'en-GB' } }); // Extract security settings setSecuritySettings({ require_password: settings.security_require_password || true, password_min_length: settings.security_password_min_length || 8, enable_2fa: settings.security_enable_2fa || false, session_timeout_minutes: settings.security_session_timeout_minutes || 60, max_login_attempts: settings.security_max_login_attempts || 5, enable_recaptcha: settings.security_enable_recaptcha || false, recaptcha_site_key: settings.security_recaptcha_site_key || '', recaptcha_secret_key: settings.security_recaptcha_secret_key || '' }); // Extract analytics settings setAnalyticsSettings({ umami_enabled: settings.analytics_umami_enabled || false, umami_url: settings.analytics_umami_url || '', umami_website_id: settings.analytics_umami_website_id || '', umami_share_url: settings.analytics_umami_share_url || '' }); } }, [settings, i18n]); // Save mutations const saveGeneralMutation = useMutation({ mutationFn: async () => { // Convert to the format expected by the API const settingsData: Record = {}; Object.entries(generalSettings).forEach(([key, value]) => { settingsData[`general_${key}`] = value; }); return settingsService.updateSettings(settingsData); }, onSuccess: () => { toast.success(t('toast.settingsSaved')); queryClient.invalidateQueries({ queryKey: ['admin-settings'] }); }, onError: () => { toast.error(t('toast.saveError')); } }); const saveSecurityMutation = useMutation({ mutationFn: async () => { // Convert to the format expected by the API const settingsData: Record = {}; Object.entries(securitySettings).forEach(([key, value]) => { settingsData[`security_${key}`] = value; }); return settingsService.updateSettings(settingsData); }, onSuccess: () => { toast.success(t('toast.settingsSaved')); queryClient.invalidateQueries({ queryKey: ['admin-settings'] }); }, onError: () => { toast.error(t('toast.saveError')); } }); const saveAnalyticsMutation = useMutation({ mutationFn: async () => { // Convert to the format expected by the API const settingsData: Record = {}; Object.entries(analyticsSettings).forEach(([key, value]) => { settingsData[`analytics_${key}`] = value; }); return settingsService.updateSettings(settingsData); }, onSuccess: () => { toast.success(t('toast.settingsSaved')); queryClient.invalidateQueries({ queryKey: ['admin-settings'] }); }, onError: () => { toast.error(t('toast.saveError')); } }); if (isLoading) { return (
); } return (

{t('settings.title')}

{t('settings.subtitle')}

{/* Tab Navigation */}
{/* General Settings Tab */} {activeTab === 'general' && (

{t('settings.general.siteConfiguration')}

setGeneralSettings(prev => ({ ...prev, site_url: e.target.value }))} placeholder="https://yourdomain.com" leftIcon={} />

{t('settings.general.siteUrlHelp')}

setGeneralSettings(prev => ({ ...prev, default_expiration_days: parseInt(e.target.value) || 30 }))} min="1" max="365" />
setGeneralSettings(prev => ({ ...prev, max_file_size_mb: parseInt(e.target.value) || 50 }))} min="1" max="500" />
setGeneralSettings(prev => ({ ...prev, allowed_file_types: e.target.value }))} placeholder="jpg,jpeg,png,gif" />

{t('settings.general.allowedFileTypesHelp')}

{t('settings.general.featureToggles')}

{t('settings.general.language')}

{t('settings.general.defaultLanguageHelp')}

{t('settings.general.dateTimeFormat')}

{t('settings.general.dateFormatHelp')}

)} {/* System Status Tab */} {activeTab === 'status' && (
{/* Storage Overview */} {storageInfo && (

{t('settings.systemStatus.storageOverview')}

{t('settings.storage.totalUsed')}

{settingsService.formatBytes(storageInfo.total_used)}

{t('settings.storage.archiveStorage')}

{settingsService.formatBytes(storageInfo.archive_storage)}

{t('settings.storage.storageLimit')}

{settingsService.formatBytes(storageInfo.storage_limit)}

{t('settings.storage.storageUsage')} {Math.round((storageInfo.total_used / storageInfo.storage_limit) * 100)}%
)} {/* System Information */} {systemStatus && ( <>

{t('settings.systemStatus.systemInfo')}

{t('settings.systemStatus.platform')}

{systemStatus.system.platform}

{t('settings.systemStatus.nodeVersion')}

{systemStatus.system.nodeVersion}

{t('settings.systemStatus.uptime')}

{Math.floor(systemStatus.system.uptime / 3600)}h {Math.floor((systemStatus.system.uptime % 3600) / 60)}m

{t('settings.systemStatus.cpuCores')}

{systemStatus.system.cpu.cores}

{t('settings.systemStatus.memoryUsage')}

{t('settings.systemStatus.memoryUsed')} {settingsService.formatBytes(systemStatus.system.memory.used)} / {settingsService.formatBytes(systemStatus.system.memory.total)}

{t('settings.systemStatus.databaseInfo')}

{systemStatus.database.tables.events}

{t('navigation.events')}

{systemStatus.database.tables.photos}

{t('settings.systemStatus.photos')}

{systemStatus.database.tables.admins}

{t('settings.systemStatus.admins')}

{systemStatus.database.tables.categories}

{t('settings.categories.title')}

{settingsService.formatBytes(systemStatus.database.size)}

{t('settings.systemStatus.dbSize')}

{t('settings.systemStatus.services')}

{t('settings.systemStatus.fileWatcher')}

{t('settings.systemStatus.fileWatcherDesc')}

{t('settings.systemStatus.expirationChecker')}

{t('settings.systemStatus.expirationCheckerDesc')}

{t('settings.systemStatus.emailProcessor')}

{t('settings.systemStatus.emailProcessorDesc')}

{t('settings.systemStatus.emailQueue')}

{t('settings.systemStatus.pending')}: {systemStatus.emailQueue.pending} {systemStatus.emailQueue.stuck > 0 && ( ({systemStatus.emailQueue.stuck} stuck) )}
{t('settings.systemStatus.sent')}: {systemStatus.emailQueue.sent}
{t('settings.systemStatus.failed')}: {systemStatus.emailQueue.failed}
{systemStatus.emailQueue.stuck > 0 && (

⚠️ {systemStatus.emailQueue.stuck} email(s) stuck: These emails have exceeded retry limits and won't be processed automatically. Only {systemStatus.emailQueue.processable} of {systemStatus.emailQueue.pending} pending emails will be processed.

)}
)} {/* Last update time */} {systemStatus && (
{t('settings.systemStatus.lastUpdate')}: {new Date(systemStatus.timestamp).toLocaleString()}
)}
)} {/* Security Tab */} {activeTab === 'security' && (

{t('settings.security.passwordSettings')}

setSecuritySettings(prev => ({ ...prev, password_min_length: parseInt(e.target.value) || 8 }))} min="4" max="32" />

{t('settings.security.sessionAuth')}

setSecuritySettings(prev => ({ ...prev, session_timeout_minutes: parseInt(e.target.value) || 60 }))} min="5" max="1440" />
setSecuritySettings(prev => ({ ...prev, max_login_attempts: parseInt(e.target.value) || 5 }))} min="3" max="10" />

{t('settings.security.recaptchaSettings')}

{securitySettings.enable_recaptcha && ( <>
setSecuritySettings(prev => ({ ...prev, recaptcha_site_key: e.target.value }))} placeholder={t('settings.security.siteKey')} leftIcon={} />
setSecuritySettings(prev => ({ ...prev, recaptcha_secret_key: e.target.value }))} placeholder={t('settings.security.secretKey')} leftIcon={} />
)}

{t('settings.security.recaptchaHelp')} Google reCAPTCHA Admin

)} {/* Categories Tab */} {activeTab === 'categories' && (

{t('settings.categories.about')}

{t('settings.categories.aboutText')}

)} {/* Analytics Tab */} {activeTab === 'analytics' && (

{t('settings.analytics.umamiIntegration')}

{analyticsSettings.umami_enabled && ( <>
setAnalyticsSettings(prev => ({ ...prev, umami_url: e.target.value }))} placeholder="https://analytics.yourdomain.com" leftIcon={} />

{t('settings.analytics.umamiUrlHelp')}

setAnalyticsSettings(prev => ({ ...prev, umami_website_id: e.target.value }))} placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" leftIcon={} />

{t('settings.analytics.websiteIdHelp')}

setAnalyticsSettings(prev => ({ ...prev, umami_share_url: e.target.value }))} placeholder="https://analytics.yourdomain.com/share/..." leftIcon={} />

{t('settings.analytics.shareUrlHelp')}

)}

{t('settings.analytics.umamiInfo')}

{t('settings.analytics.umamiInfoText')}

{t('settings.analytics.learnMore')}
{/* Backend Analytics Info */}

{t('settings.analytics.backendAnalytics')}

{t('settings.analytics.backendAnalyticsText')}

{t('settings.analytics.tracked')}

  • • {t('settings.analytics.galleryViews')}
  • • {t('settings.analytics.photoDownloads')}
  • • {t('settings.analytics.uniqueVisitors')}
  • • {t('settings.analytics.deviceTypes')}

{t('settings.analytics.privacy')}

{t('settings.analytics.privacyText')}

)}
); };