Files
location-mqtt-tracker-app/app/admin/emails/page.tsx
Joachim Hummel a39b53151e Apply modern SaaS design to all admin pages
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>
2025-11-29 23:31:25 +00:00

194 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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>
);
}