85 lines
3.1 KiB
TypeScript
85 lines
3.1 KiB
TypeScript
'use client';
|
||
|
||
import { useUser } from '@auth0/nextjs-auth0/client';
|
||
import { useEffect, useState } from 'react';
|
||
import Link from 'next/link';
|
||
|
||
interface Metrics {
|
||
total_sessions: number;
|
||
paid_sessions: number;
|
||
total_leads: number;
|
||
total_tokens: number;
|
||
by_tool: { tool: string; count: string }[];
|
||
}
|
||
|
||
export default function AdminDashboard() {
|
||
const { user, isLoading } = useUser();
|
||
const [metrics, setMetrics] = useState<Metrics | null>(null);
|
||
|
||
useEffect(() => {
|
||
if (user) {
|
||
fetch('/api/admin/metrics').then((r) => r.json()).then(setMetrics);
|
||
}
|
||
}, [user]);
|
||
|
||
if (isLoading) return <div className="p-8 text-center">Loading...</div>;
|
||
if (!user) {
|
||
return (
|
||
<div className="p-8 text-center">
|
||
<h1 className="text-2xl font-bold mb-4">Admin Access Required</h1>
|
||
<a href="/api/auth/login" className="bg-accent text-white px-6 py-2 rounded-lg">
|
||
Sign In
|
||
</a>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="max-w-6xl mx-auto px-4 py-8">
|
||
<div className="flex justify-between items-center mb-8">
|
||
<h1 className="text-2xl font-bold">Admin Dashboard</h1>
|
||
<div className="flex gap-4">
|
||
<Link href="/admin/config" className="text-sm text-accent hover:underline">⚙️ Config</Link>
|
||
<Link href="/admin/leads" className="text-sm text-accent hover:underline">👥 Leads</Link>
|
||
<a href="/api/auth/logout" className="text-sm text-gray-500 hover:underline">Sign Out</a>
|
||
</div>
|
||
</div>
|
||
|
||
{metrics && (
|
||
<div className="grid md:grid-cols-4 gap-4 mb-8">
|
||
<div className="bg-white border rounded-xl p-6">
|
||
<div className="text-3xl font-bold text-accent">{metrics.total_sessions}</div>
|
||
<div className="text-sm text-gray-500">Total Sessions</div>
|
||
</div>
|
||
<div className="bg-white border rounded-xl p-6">
|
||
<div className="text-3xl font-bold text-green-600">{metrics.paid_sessions}</div>
|
||
<div className="text-sm text-gray-500">Paid Sessions</div>
|
||
</div>
|
||
<div className="bg-white border rounded-xl p-6">
|
||
<div className="text-3xl font-bold text-blue-600">{metrics.total_leads}</div>
|
||
<div className="text-sm text-gray-500">Leads Captured</div>
|
||
</div>
|
||
<div className="bg-white border rounded-xl p-6">
|
||
<div className="text-3xl font-bold text-purple-600">{metrics.total_tokens.toLocaleString()}</div>
|
||
<div className="text-sm text-gray-500">Tokens Used</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{metrics?.by_tool && (
|
||
<div className="bg-white border rounded-xl p-6">
|
||
<h2 className="font-semibold mb-4">Usage by Tool</h2>
|
||
<div className="space-y-2">
|
||
{metrics.by_tool.map((t) => (
|
||
<div key={t.tool} className="flex justify-between">
|
||
<span className="capitalize">{t.tool.replace(/-/g, ' ')}</span>
|
||
<span className="font-mono">{t.count}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|