diff --git a/shop/app/admin/settings/page.tsx b/shop/app/admin/settings/page.tsx index 928de99..ba3a080 100644 --- a/shop/app/admin/settings/page.tsx +++ b/shop/app/admin/settings/page.tsx @@ -1,9 +1,13 @@ -"use client"; +'use client'; import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; +import { motion } from 'framer-motion'; import { createClient } from '@/lib/supabase/client'; -import { Loader2 } from 'lucide-react'; +import { Loader2, Mail, Server, ShieldCheck, Key, Send, CheckCircle2, AlertCircle } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; interface Settings { host: string; @@ -13,39 +17,60 @@ interface Settings { pass: string; } +const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { staggerChildren: 0.1 } + } +}; + +const itemVariants = { + hidden: { opacity: 0, y: 15 }, + visible: { opacity: 1, y: 0, transition: { type: 'spring' as const, stiffness: 80, damping: 15 } } +}; + export default function SettingsPage() { const [settings, setSettings] = useState(null); const [loading, setLoading] = useState(true); const [message, setMessage] = useState(''); + const [msgType, setMsgType] = useState<'success' | 'error' | ''>(''); + const [saving, setSaving] = useState(false); + const [testing, setTesting] = useState(false); const router = useRouter(); - // Load current settings and verify access useEffect(() => { async function checkAccessAndLoad() { - const supabase = createClient(); - const { data: { user } } = await supabase.auth.getUser(); - if (!user) { - router.push('/auth/login'); - return; - } - const { data: userData } = await supabase - .from('users') - .select('role') - .eq('id', user.id) - .single(); - if (!userData || userData.role === 'verwaltung') { - router.push('/admin'); - return; - } + try { + const supabase = createClient(); + const { data: { user } } = await supabase.auth.getUser(); + if (!user) { + router.push('/auth/login'); + return; + } - fetch('/api/admin/smtp-settings') - .then((res) => res.json()) - .then((data) => { - if (data.settings) setSettings(data.settings as Settings); - else setMessage('Failed to load settings'); - }) - .catch(() => setMessage('Failed to load settings')) - .finally(() => setLoading(false)); + const [userRes, smtpRes] = await Promise.all([ + supabase.from('users').select('role').eq('id', user.id).single(), + fetch('/api/admin/smtp-settings').then(res => res.json()) + ]); + + if (!userRes.data || userRes.data.role === 'verwaltung') { + router.push('/admin'); + return; + } + + if (smtpRes.settings) { + setSettings(smtpRes.settings as Settings); + } else { + setMessage('Fehler beim Laden der SMTP-Einstellungen.'); + setMsgType('error'); + } + } catch (err) { + setMessage('Fehler beim Laden der Einstellungen.'); + setMsgType('error'); + } finally { + setLoading(false); + } } checkAccessAndLoad(); }, [router]); @@ -62,110 +87,195 @@ export default function SettingsPage() { const handleSave = async (e: React.FormEvent) => { e.preventDefault(); + setSaving(true); setMessage(''); - const res = await fetch('/api/admin/smtp-settings', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(settings), - }); - const data = await res.json(); - if (res.ok) setMessage('Settings saved'); - else setMessage(data.error || 'Error saving settings'); + try { + const res = await fetch('/api/admin/smtp-settings', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(settings), + }); + const data = await res.json(); + if (res.ok) { + setMessage('SMTP-Einstellungen erfolgreich gespeichert.'); + setMsgType('success'); + } else { + setMessage(data.error || 'Fehler beim Speichern.'); + setMsgType('error'); + } + } catch { + setMessage('Verbindungsfehler beim Speichern.'); + setMsgType('error'); + } finally { + setSaving(false); + } }; const handleTestEmail = async () => { + setTesting(true); setMessage(''); - const testPayload = { - to: settings?.user || '', // send to the configured user address - subject: 'Test Email from Webshop Admin', - text: 'This is a test email to verify SMTP configuration.', - }; - const res = await fetch('/api/admin/send-test-email', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(testPayload), - }); - const data = await res.json(); - if (res.ok) setMessage('Test email sent successfully'); - else setMessage(data.error || 'Failed to send test email'); + try { + const testPayload = { + to: settings?.user || '', + subject: 'Test-E-Mail aus dem CASPOS Webshop Admin', + text: 'Dies ist eine automatische Test-E-Mail zur Bestätigung der SMTP-Konfiguration.', + }; + const res = await fetch('/api/admin/send-test-email', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(testPayload), + }); + const data = await res.json(); + if (res.ok) { + setMessage('Test-E-Mail erfolgreich versendet.'); + setMsgType('success'); + } else { + setMessage(data.error || 'Versand der Test-E-Mail fehlgeschlagen.'); + setMsgType('error'); + } + } catch { + setMessage('Fehler beim Senden der Test-E-Mail.'); + setMsgType('error'); + } finally { + setTesting(false); + } }; - if (loading) return
; + if (loading) { + return
; + } return ( -
-

SMTP‑Einstellungen

- {message &&

{message}

} -
- - - - - -
- - -
+
+ {/* Header */} + +

+ + SMTP-Einstellungen +

+

+ Konfigurieren Sie den E-Mail-Server für transaktionale Benachrichtigungen und Bestellbestätigungen. +

+
+ + {/* Dynamic Status Message */} + {message && ( + + {msgType === 'success' ? : } + {message} + + )} + + {/* Bento Grid layout for SMTP */} + + + {/* Bento Box 1: Server Connection Details (2 Spalten) */} + +
+ + Server & Serververbindung +
+ +
+
+ + +
+ +
+ + +
+
+ +
+ +
+
+ + {/* Bento Box 2: Auth Credentials (1 Spalte) */} + +
+
+ + Zugangsdaten +
+ +
+ + +
+ +
+ + +
+
+ + {/* Submit & Test Buttons */} +
+ + +
+
+
);