Files
webshop/shop/app/admin/page.tsx

87 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createClient } from '@/lib/supabase/server'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Package, ShoppingCart, Users, TrendingUp } from 'lucide-react'
import { AdminRecentOrders } from '@/components/admin/recent-orders'
// ─── KPI-Daten aus DB ────────────────────────────────────────────────────────
async function getKpis() {
const supabase = await createClient()
const [
{ data: orders },
{ count: userCount },
{ count: productCount },
] = await Promise.all([
supabase.from('orders').select('total_price, status'),
supabase.from('profiles').select('*', { count: 'exact', head: true }),
supabase.from('products').select('*', { count: 'exact', head: true }),
])
const totalRevenue = (orders ?? []).reduce((sum, o) => sum + Number(o.total_price), 0)
const orderCount = (orders ?? []).length
return { totalRevenue, orderCount, userCount: userCount ?? 0, productCount: productCount ?? 0 }
}
export default async function AdminDashboard() {
const { totalRevenue, orderCount, userCount, productCount } = await getKpis()
return (
<div className="p-8 space-y-8">
<h2 className="text-3xl font-bold tracking-tight text-gradient">Dashboard</h2>
{/* KPI Cards echte DB-Daten */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card className="glass-dark border-white/5">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-slate-300">Umsatz gesamt</CardTitle>
<TrendingUp className="h-4 w-4 text-primary" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-white">
{new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(totalRevenue)}
</div>
<p className="text-xs text-slate-400">Aus allen Bestellungen</p>
</CardContent>
</Card>
<Card className="glass-dark border-white/5">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-slate-300">Bestellungen</CardTitle>
<ShoppingCart className="h-4 w-4 text-primary" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-white">{orderCount}</div>
<p className="text-xs text-slate-400">Gesamt</p>
</CardContent>
</Card>
<Card className="glass-dark border-white/5">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-slate-300">Produkte</CardTitle>
<Package className="h-4 w-4 text-primary" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-white">{productCount}</div>
<p className="text-xs text-slate-400">Im Katalog</p>
</CardContent>
</Card>
<Card className="glass-dark border-white/5">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-slate-300">Kunden</CardTitle>
<Users className="h-4 w-4 text-primary" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-white">{userCount}</div>
<p className="text-xs text-slate-400">Registrierte User</p>
</CardContent>
</Card>
</div>
{/* Letzte Bestellungen Client Component mit 30s-Polling */}
<AdminRecentOrders />
</div>
)
}