feat: implement StatCard component and integrate it into AdminDashboard and AdminMembers for improved stats display
This commit is contained in:
@@ -4,13 +4,16 @@ 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, Mail, AlertCircle, Globe } from 'lucide-react';
|
||||
import { Users, Calendar, Clock, CheckCircle, Mail, AlertCircle, Globe, CircleMinus } from 'lucide-react';
|
||||
import { StatCard } from '../../components/StatCard';
|
||||
|
||||
|
||||
const AdminDashboard = () => {
|
||||
const [stats, setStats] = useState({
|
||||
totalMembers: 0,
|
||||
pendingValidations: 0,
|
||||
activeMembers: 0
|
||||
activeMembers: 0,
|
||||
inactiveMembers: 0
|
||||
});
|
||||
const [usersNeedingAttention, setUsersNeedingAttention] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -29,7 +32,8 @@ const AdminDashboard = () => {
|
||||
pendingValidations: users.filter(u =>
|
||||
['pending_email', 'pending_validation', 'pre_validated', 'payment_pending'].includes(u.status)
|
||||
).length,
|
||||
activeMembers: users.filter(u => u.status === 'active' && u.role === 'member').length
|
||||
activeMembers: users.filter(u => u.status === 'active' && u.role === 'member').length,
|
||||
inactiveMembers: users.filter(u => u.status === 'inactive' && u.role === 'member').length
|
||||
});
|
||||
|
||||
// Find users who have received 3+ reminders (may need personal outreach)
|
||||
@@ -76,52 +80,42 @@ const AdminDashboard = () => {
|
||||
</div>
|
||||
|
||||
{/* Stats Grid */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]" data-testid="stat-total-users">
|
||||
<div className='flex items-start justify-between'>
|
||||
<p className="text-3xl font-semibold text-[var(--purple-ink)] mb-1" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
{loading ? '-' : stats.totalMembers}
|
||||
</p>
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className="bg-[var(--neutral-800)]/20 p-3 rounded-lg">
|
||||
<Users className="h-6 w-6 text-brand-purple" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<p className="text-sm text-brand-purple" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Total Members</p>
|
||||
</Card>
|
||||
<div className='rounded-3xl bg-brand-lavender/10 p-8 mb-8'>
|
||||
<div className=' text-2xl text-[var(--purple-ink)] pb-8 font-semibold'>
|
||||
Quick Overview
|
||||
</div>
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-8 ">
|
||||
<StatCard
|
||||
title="Total Members"
|
||||
value={loading ? '-' : stats.totalMembers}
|
||||
icon={Users}
|
||||
iconBgClass="text-brand-purple"
|
||||
dataTestId="stat-total-users"
|
||||
/>
|
||||
<StatCard
|
||||
title="Pending Validations"
|
||||
value={loading ? '-' : stats.pendingValidations}
|
||||
icon={Clock}
|
||||
iconBgClass="text-brand-light-orange"
|
||||
dataTestId="stat-total-users"
|
||||
/>
|
||||
<StatCard
|
||||
title="Active Members"
|
||||
value={loading ? '-' : stats.activeMembers}
|
||||
icon={CheckCircle}
|
||||
iconBgClass="text-[var(--green-light)]"
|
||||
dataTestId="stat-total-users"
|
||||
/>
|
||||
<StatCard
|
||||
title="Inactive Members"
|
||||
value={loading ? '-' : stats.inactiveMembers}
|
||||
icon={CircleMinus}
|
||||
iconBgClass="text-brand-pink"
|
||||
dataTestId="stat-total-users"
|
||||
/>
|
||||
|
||||
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]" data-testid="stat-pending-validations">
|
||||
<div className='flex items-start justify-between'>
|
||||
<p className="text-3xl font-semibold text-[var(--purple-ink)] mb-1" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
{loading ? '-' : stats.pendingValidations}
|
||||
</p>
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className=" p-3 rounded-lg">
|
||||
<Clock className="h-6 w-6 text-orange-600" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-brand-purple" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Pending Validations</p>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]" data-testid="stat-active-members">
|
||||
<div className='flex items-start justify-between'>
|
||||
<p className="text-3xl font-semibold text-[var(--purple-ink)] mb-1" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
{loading ? '-' : stats.activeMembers}
|
||||
</p>
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className="bg-[var(--green-light)]/20 p-3 rounded-lg">
|
||||
<CheckCircle className="h-6 w-6 text-[var(--green-light)]" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<p className="text-sm text-brand-purple" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Active Members</p>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Actions */}
|
||||
|
||||
Reference in New Issue
Block a user