153 lines
4.5 KiB
TypeScript
153 lines
4.5 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
Users,
|
|
CreditCard,
|
|
CalendarCheck,
|
|
TrendingUp,
|
|
RefreshCw,
|
|
} from "lucide-react";
|
|
import { StatsCard, StatsCardSkeleton } from "@/components/ui/StatsCard";
|
|
import { PageHeader } from "@/components/ui/PageHeader";
|
|
import { UserManagement } from "@/components/users/UserManagement";
|
|
import { AnalyticsDashboard } from "@/components/analytics/AnalyticsDashboard";
|
|
import { useDashboardStats } from "@/hooks/use-api";
|
|
import { useQueryClient } from "@tanstack/react-query";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useUser } from "@clerk/nextjs";
|
|
import { useSearchParams } from "next/navigation";
|
|
import { GymSelector } from "@/components/gym/GymSelector";
|
|
|
|
export default function Home() {
|
|
const { user } = useUser();
|
|
const searchParams = useSearchParams();
|
|
const gymId = searchParams.get("gymId") ?? undefined;
|
|
|
|
const {
|
|
data: stats,
|
|
isLoading,
|
|
refetch,
|
|
isFetching,
|
|
} = useDashboardStats(gymId);
|
|
const queryClient = useQueryClient();
|
|
|
|
// Get user role from metadata
|
|
const userRole = (user?.publicMetadata?.role as string) ?? "client";
|
|
|
|
const handleRefresh = () => {
|
|
queryClient.invalidateQueries({ queryKey: ["dashboard-stats"] });
|
|
queryClient.invalidateQueries({ queryKey: ["analytics"] });
|
|
refetch();
|
|
};
|
|
|
|
const formatCurrency = (value: number) => {
|
|
return new Intl.NumberFormat("en-US", {
|
|
style: "currency",
|
|
currency: "USD",
|
|
minimumFractionDigits: 0,
|
|
maximumFractionDigits: 0,
|
|
}).format(value || 0);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-8">
|
|
<PageHeader
|
|
title="Dashboard"
|
|
description="Welcome back! Here's what's happening with your gym today."
|
|
actions={
|
|
<div className="flex items-center gap-3">
|
|
<GymSelector userRole={userRole} />
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={handleRefresh}
|
|
disabled={isFetching}
|
|
className="gap-2"
|
|
>
|
|
<RefreshCw
|
|
className={`h-4 w-4 ${isFetching ? "animate-spin" : ""}`}
|
|
/>
|
|
Refresh
|
|
</Button>
|
|
</div>
|
|
}
|
|
/>
|
|
|
|
{/* Stats Grid */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
{isLoading ? (
|
|
<>
|
|
<StatsCardSkeleton />
|
|
<StatsCardSkeleton />
|
|
<StatsCardSkeleton />
|
|
<StatsCardSkeleton />
|
|
</>
|
|
) : (
|
|
<>
|
|
<StatsCard
|
|
title="Total Users"
|
|
value={stats?.totalUsers ?? 0}
|
|
change="+12%"
|
|
trend="up"
|
|
icon={Users}
|
|
color="blue"
|
|
/>
|
|
<StatsCard
|
|
title="Active Clients"
|
|
value={stats?.activeClients ?? 0}
|
|
change="+5%"
|
|
trend="up"
|
|
icon={CalendarCheck}
|
|
color="green"
|
|
/>
|
|
<StatsCard
|
|
title="Revenue"
|
|
value={formatCurrency(stats?.totalRevenue ?? 0)}
|
|
change={`${(stats?.revenueGrowth ?? 0) > 0 ? "+" : ""}${stats?.revenueGrowth ?? 0}%`}
|
|
trend={(stats?.revenueGrowth ?? 0) >= 0 ? "up" : "down"}
|
|
icon={CreditCard}
|
|
color="purple"
|
|
/>
|
|
<StatsCard
|
|
title="Growth"
|
|
value="24%"
|
|
change="-2%"
|
|
trend="down"
|
|
icon={TrendingUp}
|
|
color="orange"
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* Main Content Grid */}
|
|
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6">
|
|
{/* <div className="xl:col-span-2"> */}
|
|
{/* <div className="card-modern"> */}
|
|
{/* <div className="mb-6"> */}
|
|
{/* <h3 className="text-lg font-semibold">Recent Activity</h3> */}
|
|
{/* <p className="text-sm text-muted-foreground"> */}
|
|
{/* Manage and view your users */}
|
|
{/* </p> */}
|
|
{/* </div> */}
|
|
{/* <UserManagement /> */}
|
|
{/* </div> */}
|
|
{/* </div> */}
|
|
|
|
{/* Analytics Sidebar */}
|
|
<div className="xl:col-span-3">
|
|
<div className="card-modern">
|
|
<div className="mb-6">
|
|
<h3 className="text-lg font-semibold">Quick Analytics</h3>
|
|
<p className="text-sm text-muted-foreground">
|
|
Overview of your gym metrics
|
|
</p>
|
|
</div>
|
|
<AnalyticsDashboard gymId={gymId} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|