203 lines
8.0 KiB
TypeScript
203 lines
8.0 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useEffect } from "react"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Users, Vote, BarChart3, LogOut, Calendar, Settings } from "lucide-react"
|
|
import Link from "next/link"
|
|
import { AuthGuard } from "@/components/auth-guard"
|
|
import { useAuth } from "@/hooks/use-auth"
|
|
import apiClient from "@/lib/api-client"
|
|
import { API_CONFIG } from "@/lib/config"
|
|
|
|
function AdminPageContent() {
|
|
const { user, logout } = useAuth()
|
|
const [stats, setStats] = useState({
|
|
totalEvents: 0,
|
|
activeEvents: 0,
|
|
totalCandidates: 0
|
|
})
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
useEffect(() => {
|
|
fetchStats()
|
|
}, [])
|
|
|
|
const fetchStats = async () => {
|
|
try {
|
|
const response = await apiClient.get(API_CONFIG.ENDPOINTS.VOTE_EVENTS)
|
|
if (response.data.success) {
|
|
const events = response.data.data.vote_events || []
|
|
const now = new Date()
|
|
const activeEvents = events.filter((event: any) => {
|
|
const start = new Date(event.start_date)
|
|
const end = new Date(event.end_date)
|
|
return now >= start && now <= end
|
|
})
|
|
const totalCandidates = events.reduce((total: number, event: any) => {
|
|
return total + (event.candidates?.length || 0)
|
|
}, 0)
|
|
|
|
setStats({
|
|
totalEvents: events.length,
|
|
activeEvents: activeEvents.length,
|
|
totalCandidates
|
|
})
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching stats:', error)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50">
|
|
<header className="bg-white shadow-sm border-b">
|
|
<div className="container mx-auto px-4 py-4 flex justify-between items-center">
|
|
<div className="flex items-center gap-4">
|
|
<img src="/images/meti-logo.png" alt="METI - New & Renewable Energy" className="h-12 w-auto" />
|
|
<h1 className="text-2xl font-bold text-gray-900">Admin Dashboard METI</h1>
|
|
</div>
|
|
<div className="flex items-center gap-4">
|
|
<span className="text-sm text-gray-600">Welcome, {user?.username || 'Admin'}</span>
|
|
<Button variant="outline" size="sm" onClick={logout}>
|
|
<LogOut className="h-4 w-4 mr-2" />
|
|
Logout
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="container mx-auto px-4 py-8">
|
|
{/* Statistics Cards */}
|
|
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Total Events</CardTitle>
|
|
<Vote className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{loading ? '...' : stats.totalEvents}</div>
|
|
<p className="text-xs text-muted-foreground">Vote events created</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Active Events</CardTitle>
|
|
<BarChart3 className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{loading ? '...' : stats.activeEvents}</div>
|
|
<p className="text-xs text-muted-foreground">Currently running</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Total Candidates</CardTitle>
|
|
<Users className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{loading ? '...' : stats.totalCandidates}</div>
|
|
<p className="text-xs text-muted-foreground">Across all events</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">System Status</CardTitle>
|
|
<Settings className="h-4 w-4 text-green-600" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold text-green-600">Online</div>
|
|
<p className="text-xs text-muted-foreground">All systems operational</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Quick Actions */}
|
|
<div className="mb-8">
|
|
<h2 className="text-2xl font-bold text-gray-900 mb-6">Quick Actions</h2>
|
|
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
<Card className="hover:shadow-lg transition-shadow cursor-pointer group">
|
|
<CardHeader>
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center group-hover:bg-blue-200 transition-colors">
|
|
<Calendar className="h-6 w-6 text-blue-600" />
|
|
</div>
|
|
<div>
|
|
<CardTitle className="text-lg">Manage Events</CardTitle>
|
|
<CardDescription>Create and manage voting events</CardDescription>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Link href="/admin/events">
|
|
<Button className="w-full bg-blue-600 hover:bg-blue-700">
|
|
<Settings className="h-4 w-4 mr-2" />
|
|
Event Management
|
|
</Button>
|
|
</Link>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="hover:shadow-lg transition-shadow cursor-pointer group">
|
|
<CardHeader>
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center group-hover:bg-green-200 transition-colors">
|
|
<Users className="h-6 w-6 text-green-600" />
|
|
</div>
|
|
<div>
|
|
<CardTitle className="text-lg">Manage Members</CardTitle>
|
|
<CardDescription>Verify and manage members</CardDescription>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Link href="/admin/members">
|
|
<Button className="w-full bg-green-600 hover:bg-green-700">
|
|
<Users className="h-4 w-4 mr-2" />
|
|
Member Management
|
|
</Button>
|
|
</Link>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="hover:shadow-lg transition-shadow cursor-pointer group">
|
|
<CardHeader>
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center group-hover:bg-purple-200 transition-colors">
|
|
<BarChart3 className="h-6 w-6 text-purple-600" />
|
|
</div>
|
|
<div>
|
|
<CardTitle className="text-lg">View Results</CardTitle>
|
|
<CardDescription>Monitor voting results</CardDescription>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Link href="/results">
|
|
<Button className="w-full bg-purple-600 hover:bg-purple-700">
|
|
<BarChart3 className="h-4 w-4 mr-2" />
|
|
View Results
|
|
</Button>
|
|
</Link>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default function AdminPage() {
|
|
return (
|
|
<AuthGuard requiredRole="superadmin">
|
|
<AdminPageContent />
|
|
</AuthGuard>
|
|
)
|
|
}
|