Modernize all admin interface pages with consistent design language: - Add hero sections with gradient backgrounds and blur effects - Implement modern card designs with hover animations - Use gradient buttons with shadow effects - Add emoji icons in colored containers - Apply consistent color themes per page - Enhance user experience with smooth transitions Pages updated: - /admin/devices (purple theme) - /admin/mqtt (cyan/blue theme) - /admin/setup (emerald theme) - /admin/users (violet theme) - /admin/settings (indigo theme) - /admin/emails (pink/rose theme) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
194 lines
7.8 KiB
TypeScript
194 lines
7.8 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import { EMAIL_TEMPLATES, EmailTemplate } from "@/lib/types/smtp";
|
||
|
||
export default function EmailsPage() {
|
||
const [selectedTemplate, setSelectedTemplate] = useState<string>('welcome');
|
||
const [testEmail, setTestEmail] = useState('');
|
||
const [sending, setSending] = useState(false);
|
||
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
|
||
const [showSendModal, setShowSendModal] = useState(false);
|
||
|
||
const handleSendTest = async () => {
|
||
if (!testEmail) {
|
||
alert('Please enter a test email address');
|
||
return;
|
||
}
|
||
|
||
setSending(true);
|
||
setMessage(null);
|
||
|
||
try {
|
||
const response = await fetch('/api/admin/emails/send-test', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
template: selectedTemplate,
|
||
email: testEmail,
|
||
}),
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (!response.ok) {
|
||
throw new Error(data.error || 'Failed to send');
|
||
}
|
||
|
||
setMessage({ type: 'success', text: data.message });
|
||
setShowSendModal(false);
|
||
setTestEmail('');
|
||
} catch (error: any) {
|
||
setMessage({ type: 'error', text: error.message || 'Failed to send test email' });
|
||
} finally {
|
||
setSending(false);
|
||
}
|
||
};
|
||
|
||
const previewUrl = `/api/admin/emails/preview?template=${selectedTemplate}`;
|
||
|
||
return (
|
||
<div className="space-y-8">
|
||
{/* Hero Section with Gradient */}
|
||
<div className="relative overflow-hidden rounded-2xl bg-gradient-to-br from-pink-600 via-rose-700 to-red-800 p-8 shadow-xl">
|
||
<div className="absolute top-0 right-0 -mt-4 -mr-4 h-40 w-40 rounded-full bg-white/10 blur-3xl"></div>
|
||
<div className="absolute bottom-0 left-0 -mb-4 -ml-4 h-40 w-40 rounded-full bg-white/10 blur-3xl"></div>
|
||
<div className="relative">
|
||
<h2 className="text-4xl font-bold text-white mb-2">Email Templates</h2>
|
||
<p className="text-pink-100 text-lg">Verwalte und teste E-Mail-Vorlagen</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Status Message */}
|
||
{message && (
|
||
<div
|
||
className={`p-5 rounded-xl shadow-lg flex items-center gap-3 ${
|
||
message.type === 'success'
|
||
? 'bg-gradient-to-r from-green-50 to-emerald-50 border-2 border-green-200 text-green-800'
|
||
: 'bg-gradient-to-r from-red-50 to-orange-50 border-2 border-red-200 text-red-800'
|
||
}`}
|
||
>
|
||
<span className="text-2xl">{message.type === 'success' ? '✓' : '⚠️'}</span>
|
||
<span className="font-semibold">{message.text}</span>
|
||
</div>
|
||
)}
|
||
|
||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
{/* Template List */}
|
||
<div className="lg:col-span-1 space-y-4">
|
||
<div className="bg-white rounded-2xl shadow-lg overflow-hidden">
|
||
<div className="bg-gradient-to-r from-pink-50 to-rose-50 px-6 py-4 border-b border-pink-100">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-pink-600 to-rose-600 flex items-center justify-center text-white text-xl">
|
||
📧
|
||
</div>
|
||
<h3 className="text-lg font-bold text-gray-900">Templates</h3>
|
||
</div>
|
||
</div>
|
||
<div className="p-4">
|
||
<div className="space-y-2">
|
||
{EMAIL_TEMPLATES.map((template) => (
|
||
<button
|
||
key={template.name}
|
||
onClick={() => setSelectedTemplate(template.name)}
|
||
className={`w-full text-left px-4 py-3 rounded-xl transition-all transform ${
|
||
selectedTemplate === template.name
|
||
? 'bg-gradient-to-r from-pink-600 to-rose-600 text-white shadow-lg scale-105'
|
||
: 'bg-gradient-to-br from-gray-50 to-slate-50 hover:from-pink-50 hover:to-rose-50 text-gray-900 hover:shadow-md'
|
||
}`}
|
||
>
|
||
<p className="font-bold">{template.subject}</p>
|
||
<p className={`text-sm mt-1 ${
|
||
selectedTemplate === template.name
|
||
? 'text-pink-100'
|
||
: 'text-gray-600'
|
||
}`}>
|
||
{template.description}
|
||
</p>
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Send Test Button */}
|
||
<button
|
||
onClick={() => setShowSendModal(true)}
|
||
className="w-full px-6 py-4 bg-gradient-to-r from-green-500 to-emerald-600 text-white rounded-xl hover:from-green-600 hover:to-emerald-700 font-bold shadow-lg hover:shadow-xl transition-all flex items-center justify-center gap-2"
|
||
>
|
||
<span className="text-xl">📨</span>
|
||
Send Test Email
|
||
</button>
|
||
</div>
|
||
|
||
{/* Preview */}
|
||
<div className="lg:col-span-2">
|
||
<div className="bg-white rounded-2xl shadow-lg overflow-hidden">
|
||
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 px-6 py-4 border-b border-blue-100">
|
||
<div className="flex justify-between items-center">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-600 to-indigo-600 flex items-center justify-center text-white text-xl">
|
||
👁️
|
||
</div>
|
||
<h3 className="text-lg font-bold text-gray-900">Preview</h3>
|
||
</div>
|
||
<span className="text-sm font-semibold text-gray-700 bg-white px-3 py-1.5 rounded-lg shadow-sm">
|
||
{EMAIL_TEMPLATES.find(t => t.name === selectedTemplate)?.subject}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div className="p-4">
|
||
<iframe
|
||
src={previewUrl}
|
||
className="w-full border-2 border-gray-200 rounded-xl shadow-inner"
|
||
style={{ height: '600px' }}
|
||
title="Email Preview"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Send Test Email Modal */}
|
||
{showSendModal && (
|
||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||
<div className="bg-white rounded-lg p-6 w-full max-w-md">
|
||
<h3 className="text-xl font-bold mb-4">Send Test Email</h3>
|
||
<p className="text-sm text-gray-600 mb-2">
|
||
Template: <strong>{EMAIL_TEMPLATES.find(t => t.name === selectedTemplate)?.subject}</strong>
|
||
</p>
|
||
<p className="text-sm text-gray-600 mb-4">
|
||
Enter your email address to receive a test email.
|
||
</p>
|
||
<input
|
||
type="email"
|
||
value={testEmail}
|
||
onChange={(e) => setTestEmail(e.target.value)}
|
||
placeholder="your-email@example.com"
|
||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 mb-4"
|
||
/>
|
||
<div className="flex gap-3">
|
||
<button
|
||
onClick={() => {
|
||
setShowSendModal(false);
|
||
setTestEmail('');
|
||
}}
|
||
className="flex-1 px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-100"
|
||
>
|
||
Cancel
|
||
</button>
|
||
<button
|
||
onClick={handleSendTest}
|
||
disabled={sending || !testEmail}
|
||
className="flex-1 px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 disabled:bg-gray-400"
|
||
>
|
||
{sending ? 'Sending...' : 'Send Test'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|