Files
GuardDen/dashboard/frontend/src/components/Layout.tsx
latte 574a07d127
Some checks failed
CI/CD Pipeline / Security Scanning (push) Has been cancelled
CI/CD Pipeline / Tests (3.11) (push) Has been cancelled
CI/CD Pipeline / Tests (3.12) (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (push) Has been cancelled
Update dashboard and Docker compose
2026-01-24 19:14:00 +01:00

116 lines
3.9 KiB
TypeScript

/**
* Main dashboard layout with navigation
*/
import { Link, Outlet, useLocation } from "react-router-dom";
import { useQuery } from "@tanstack/react-query";
import { authApi } from "../services/api";
const navigation = [
{ name: "Dashboard", href: "/" },
{ name: "Servers", href: "/servers" },
{ name: "Users", href: "/users" },
{ name: "Chats", href: "/chats" },
{ name: "Moderation", href: "/moderation" },
{ name: "Analytics", href: "/analytics" },
{ name: "Settings", href: "/settings" },
];
export function Layout() {
const location = useLocation();
const { data: me } = useQuery({
queryKey: ["me"],
queryFn: authApi.getMe,
});
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<header className="bg-white border-b border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center">
<h1 className="text-xl font-bold text-gray-900">GuardDen</h1>
<nav className="ml-10 flex space-x-4">
{navigation.map((item) => {
const isActive = location.pathname === item.href;
return (
<Link
key={item.name}
to={item.href}
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
isActive
? "bg-gray-100 text-gray-900"
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900"
}`}
>
{item.name}
</Link>
);
})}
</nav>
</div>
<div className="flex items-center space-x-4">
{me?.owner ? (
<div className="flex items-center space-x-2">
<span className="text-sm text-gray-600">
{me.entra ? "✓ Entra" : ""} {me.discord ? "✓ Discord" : ""}
</span>
<a
href="/auth/logout"
className="text-sm text-gray-600 hover:text-gray-900"
>
Logout
</a>
</div>
) : (
<div className="flex space-x-2">
<a href="/auth/entra/login" className="btn-secondary text-sm">
Login with Entra
</a>
<a href="/auth/discord/login" className="btn-primary text-sm">
Connect Discord
</a>
</div>
)}
</div>
</div>
</div>
</header>
{/* Main content */}
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{!me?.owner ? (
<div className="card text-center py-12">
<h2 className="text-2xl font-bold text-gray-900 mb-4">
Authentication Required
</h2>
<p className="text-gray-600 mb-6">
Please authenticate with both Entra ID and Discord to access the
dashboard.
</p>
<div className="flex justify-center space-x-4">
<a href="/auth/entra/login" className="btn-secondary">
Login with Entra
</a>
<a href="/auth/discord/login" className="btn-primary">
Connect Discord
</a>
</div>
</div>
) : (
<Outlet />
)}
</main>
{/* Footer */}
<footer className="mt-12 border-t border-gray-200 py-6">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center text-sm text-gray-500">
© {new Date().getFullYear()} GuardDen. Discord Moderation Bot.
</div>
</footer>
</div>
);
}