import React, { useState } from 'react'; import { Save, Database, Globe, Key, AlertCircle, Image } 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' | 'storage' | 'security' | 'categories'>('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 === 'storage' }); // 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' }); // 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: '' }); 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' }); // 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 || '' }); } }, [settings]); // 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('General settings saved successfully'); queryClient.invalidateQueries({ queryKey: ['admin-settings'] }); }, onError: () => { toast.error('Failed to save general settings'); } }); 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('Security settings saved successfully'); queryClient.invalidateQueries({ queryKey: ['admin-settings'] }); }, onError: () => { toast.error('Failed to save security settings'); } }); if (isLoading) { return (
); } return (

System Settings

Configure system-wide settings and preferences

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

Site Configuration

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

Used for generating gallery links in emails

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" />

Comma-separated list of file extensions

Feature Toggles

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

Sets the default language for all gallery pages and login screens

)} {/* Storage Tab */} {activeTab === 'storage' && storageInfo && (

Storage Overview

Total Used

{settingsService.formatBytes(storageInfo.total_used)}

Archive Storage

{settingsService.formatBytes(storageInfo.archive_storage)}

Storage Limit

{settingsService.formatBytes(storageInfo.storage_limit)}

Storage Usage {Math.round((storageInfo.total_used / storageInfo.storage_limit) * 100)}%

Storage by Event

{storageInfo.storage_by_event.slice(0, 10).map((event) => (
{event.event_name} {settingsService.formatBytes(event.size)}
))}

Storage Management

Consider archiving or deleting old events to free up storage space. Archived events are compressed and use less storage than active galleries.

)} {/* Security Tab */} {activeTab === 'security' && (

Password Settings

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

Session & Authentication

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" />

reCAPTCHA Settings

{securitySettings.enable_recaptcha && ( <>
setSecuritySettings(prev => ({ ...prev, recaptcha_site_key: e.target.value }))} placeholder="Your reCAPTCHA site key" leftIcon={} />
setSecuritySettings(prev => ({ ...prev, recaptcha_secret_key: e.target.value }))} placeholder="Your reCAPTCHA secret key" leftIcon={} />
)}

Get your reCAPTCHA keys from Google reCAPTCHA Admin

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

About Photo Categories

Global categories are available for all events. You can also create event-specific categories when editing individual events. Categories help organize photos and allow guests to filter photos by type in the gallery view.

)}
); };