Initial Commit
This commit is contained in:
132
src/pages/admin/AdminDashboard.js
Normal file
132
src/pages/admin/AdminDashboard.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import api from '../../utils/api';
|
||||
import { Card } from '../../components/ui/card';
|
||||
import { Button } from '../../components/ui/button';
|
||||
import { Badge } from '../../components/ui/badge';
|
||||
import { Users, Calendar, Clock, CheckCircle } from 'lucide-react';
|
||||
|
||||
const AdminDashboard = () => {
|
||||
const [stats, setStats] = useState({
|
||||
totalMembers: 0,
|
||||
pendingApprovals: 0,
|
||||
activeMembers: 0
|
||||
});
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchDashboardStats();
|
||||
}, []);
|
||||
|
||||
const fetchDashboardStats = async () => {
|
||||
try {
|
||||
const usersResponse = await api.get('/admin/users');
|
||||
const users = usersResponse.data;
|
||||
|
||||
setStats({
|
||||
totalMembers: users.filter(u => u.role === 'member').length,
|
||||
pendingApprovals: users.filter(u =>
|
||||
['pending_email', 'pending_approval', 'pre_approved', 'payment_pending'].includes(u.status)
|
||||
).length,
|
||||
activeMembers: users.filter(u => u.status === 'active' && u.role === 'member').length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch stats:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-8">
|
||||
<h1 className="text-4xl md:text-5xl font-semibold fraunces text-[#3D405B] mb-4">
|
||||
Admin Dashboard
|
||||
</h1>
|
||||
<p className="text-lg text-[#6B708D]">
|
||||
Manage users, events, and membership applications.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Stats Grid */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
<Card className="p-6 bg-white rounded-2xl border border-[#EAE0D5]" data-testid="stat-total-users">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="bg-[#A3B1C6]/20 p-3 rounded-lg">
|
||||
<Users className="h-6 w-6 text-[#A3B1C6]" />
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-3xl font-semibold fraunces text-[#3D405B] mb-1">
|
||||
{loading ? '-' : stats.totalMembers}
|
||||
</p>
|
||||
<p className="text-sm text-[#6B708D]">Total Members</p>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6 bg-white rounded-2xl border border-[#EAE0D5]" data-testid="stat-pending-approvals">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="bg-[#F2CC8F]/20 p-3 rounded-lg">
|
||||
<Clock className="h-6 w-6 text-[#E07A5F]" />
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-3xl font-semibold fraunces text-[#3D405B] mb-1">
|
||||
{loading ? '-' : stats.pendingApprovals}
|
||||
</p>
|
||||
<p className="text-sm text-[#6B708D]">Pending Approvals</p>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6 bg-white rounded-2xl border border-[#EAE0D5]" data-testid="stat-active-members">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="bg-[#81B29A]/20 p-3 rounded-lg">
|
||||
<CheckCircle className="h-6 w-6 text-[#81B29A]" />
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-3xl font-semibold fraunces text-[#3D405B] mb-1">
|
||||
{loading ? '-' : stats.activeMembers}
|
||||
</p>
|
||||
<p className="text-sm text-[#6B708D]">Active Members</p>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
<Link to="/admin/users">
|
||||
<Card className="p-8 bg-white rounded-2xl border border-[#EAE0D5] hover:shadow-lg hover:-translate-y-1 transition-all cursor-pointer" data-testid="quick-action-users">
|
||||
<Users className="h-12 w-12 text-[#E07A5F] mb-4" />
|
||||
<h3 className="text-xl font-semibold fraunces text-[#3D405B] mb-2">
|
||||
Manage Users
|
||||
</h3>
|
||||
<p className="text-[#6B708D]">
|
||||
View and manage all registered users and their membership status.
|
||||
</p>
|
||||
<Button
|
||||
className="mt-4 bg-[#F2CC8F] text-[#3D405B] hover:bg-[#E5B875] rounded-full"
|
||||
data-testid="manage-users-button"
|
||||
>
|
||||
Go to Users
|
||||
</Button>
|
||||
</Card>
|
||||
</Link>
|
||||
|
||||
<Link to="/admin/approvals">
|
||||
<Card className="p-8 bg-white rounded-2xl border border-[#EAE0D5] hover:shadow-lg hover:-translate-y-1 transition-all cursor-pointer" data-testid="quick-action-approvals">
|
||||
<Clock className="h-12 w-12 text-[#E07A5F] mb-4" />
|
||||
<h3 className="text-xl font-semibold fraunces text-[#3D405B] mb-2">
|
||||
Approval Queue
|
||||
</h3>
|
||||
<p className="text-[#6B708D]">
|
||||
Review and approve pending membership applications.
|
||||
</p>
|
||||
<Button
|
||||
className="mt-4 bg-[#F2CC8F] text-[#3D405B] hover:bg-[#E5B875] rounded-full"
|
||||
data-testid="manage-approvals-button"
|
||||
>
|
||||
View Approvals
|
||||
</Button>
|
||||
</Card>
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AdminDashboard;
|
||||
Reference in New Issue
Block a user