import { useState, useEffect } from "react"; import Layout from "@/components/Layout"; import SEO from "@/components/SEO"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { BarChart3, Users, Briefcase, FileText, DollarSign, TrendingUp, Activity, MessageSquare, Loader2, ArrowUpRight, ArrowDownRight, } from "lucide-react"; import { useAuth } from "@/contexts/AuthContext"; import { aethexToast } from "@/lib/aethex-toast"; interface Analytics { users: { total: number; new: number; active: number; creators: number; }; opportunities: { total: number; open: number; new: number; }; applications: { total: number; new: number; }; contracts: { total: number; active: number; }; community: { posts: number; newPosts: number; }; revenue: { total: number; period: string; }; trends: { dailySignups: Array<{ date: string; count: number }>; topOpportunities: Array<{ id: string; title: string; applications: number }>; }; period: number; } export default function AdminAnalytics() { const { session } = useAuth(); const [analytics, setAnalytics] = useState(null); const [loading, setLoading] = useState(true); const [period, setPeriod] = useState("30"); useEffect(() => { if (session?.access_token) { fetchAnalytics(); } }, [session?.access_token, period]); const fetchAnalytics = async () => { try { const res = await fetch(`/api/admin/analytics?period=${period}`, { headers: { Authorization: `Bearer ${session?.access_token}` }, }); const data = await res.json(); if (res.ok) { setAnalytics(data); } else { aethexToast.error(data.error || "Failed to load analytics"); } } catch (err) { aethexToast.error("Failed to load analytics"); } finally { setLoading(false); } }; const formatCurrency = (amount: number) => { return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", minimumFractionDigits: 0 }).format(amount); }; const maxSignups = analytics?.trends.dailySignups ? Math.max(...analytics.trends.dailySignups.map(d => d.count), 1) : 1; if (loading) { return (
); } return (
{/* Header */}

Analytics

Platform insights and metrics

{/* Overview Stats */}

Total Users

{analytics?.users.total.toLocaleString()}

+{analytics?.users.new} this period

Active Users

{analytics?.users.active.toLocaleString()}

{analytics?.users.total ? Math.round((analytics.users.active / analytics.users.total) * 100) : 0}% of total

Opportunities

{analytics?.opportunities.open}

+{analytics?.opportunities.new} new

Revenue

{formatCurrency(analytics?.revenue.total || 0)}

Last {period} days

{/* Detailed Stats Grid */}
{/* Applications */} Applications
Total {analytics?.applications.total}
This Period +{analytics?.applications.new}
Avg per Opportunity {analytics?.opportunities.total ? (analytics.applications.total / analytics.opportunities.total).toFixed(1) : 0}
{/* Contracts */} Contracts
Total {analytics?.contracts.total}
Active {analytics?.contracts.active}
Completion Rate {analytics?.contracts.total ? Math.round(((analytics.contracts.total - analytics.contracts.active) / analytics.contracts.total) * 100) : 0}%
{/* Community */} Community
Total Posts {analytics?.community.posts}
New Posts +{analytics?.community.newPosts}
Creators {analytics?.users.creators}
{/* Charts Row */}
{/* Signup Trend */} Daily Signups User registrations over the last 30 days
{analytics?.trends.dailySignups.slice(-30).map((day, i) => (
))}
30 days ago Today
{/* Top Opportunities */} Top Opportunities By number of applications
{analytics?.trends.topOpportunities.map((opp, i) => (
#{i + 1}

{opp.title}

{opp.applications} applications

))} {(!analytics?.trends.topOpportunities || analytics.trends.topOpportunities.length === 0) && (

No opportunities yet

)}
); }