Files
Joachim Hummel 5f637817ce Improve admin page UI with modern SaaS design
- Add gradient hero section with welcome message
- Redesign stat cards with colorful gradients and hover effects
- Update system status cards with color-coded backgrounds
- Enhance database statistics section with modern cards
- Modernize device list table with gradient headers
- Improve database maintenance section with better visual hierarchy
- Add gradient background to entire admin layout
- Update header with glassmorphism effect and modern badges
- Enhance navigation with improved active states and transitions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 22:37:08 +00:00

110 lines
5.1 KiB
TypeScript
Raw Permalink 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 { signOut, useSession } from "next-auth/react";
import Link from "next/link";
import { usePathname } from "next/navigation";
export default function AdminLayout({
children,
}: {
children: React.ReactNode;
}) {
const pathname = usePathname();
const { data: session } = useSession();
const userRole = (session?.user as any)?.role;
const username = session?.user?.name || '';
const isAdmin = userRole === 'ADMIN';
const isSuperAdmin = username === 'admin';
const allNavigation = [
{ name: "Dashboard", href: "/admin", roles: ['ADMIN', 'VIEWER'], superAdminOnly: false },
{ name: "Devices", href: "/admin/devices", roles: ['ADMIN', 'VIEWER'], superAdminOnly: false },
{ name: "MQTT Provisioning", href: "/admin/mqtt", roles: ['ADMIN'], superAdminOnly: false },
{ name: "Setup Guide", href: "/admin/setup", roles: ['ADMIN', 'VIEWER'], superAdminOnly: false },
{ name: "Users", href: "/admin/users", roles: ['ADMIN'], superAdminOnly: false },
{ name: "Settings", href: "/admin/settings", roles: ['ADMIN'], superAdminOnly: true },
{ name: "Emails", href: "/admin/emails", roles: ['ADMIN'], superAdminOnly: true },
];
// Filter navigation based on user role and super admin status
const navigation = allNavigation.filter(item => {
const hasRole = item.roles.includes(userRole as string);
const hasAccess = item.superAdminOnly ? isSuperAdmin : true;
return hasRole && hasAccess;
});
return (
<div className="min-h-screen bg-gradient-to-br from-gray-50 via-blue-50 to-indigo-50">
{/* Header */}
<header className="bg-white/80 backdrop-blur-lg shadow-lg border-b border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-5">
{/* Top row: Title + User Info + Actions */}
<div className="flex justify-between items-center mb-4 lg:mb-0">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-600 to-indigo-700 flex items-center justify-center text-white text-xl shadow-lg">
🎯
</div>
<h1 className="text-2xl sm:text-3xl font-bold bg-gradient-to-r from-blue-600 to-indigo-700 bg-clip-text text-transparent">
{isAdmin ? 'Admin Panel' : 'Dashboard'}
</h1>
</div>
<div className="flex gap-2 sm:gap-4 items-center">
{/* User info */}
<div className="flex items-center gap-3 text-xs sm:text-sm bg-gradient-to-r from-gray-50 to-slate-50 px-4 py-2 rounded-xl border border-gray-200 shadow-sm">
<span className="text-gray-600 font-medium">Angemeldet als:</span>
<span className="font-bold text-gray-900">{username || session?.user?.email}</span>
{!isAdmin && (
<span className="px-3 py-1 bg-gradient-to-r from-blue-500 to-blue-600 text-white rounded-lg text-xs font-bold shadow-md">Viewer</span>
)}
{isAdmin && (
<span className="px-3 py-1 bg-gradient-to-r from-red-500 to-red-600 text-white rounded-lg text-xs font-bold shadow-md">Admin</span>
)}
</div>
{/* Actions */}
<div className="flex gap-2 items-center border-l-2 border-gray-300 pl-2 sm:pl-4">
<Link
href="/map"
className="px-3 sm:px-5 py-2.5 text-sm text-gray-700 font-bold hover:text-blue-600 bg-white rounded-lg hover:bg-blue-50 transition-all shadow-sm hover:shadow-md border border-gray-200"
>
🗺 Map
</Link>
<button
onClick={async () => {
await signOut({ redirect: false });
window.location.href = '/login';
}}
className="px-3 sm:px-5 py-2.5 bg-gradient-to-r from-red-600 to-red-700 text-white rounded-lg hover:from-red-700 hover:to-red-800 text-sm font-bold shadow-md hover:shadow-lg transition-all"
>
Logout
</button>
</div>
</div>
</div>
{/* Navigation row (scrollable on mobile) */}
<nav className="flex gap-2 overflow-x-auto lg:gap-3 pb-2 lg:pb-0 -mx-4 px-4 sm:mx-0 sm:px-0 mt-4 border-t border-gray-200 pt-4">
{navigation.map((item) => (
<Link
key={item.href}
href={item.href}
className={`px-4 py-2.5 rounded-xl text-sm font-bold transition-all whitespace-nowrap shadow-sm ${
pathname === item.href
? "bg-gradient-to-r from-blue-600 to-indigo-700 text-white shadow-lg scale-105"
: "bg-white text-gray-700 hover:bg-gradient-to-r hover:from-blue-50 hover:to-indigo-50 hover:text-blue-700 border border-gray-200"
}`}
>
{item.name}
</Link>
))}
</nav>
</div>
</header>
{/* Main Content */}
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{children}
</main>
</div>
);
}