Files
webshop/shop/app/admin/einstellungen/page.tsx
DanielS 5ea0719225
All checks were successful
Staging Build / build (push) Successful in 3m3s
feat(admin): restructure settings into subpages and hub overview
2026-08-18 22:55:20 +02:00

128 lines
4.6 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import Link from 'next/link';
import { motion } from 'framer-motion';
import { Building2, Palette, KeyRound, Mail, Sliders, ArrowRight, Loader2 } from 'lucide-react';
import { createClient } from '@/lib/supabase/client';
import { useRouter } from 'next/navigation';
const menuItems = [
{
title: 'Firmendaten & Anschrift',
description: 'Verwaltung der eigenen Firmenanschrift, Rechnungsadresse und Sublines für Dokumente.',
href: '/admin/einstellungen/firmendaten',
icon: Building2,
color: 'text-blue-400',
bgColor: 'bg-blue-500/10 border-blue-500/20',
},
{
title: 'Branding & Farbschema',
description: 'Anpassung von Farbschemata (Primary / Accent), Buttons und Themes für den Webshop.',
href: '/admin/einstellungen/branding',
icon: Palette,
color: 'text-violet-400',
bgColor: 'bg-violet-500/10 border-violet-500/20',
},
{
title: 'CASPOS LicServer',
description: 'REST API Konfiguration für den Lizenzserver & automatisierte Schlüsselgenerierung.',
href: '/admin/einstellungen/licserver',
icon: KeyRound,
color: 'text-amber-400',
bgColor: 'bg-amber-500/10 border-amber-500/20',
},
{
title: 'SMTP E-Mail Server',
description: 'Serverdaten & Authentifizierung für Bestellbestätigungen und Benachrichtigungen.',
href: '/admin/settings',
icon: Mail,
color: 'text-sky-400',
bgColor: 'bg-sky-500/10 border-sky-500/20',
},
{
title: 'System & Backup',
description: 'Demo-Banner Steuerung sowie ZIP-Export und Wiederherstellung der Datenbank.',
href: '/admin/einstellungen/system',
icon: Sliders,
color: 'text-emerald-400',
bgColor: 'bg-emerald-500/10 border-emerald-500/20',
},
];
export default function AdminSettingsOverview() {
const [loading, setLoading] = useState(true);
const router = useRouter();
useEffect(() => {
async function checkAccess() {
try {
const supabase = createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
router.push('/auth/login');
return;
}
const { data } = await supabase.from('users').select('role').eq('id', user.id).single();
if (!data || data.role === 'verwaltung') {
router.push('/admin');
return;
}
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
}
checkAccess();
}, [router]);
if (loading) {
return <div className="p-8 text-white flex justify-center items-center"><Loader2 className="w-8 h-8 animate-spin text-primary" /></div>;
}
return (
<div className="p-6 max-w-6xl mx-auto space-y-6">
<motion.div initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }}>
<h1 className="text-3xl font-extrabold tracking-tight text-white">Systemeinstellungen</h1>
<p className="text-slate-400 text-xs mt-1">
Wählen Sie eine Kategorie aus, um Konfigurationen, Server-Anbindungen oder Branding anzupassen.
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
{menuItems.map((item, idx) => {
const Icon = item.icon;
return (
<Link key={idx} href={item.href}>
<motion.div
whileHover={{ y: -4, scale: 1.01 }}
className="p-6 rounded-2xl bg-slate-900/60 border border-slate-800 backdrop-blur-md h-full flex flex-col justify-between space-y-4 hover:border-slate-700 transition-all shadow-md group cursor-pointer"
>
<div className="space-y-3">
<div className={`w-12 h-12 rounded-xl border flex items-center justify-center ${item.bgColor}`}>
<Icon className={`w-6 h-6 ${item.color}`} />
</div>
<div>
<h3 className="font-bold text-lg text-white group-hover:text-primary transition-colors">
{item.title}
</h3>
<p className="text-xs text-slate-400 mt-1 leading-relaxed">
{item.description}
</p>
</div>
</div>
<div className="flex items-center text-xs font-bold text-slate-300 group-hover:text-primary pt-3 border-t border-slate-800/80 gap-1.5 transition-colors">
<span>Einstellungen öffnen</span>
<ArrowRight className="w-4 h-4 transition-transform group-hover:translate-x-1" />
</div>
</motion.div>
</Link>
);
})}
</div>
</div>
);
}