126 lines
4.1 KiB
TypeScript
126 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { Users, CreditCard, CalendarCheck, TrendingUp } from "lucide-react";
|
|
import { StatsCard } from "@/components/ui/StatsCard";
|
|
import { UserManagement } from "@/components/users/UserManagement";
|
|
import { AnalyticsDashboard } from "@/components/analytics/AnalyticsDashboard";
|
|
import axios from "axios";
|
|
|
|
interface DashboardStats {
|
|
totalUsers: number;
|
|
activeClients: number;
|
|
totalRevenue: number;
|
|
revenueGrowth: number;
|
|
}
|
|
|
|
export default function Home() {
|
|
const [stats, setStats] = useState<DashboardStats>({
|
|
totalUsers: 0,
|
|
activeClients: 0,
|
|
totalRevenue: 0,
|
|
revenueGrowth: 0,
|
|
});
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const fetchStats = async () => {
|
|
try {
|
|
const response = await axios.get("/api/admin/stats");
|
|
setStats(response.data);
|
|
} catch (error) {
|
|
console.error("Failed to fetch dashboard stats:", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchStats();
|
|
}, []);
|
|
|
|
const formatCurrency = (value: number) => {
|
|
return new Intl.NumberFormat("en-US", {
|
|
style: "currency",
|
|
currency: "USD",
|
|
}).format(value);
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-slate-100">
|
|
<div className="space-y-8 max-w-7xl">
|
|
{/* Hero Section */}
|
|
<div className="pt-8 pb-4">
|
|
<div className="space-y-3">
|
|
<div className="flex items-center gap-3">
|
|
<div className="h-12 w-1 bg-gradient-to-b from-blue-600 to-cyan-600 rounded-full"></div>
|
|
<h1 className="text-5xl font-black bg-gradient-to-r from-blue-600 via-blue-700 to-cyan-600 bg-clip-text text-transparent">
|
|
FitAI Dashboard
|
|
</h1>
|
|
</div>
|
|
<p className="text-lg text-gray-600 ml-4">Performance metrics & athlete insights</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Stats Grid */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-5">
|
|
<StatsCard
|
|
title="Total Users"
|
|
value={loading ? "..." : stats.totalUsers}
|
|
change="+12%" // Placeholder for now as we don't track historical growth yet
|
|
trend="up"
|
|
icon={Users}
|
|
color="blue"
|
|
/>
|
|
<StatsCard
|
|
title="Active Clients"
|
|
value={loading ? "..." : stats.activeClients}
|
|
change="+5%"
|
|
trend="up"
|
|
icon={CalendarCheck}
|
|
color="green"
|
|
/>
|
|
<StatsCard
|
|
title="Revenue"
|
|
value={loading ? "..." : formatCurrency(stats.totalRevenue)}
|
|
change={`${stats.revenueGrowth > 0 ? "+" : ""}${stats.revenueGrowth}%`}
|
|
trend={stats.revenueGrowth >= 0 ? "up" : "down"}
|
|
icon={CreditCard}
|
|
color="purple"
|
|
/>
|
|
<StatsCard
|
|
title="Growth"
|
|
value="24%" // Placeholder
|
|
change="-2%"
|
|
trend="down"
|
|
icon={TrendingUp}
|
|
color="orange"
|
|
/>
|
|
</div>
|
|
|
|
{/* Main Content Grid */}
|
|
<div className="space-y-6 pb-12">
|
|
{/* User Management - Full Width */}
|
|
<div className="bg-white rounded-2xl shadow-lg border border-slate-200/80 p-7 hover:shadow-xl transition-shadow">
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h2 className="text-2xl font-bold text-slate-900">Active Athletes</h2>
|
|
<p className="text-sm text-gray-500 mt-1">Manage and monitor your fitness clients</p>
|
|
</div>
|
|
<UserManagement />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Analytics - 3 Columns Horizontal Layout */}
|
|
<div className="space-y-4">
|
|
<div>
|
|
<h2 className="text-2xl font-bold text-slate-900">Analytics</h2>
|
|
<p className="text-sm text-gray-500 mt-1">Performance metrics and insights</p>
|
|
</div>
|
|
<AnalyticsDashboard />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|