Add layout y dashboard del admin

This commit is contained in:
Carlos Narro
2026-05-30 19:56:31 +02:00
parent b91e1685c0
commit 6f86334c8a
2 changed files with 56 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
import Link from 'next/link';
import type { Metadata } from 'next';
import { requireAdmin } from '@/lib/auth/current-user';
export const metadata: Metadata = { title: 'Admin · Reformix' };
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
await requireAdmin();
return (
<div className="min-h-screen bg-gray-50">
<header className="sticky top-0 z-10 bg-white border-b border-gray-200">
<div className="max-w-6xl mx-auto px-6 h-16 flex items-center justify-between">
<Link href="/admin" className="flex items-center gap-3">
<span className="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-black text-white font-black italic text-lg leading-none">R</span>
<span className="font-extrabold tracking-tight text-black">Reformix</span>
<span className="text-gray-300">/</span>
<span className="text-sm font-medium text-gray-600">Admin</span>
</Link>
<nav className="flex items-center gap-4 text-xs font-medium">
<Link href="/admin" className="text-gray-500 hover:text-black">Resumen</Link>
<Link href="/admin/usuarios" className="text-gray-500 hover:text-black">Usuarios</Link>
<Link href="/admin/planes" className="text-gray-500 hover:text-black">Planes</Link>
<form action="/logout" method="post"><button type="submit" className="text-gray-500 hover:text-black">Salir</button></form>
</nav>
</div>
</header>
<main className="max-w-6xl mx-auto px-6 py-8">{children}</main>
</div>
);
}

View File

@@ -0,0 +1,26 @@
import { listTenants, listUsers, listPlans } from '@/db/admin-queries';
export const dynamic = 'force-dynamic';
export default async function AdminHome() {
const [tenants, users, plans] = await Promise.all([listTenants(), listUsers(), listPlans()]);
const cards = [
{ label: 'Reformistas (tenants)', value: tenants.length },
{ label: 'Usuarios', value: users.length },
{ label: 'Planes activos', value: plans.length },
{ label: 'En trial', value: tenants.filter((t) => t.subscriptionStatus === 'trial').length },
];
return (
<div className="flex flex-col gap-6">
<h1 className="text-2xl font-black tracking-tight text-black">Resumen</h1>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{cards.map((c) => (
<div key={c.label} className="bg-white border border-gray-200 rounded-xl p-5">
<div className="text-3xl font-black text-black">{c.value}</div>
<div className="text-xs text-gray-500 mt-1">{c.label}</div>
</div>
))}
</div>
</div>
);
}