141 lines
5.8 KiB
TypeScript
141 lines
5.8 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect } from 'react'
|
|
import { UserGrowthChart } from '@/components/charts/UserGrowthChart'
|
|
import { MembershipDistributionChart } from '@/components/charts/MembershipDistributionChart'
|
|
import { RevenueChart } from '@/components/charts/RevenueChart'
|
|
import { Card, CardHeader, CardContent } from '@/components/ui/card'
|
|
|
|
interface ChartData {
|
|
label: string
|
|
value: number
|
|
color?: string
|
|
}
|
|
|
|
export function AnalyticsDashboard() {
|
|
const [userGrowthData, setUserGrowthData] = useState<ChartData[]>([])
|
|
const [membershipData, setMembershipData] = useState<ChartData[]>([])
|
|
const [revenueData, setRevenueData] = useState<ChartData[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
useEffect(() => {
|
|
fetchAnalyticsData()
|
|
}, [])
|
|
|
|
const fetchAnalyticsData = async () => {
|
|
setLoading(true)
|
|
try {
|
|
// Mock data for demonstration - replace with real API calls
|
|
const mockUserGrowth = [
|
|
{ label: 'Jan', value: 45 },
|
|
{ label: 'Feb', value: 52 },
|
|
{ label: 'Mar', value: 61 },
|
|
{ label: 'Apr', value: 58 },
|
|
{ label: 'May', value: 67 },
|
|
{ label: 'Jun', value: 74 },
|
|
]
|
|
|
|
const mockMembershipData = [
|
|
{ label: 'Basic', value: 45, color: '#6b7280' },
|
|
{ label: 'Premium', value: 28, color: '#3b82f6' },
|
|
{ label: 'VIP', value: 12, color: '#f59e0b' },
|
|
]
|
|
|
|
const mockRevenueData = [
|
|
{ label: 'Jan', value: 12500, color: '#10b981' },
|
|
{ label: 'Feb', value: 14200, color: '#10b981' },
|
|
{ label: 'Mar', value: 16800, color: '#10b981' },
|
|
{ label: 'Apr', value: 15900, color: '#10b981' },
|
|
{ label: 'May', value: 18200, color: '#10b981' },
|
|
{ label: 'Jun', value: 19400, color: '#10b981' },
|
|
]
|
|
|
|
setUserGrowthData(mockUserGrowth)
|
|
setMembershipData(mockMembershipData)
|
|
setRevenueData(mockRevenueData)
|
|
} catch (error) {
|
|
console.error('Failed to fetch analytics data:', error)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
const totalUsers = userGrowthData.length > 0 ? userGrowthData[userGrowthData.length - 1].value : 0
|
|
const totalRevenue = revenueData.reduce((sum, item) => sum + item.value, 0)
|
|
const activeMembers = membershipData.reduce((sum, item) => sum + item.value, 0)
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="flex justify-center items-center h-64">
|
|
<div className="text-center">
|
|
<div className="inline-block animate-spin">⚡</div>
|
|
<p className="text-gray-600 mt-2 text-sm">Loading analytics...</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* Key Metrics Cards - 3 columns */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
|
<div className="bg-gradient-to-br from-blue-600 via-cyan-500 to-teal-500 rounded-xl p-5 border-0 shadow-lg hover:shadow-2xl transition-all text-white">
|
|
<p className="text-xs uppercase tracking-wide font-bold text-white mb-2">Total Athletes</p>
|
|
<div className="flex items-baseline gap-2">
|
|
<div className="text-2xl font-black text-white">{totalUsers}</div>
|
|
<span className="text-xs text-white font-semibold">active</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-gradient-to-br from-emerald-600 via-teal-500 to-cyan-500 rounded-xl p-5 border-0 shadow-lg hover:shadow-2xl transition-all text-white">
|
|
<p className="text-xs uppercase tracking-wide font-bold text-white mb-2">Total Revenue</p>
|
|
<div className="flex items-baseline gap-2">
|
|
<div className="text-2xl font-black text-white">${totalRevenue.toLocaleString()}</div>
|
|
<span className="text-xs text-white font-semibold">ytd</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-gradient-to-br from-purple-600 via-pink-500 to-blue-500 rounded-xl p-5 border-0 shadow-lg hover:shadow-2xl transition-all text-white">
|
|
<p className="text-xs uppercase tracking-wide font-bold text-white mb-2">Active Members</p>
|
|
<div className="flex items-baseline gap-2">
|
|
<div className="text-2xl font-black text-white">{activeMembers}</div>
|
|
<span className="text-xs text-white font-semibold">members</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Charts - 3 Columns Horizontal */}
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
|
|
<div className="bg-gradient-to-br from-blue-600 via-cyan-500 to-teal-500 rounded-xl shadow-lg border-0 p-5 hover:shadow-2xl transition-all">
|
|
<div className="mb-3">
|
|
<h3 className="text-sm font-bold text-white">User Growth Trend</h3>
|
|
<p className="text-xs text-blue-100">Last 6 months performance</p>
|
|
</div>
|
|
<div className="h-48 overflow-auto">
|
|
<UserGrowthChart data={userGrowthData} />
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-gradient-to-br from-emerald-600 via-teal-500 to-cyan-500 rounded-xl shadow-lg border-0 p-5 hover:shadow-2xl transition-all">
|
|
<div className="mb-3">
|
|
<h3 className="text-sm font-bold text-white">Membership Mix</h3>
|
|
<p className="text-xs text-emerald-100">Distribution breakdown</p>
|
|
</div>
|
|
<div className="h-48 overflow-auto">
|
|
<MembershipDistributionChart data={membershipData} />
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-gradient-to-br from-purple-600 via-pink-500 to-blue-500 rounded-xl shadow-lg border-0 p-5 hover:shadow-2xl transition-all">
|
|
<div className="mb-3">
|
|
<h3 className="text-sm font-bold text-white">Revenue Stream</h3>
|
|
<p className="text-xs text-purple-100">Monthly earnings</p>
|
|
</div>
|
|
<div className="h-48 overflow-auto">
|
|
<RevenueChart data={revenueData} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
} |