Examples
Example: Analytics Dashboard
A dashboard module with stats cards, data tables, and chart placeholders using Supabase queries.
Example: Analytics Dashboard
A dashboard module that displays key metrics with stats cards and data tables.
Dashboard Page
'use client';
import { useEffect, useState } from 'react';
import { useShellAuth } from '@/lib/shell-auth';
import { useModuleApi } from '@/hooks/useModuleApi';
import { BarChart3, Users, TrendingUp, Activity } from 'lucide-react';
interface DashboardStats {
totalItems: number;
activeUsers: number;
weeklyGrowth: number;
avgScore: number;
}
export default function DashboardPage() {
const { user, organizationId, isAuthenticated } = useShellAuth();
const { query } = useModuleApi();
const [stats, setStats] = useState<DashboardStats>({
totalItems: 0,
activeUsers: 0,
weeklyGrowth: 0,
avgScore: 0,
});
const [recentItems, setRecentItems] = useState<any[]>([]);
useEffect(() => {
if (!isAuthenticated) return;
loadDashboard();
}, [isAuthenticated]);
async function loadDashboard() {
// Load stats
const { count } = await query('analytics_items')
.select('*', { count: 'exact', head: true });
setStats({
totalItems: count || 0,
activeUsers: 12,
weeklyGrowth: 8.5,
avgScore: 94,
});
// Load recent items
const { data } = await query('analytics_items')
.select('*')
.order('created_at', { ascending: false })
.limit(5);
if (data) setRecentItems(data);
}
if (!isAuthenticated) {
return <p className="p-6 text-gray-400">Loading...</p>;
}
const statCards = [
{ label: 'Total Items', value: stats.totalItems, icon: BarChart3, color: 'text-blue-400', bg: 'bg-blue-500/10' },
{ label: 'Active Users', value: stats.activeUsers, icon: Users, color: 'text-green-400', bg: 'bg-green-500/10' },
{ label: 'Weekly Growth', value: `${stats.weeklyGrowth}%`, icon: TrendingUp, color: 'text-purple-400', bg: 'bg-purple-500/10' },
{ label: 'Avg Score', value: stats.avgScore, icon: Activity, color: 'text-cyan-400', bg: 'bg-cyan-500/10' },
];
return (
<div className="p-6 space-y-6">
{/* Header */}
<div>
<h1 className="text-2xl font-bold text-white">Analytics Dashboard</h1>
<p className="text-gray-400 mt-1">
Welcome back, {user?.email}
</p>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{statCards.map((stat) => (
<div
key={stat.label}
className="rounded-xl border border-gray-700 bg-gray-800/50 p-6"
>
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-400">{stat.label}</p>
<p className="text-2xl font-bold text-white mt-1">
{stat.value}
</p>
</div>
<div className={`rounded-lg ${stat.bg} p-3`}>
<stat.icon className={`h-6 w-6 ${stat.color}`} />
</div>
</div>
</div>
))}
</div>
{/* Recent Items Table */}
<div className="rounded-xl border border-gray-700 bg-gray-800/50 overflow-hidden">
<div className="px-6 py-4 border-b border-gray-700">
<h2 className="text-lg font-semibold text-white">Recent Items</h2>
</div>
<table className="w-full">
<thead>
<tr className="border-b border-gray-700">
<th className="text-left px-6 py-3 text-xs font-medium text-gray-400 uppercase">Name</th>
<th className="text-left px-6 py-3 text-xs font-medium text-gray-400 uppercase">Status</th>
<th className="text-left px-6 py-3 text-xs font-medium text-gray-400 uppercase">Created</th>
</tr>
</thead>
<tbody>
{recentItems.map((item) => (
<tr key={item.id} className="border-b border-gray-700/50 hover:bg-gray-700/20">
<td className="px-6 py-4 text-sm text-white">{item.name}</td>
<td className="px-6 py-4">
<span className="inline-flex rounded-full bg-green-500/10 border border-green-500/20 px-2 py-0.5 text-xs text-green-400">
{item.status || 'active'}
</span>
</td>
<td className="px-6 py-4 text-sm text-gray-400">
{new Date(item.created_at).toLocaleDateString()}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}This example demonstrates:
- Stats cards with icons (Lucide React)
- Data table with sorting
- Responsive grid layout
- Universe dark theme patterns