2026-01-06 20:12:36 +00:00
|
|
|
import { useQuery } from '@tanstack/react-query'
|
2026-01-07 13:24:30 +00:00
|
|
|
import { Users, Package, TrendingUp, Activity } from 'lucide-react'
|
2026-01-06 20:12:36 +00:00
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
2026-01-07 13:24:30 +00:00
|
|
|
import { analyticsApi, type DashboardStats } from '@/api/analytics'
|
2026-01-06 20:12:36 +00:00
|
|
|
import { useAuthStore } from '@/stores/authStore'
|
|
|
|
|
|
|
|
|
|
export default function DashboardPage() {
|
|
|
|
|
const { isAuthenticated, token } = useAuthStore()
|
2026-01-07 13:24:30 +00:00
|
|
|
|
2026-01-06 20:12:36 +00:00
|
|
|
// Only make requests if authenticated and token exists
|
|
|
|
|
const isReady = isAuthenticated && !!token && !!localStorage.getItem('admin_token')
|
2026-01-07 13:24:30 +00:00
|
|
|
|
|
|
|
|
const { data: dashboardData, isLoading: dashboardLoading } = useQuery<DashboardStats>({
|
2026-01-06 20:12:36 +00:00
|
|
|
queryKey: ['dashboard'],
|
|
|
|
|
queryFn: analyticsApi.getDashboard,
|
|
|
|
|
enabled: isReady,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (dashboardLoading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<div>
|
|
|
|
|
<h1 className="text-3xl font-bold tracking-tight">Dashboard</h1>
|
|
|
|
|
<p className="text-muted-foreground">
|
2026-01-06 21:25:06 +00:00
|
|
|
Welcome to Sto k Odnomu Admin Panel
|
2026-01-06 20:12:36 +00:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
|
|
|
{[...Array(4)].map((_, i) => (
|
|
|
|
|
<Card key={i}>
|
|
|
|
|
<CardContent className="pt-6">
|
|
|
|
|
<div className="animate-pulse">
|
|
|
|
|
<div className="h-4 bg-gray-200 rounded w-3/4 mb-2"></div>
|
|
|
|
|
<div className="h-8 bg-gray-200 rounded w-1/2"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<div>
|
|
|
|
|
<h1 className="text-3xl font-bold tracking-tight">Dashboard</h1>
|
|
|
|
|
<p className="text-muted-foreground">
|
2026-01-06 21:25:06 +00:00
|
|
|
Welcome to Sto k Odnomu Admin Panel
|
2026-01-06 20:12:36 +00:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Stats Cards */}
|
|
|
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
|
|
|
<CardTitle className="text-sm font-medium">Total Users</CardTitle>
|
|
|
|
|
<Users className="h-4 w-4 text-muted-foreground" />
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
2026-01-07 13:24:30 +00:00
|
|
|
<div className="text-2xl font-bold">{dashboardData?.users || 0}</div>
|
2026-01-06 20:12:36 +00:00
|
|
|
<p className="text-xs text-muted-foreground">
|
|
|
|
|
Registered users
|
|
|
|
|
</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
2026-01-07 13:24:30 +00:00
|
|
|
<CardTitle className="text-sm font-medium">Active Users</CardTitle>
|
|
|
|
|
<Activity className="h-4 w-4 text-muted-foreground" />
|
2026-01-06 20:12:36 +00:00
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
2026-01-07 13:24:30 +00:00
|
|
|
<div className="text-2xl font-bold">{dashboardData?.activeUsers || 0}</div>
|
2026-01-06 20:12:36 +00:00
|
|
|
<p className="text-xs text-muted-foreground">
|
2026-01-07 13:24:30 +00:00
|
|
|
Active in last 7 days
|
2026-01-06 20:12:36 +00:00
|
|
|
</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
2026-01-07 13:24:30 +00:00
|
|
|
<CardTitle className="text-sm font-medium">Question Packs</CardTitle>
|
2026-01-06 20:12:36 +00:00
|
|
|
<Package className="h-4 w-4 text-muted-foreground" />
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
2026-01-07 13:24:30 +00:00
|
|
|
<div className="text-2xl font-bold">{dashboardData?.publicPacks || 0}</div>
|
2026-01-06 20:12:36 +00:00
|
|
|
<p className="text-xs text-muted-foreground">
|
2026-01-07 13:24:30 +00:00
|
|
|
of {dashboardData?.questionPacks || 0} total packs
|
2026-01-06 20:12:36 +00:00
|
|
|
</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
2026-01-07 13:24:30 +00:00
|
|
|
<CardTitle className="text-sm font-medium">Games Today</CardTitle>
|
|
|
|
|
<TrendingUp className="h-4 w-4 text-muted-foreground" />
|
2026-01-06 20:12:36 +00:00
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
2026-01-07 13:24:30 +00:00
|
|
|
<div className="text-2xl font-bold">{dashboardData?.gamesToday || 0}</div>
|
2026-01-06 20:12:36 +00:00
|
|
|
<p className="text-xs text-muted-foreground">
|
2026-01-07 13:24:30 +00:00
|
|
|
of {dashboardData?.gamesPlayed || 0} total games
|
2026-01-06 20:12:36 +00:00
|
|
|
</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-01-07 13:24:30 +00:00
|
|
|
{/* Rooms Stats */}
|
2026-01-06 20:12:36 +00:00
|
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
2026-01-07 13:24:30 +00:00
|
|
|
<CardTitle>Room Statistics</CardTitle>
|
2026-01-06 20:12:36 +00:00
|
|
|
<CardDescription>
|
2026-01-07 13:24:30 +00:00
|
|
|
Current room status overview
|
2026-01-06 20:12:36 +00:00
|
|
|
</CardDescription>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
<div className="space-y-4">
|
2026-01-07 13:24:30 +00:00
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-medium">Total Rooms</p>
|
|
|
|
|
<p className="text-sm text-muted-foreground">All time</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-2xl font-bold">{dashboardData?.rooms || 0}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-medium">Active Rooms</p>
|
|
|
|
|
<p className="text-sm text-muted-foreground">Currently playing or waiting</p>
|
2026-01-06 20:12:36 +00:00
|
|
|
</div>
|
2026-01-07 13:24:30 +00:00
|
|
|
<div className="text-2xl font-bold text-green-600">{dashboardData?.activeRooms || 0}</div>
|
|
|
|
|
</div>
|
2026-01-06 20:12:36 +00:00
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
2026-01-07 13:24:30 +00:00
|
|
|
<CardTitle>Game Statistics</CardTitle>
|
2026-01-06 20:12:36 +00:00
|
|
|
<CardDescription>
|
2026-01-07 13:24:30 +00:00
|
|
|
Overall game activity
|
2026-01-06 20:12:36 +00:00
|
|
|
</CardDescription>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
<div className="space-y-4">
|
2026-01-07 13:24:30 +00:00
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-medium">Total Games</p>
|
|
|
|
|
<p className="text-sm text-muted-foreground">All time completed games</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-2xl font-bold">{dashboardData?.gamesPlayed || 0}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-medium">Today's Games</p>
|
|
|
|
|
<p className="text-sm text-muted-foreground">Completed today</p>
|
2026-01-06 20:12:36 +00:00
|
|
|
</div>
|
2026-01-07 13:24:30 +00:00
|
|
|
<div className="text-2xl font-bold text-blue-600">{dashboardData?.gamesToday || 0}</div>
|
|
|
|
|
</div>
|
2026-01-06 20:12:36 +00:00
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|