import React, { useState } from 'react'; import { Mail, Save, Send, Server, Lock, User, AlertCircle, CheckCircle, Eye, EyeOff, ShieldAlert, } from 'lucide-react'; import { toast } from 'react-toastify'; import { Button, Input, Card, Loading } from '../../components/common'; import { EmailPreviewModal } from '../../components/admin/EmailPreviewModal'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { emailService, type EmailConfig, type EmailTemplate } from '../../services/email.service'; import { useTranslation } from 'react-i18next'; const defaultTemplateKeys = [ { key: 'gallery_created', name: 'Gallery Created', subject: 'Your {{event_name}} photos are ready!', body: `Hi there! Your photo gallery for {{event_name}} is now ready to view. Event: {{event_name}} Date: {{event_date}} Password: {{password}} You can access your photos here: {{gallery_link}} Your gallery will be available until {{expiration_date}}. Make sure to download your photos before they expire! {{#if welcome_message}} Personal message from your host: {{welcome_message}} {{/if}} Best regards, The Photo Sharing Team`, variables: ['event_name', 'event_date', 'password', 'gallery_link', 'expiration_date', 'welcome_message'] }, { key: 'expiration_warning', name: 'Expiration Warning', subject: 'Your {{event_name}} photos expire in {{days_remaining}} days!', body: `Important: Your photo gallery is expiring soon! Your photos from {{event_name}} will no longer be available after {{expiration_date}}. You have {{days_remaining}} days remaining to download your photos. Access your gallery here: {{gallery_link}} Don't forget to download all your favorite memories before they're gone! Best regards, The Photo Sharing Team`, variables: ['event_name', 'days_remaining', 'expiration_date', 'gallery_link'] }, { key: 'gallery_expired', name: 'Gallery Expired', subject: 'Your {{event_name}} photo gallery has expired', body: `Your photo gallery for {{event_name}} has expired and is no longer accessible. The photos have been archived for safekeeping. If you need access to them, please contact the event administrator at {{admin_email}}. Thank you for using our photo sharing service! Best regards, The Photo Sharing Team`, variables: ['event_name', 'admin_email'] }, { key: 'archive_complete', name: 'Archive Complete (Admin)', } ]; export const EmailConfigPage: React.FC = () => { const { t } = useTranslation(); const [activeTab, setActiveTab] = useState<'smtp' | 'templates'>('smtp'); const [selectedTemplateKey, setSelectedTemplateKey] = useState('gallery_created'); const [editedTemplate, setEditedTemplate] = useState>({}); const [editingLang, setEditingLang] = useState<'en' | 'de'>('en'); const [showPassword, setShowPassword] = useState(false); const [testEmail, setTestEmail] = useState(''); const [showPreview, setShowPreview] = useState(false); const [previewData, setPreviewData] = useState<{ subject: string; htmlContent: string; textContent?: string }>({ subject: '', htmlContent: '', textContent: '' }); const queryClient = useQueryClient(); // SMTP Configuration state const [smtpConfig, setSmtpConfig] = useState({ smtp_host: '', smtp_port: 587, smtp_secure: false, smtp_user: '', smtp_pass: '', from_email: '', from_name: 'Photo Sharing', tls_reject_unauthorized: true }); // Fetch SMTP config const { isLoading: configLoading } = useQuery({ queryKey: ['email-config'], queryFn: () => emailService.getConfig(), }); // Fetch email templates const { data: templates = [], isLoading: templatesLoading } = useQuery({ queryKey: ['email-templates'], queryFn: () => emailService.getTemplates() }); // Fetch selected template details const { data: selectedTemplate } = useQuery({ queryKey: ['email-template', selectedTemplateKey], queryFn: () => emailService.getTemplate(selectedTemplateKey), enabled: !!selectedTemplateKey && activeTab === 'templates', }); // Update local state when data is fetched React.useEffect(() => { const fetchConfig = async () => { try { const config = await emailService.getConfig(); setSmtpConfig(config); } catch (error) { // Config might not exist yet } }; fetchConfig(); }, []); React.useEffect(() => { if (selectedTemplate) { setEditedTemplate(selectedTemplate); } }, [selectedTemplate]); // Mutations const saveConfigMutation = useMutation({ mutationFn: (config: EmailConfig) => emailService.updateConfig(config), onSuccess: () => { toast.success(t('toast.emailConfigSaved')); queryClient.invalidateQueries({ queryKey: ['email-config'] }); }, onError: () => { toast.error(t('toast.saveError')); } }); const testEmailMutation = useMutation({ mutationFn: (email: string) => emailService.testEmail(email), onSuccess: () => { toast.success(t('email.testEmailSuccess')); }, onError: () => { toast.error(t('toast.saveError')); } }); const saveTemplateMutation = useMutation({ mutationFn: ({ key, template }: { key: string; template: Partial }) => emailService.updateTemplate(key, template), onSuccess: () => { toast.success(t('toast.saveSuccess')); queryClient.invalidateQueries({ queryKey: ['email-templates'] }); queryClient.invalidateQueries({ queryKey: ['email-template', selectedTemplateKey] }); }, onError: () => { toast.error(t('toast.saveError')); } }); const handleSaveSmtp = () => { // Validate SMTP config if (!smtpConfig.smtp_host || !smtpConfig.smtp_port || !smtpConfig.from_email) { toast.error(t('errors.requiredFields')); return; } saveConfigMutation.mutate(smtpConfig); }; const handleTestEmail = () => { if (!testEmail) { toast.error(t('errors.enterTestEmail')); return; } testEmailMutation.mutate(testEmail); }; const handleSaveTemplate = () => { if (selectedTemplateKey && editedTemplate) { const templateData: Partial = {}; // Include both language versions if (editedTemplate.subject_en !== undefined) templateData.subject_en = editedTemplate.subject_en; if (editedTemplate.subject_de !== undefined) templateData.subject_de = editedTemplate.subject_de; if (editedTemplate.body_html_en !== undefined) templateData.body_html_en = editedTemplate.body_html_en; if (editedTemplate.body_html_de !== undefined) templateData.body_html_de = editedTemplate.body_html_de; if (editedTemplate.body_text_en !== undefined) templateData.body_text_en = editedTemplate.body_text_en; if (editedTemplate.body_text_de !== undefined) templateData.body_text_de = editedTemplate.body_text_de; saveTemplateMutation.mutate({ key: selectedTemplateKey, template: templateData }); } }; const handlePreviewTemplate = async () => { if (!selectedTemplateKey || !editedTemplate) return; // Generate sample data based on the template const sampleData: Record = { event_name: 'John & Jane Wedding', event_date: 'December 25, 2024', password: 'wedding2024', gallery_link: 'https://photos.example.com/gallery/john-jane-wedding', expiration_date: 'January 25, 2025', welcome_message: 'Thank you for celebrating our special day with us!', days_remaining: '30', admin_email: 'admin@example.com', host_email: 'host@example.com' }; try { const preview = await emailService.previewTemplate(selectedTemplateKey, sampleData, editingLang); setPreviewData({ subject: preview.subject, htmlContent: preview.body_html, textContent: preview.body_text }); setShowPreview(true); } catch (error) { toast.error(t('toast.saveError')); } }; const renderVariableHelp = () => { const variables = editedTemplate.variables || []; return (

{t('email.templateVariables')}

{variables.map(variable => ( {`{{${variable}}}`} ))}

{t('email.variableHelp')}

); }; if (configLoading || templatesLoading) { return (
); } return (

{t('email.title')}

{t('email.subtitle')}

{/* Tab Navigation */}
{/* SMTP Settings Tab */} {activeTab === 'smtp' && (

{t('email.smtpConfiguration')}

setSmtpConfig(prev => ({ ...prev, smtp_host: e.target.value }))} placeholder="smtp.gmail.com" leftIcon={} />
setSmtpConfig(prev => ({ ...prev, smtp_port: parseInt(e.target.value) || 587 }))} placeholder="587" />
{/* Ignore SSL Certificate Errors */}
{!smtpConfig.tls_reject_unauthorized && (

{t('email.ignoreSslWarning')}

)}
setSmtpConfig(prev => ({ ...prev, smtp_user: e.target.value }))} placeholder="your-email@gmail.com" leftIcon={} />
setSmtpConfig(prev => ({ ...prev, smtp_pass: e.target.value }))} placeholder={t('email.enterPassword')} leftIcon={} />
setSmtpConfig(prev => ({ ...prev, from_email: e.target.value }))} placeholder="noreply@yourdomain.com" leftIcon={} />
setSmtpConfig(prev => ({ ...prev, from_name: e.target.value }))} placeholder="Photo Sharing" />

{t('email.testEmailSection')}

{t('email.beforeTesting')}

  • {t('email.saveSmtpFirst')}
  • {t('email.ensureFirewall')}
  • {t('email.gmailAppPassword')}
setTestEmail(e.target.value)} placeholder="test@example.com" leftIcon={} />

{t('email.commonSmtpSettings')}

  • Gmail: smtp.gmail.com:587 (TLS)
  • Outlook: smtp-mail.outlook.com:587 (TLS)
  • SendGrid: smtp.sendgrid.net:587 (TLS)
)} {/* Email Templates Tab */} {activeTab === 'templates' && (

{t('email.templates')}

{templates.map(template => { const templateInfo = defaultTemplateKeys.find(t => t.key === template.template_key); return ( ); })}

{t('email.editTemplate')}

t.key === selectedTemplateKey)?.name || selectedTemplateKey} disabled className="bg-neutral-50" />
setEditedTemplate(prev => ({ ...prev, [editingLang === 'en' ? 'subject_en' : 'subject_de']: e.target.value }))} placeholder="Email subject" />