The Admin Reports System provides comprehensive analytics and insights for administrators to monitor and manage the Generous Hands donation platform. The system includes 5 main report categories that cover all aspects of platform operations.
Endpoint: GET /api/admin/reports/donation-overview
Purpose: Comprehensive analysis of donation patterns, trends, and performance metrics.
Key Metrics:
- Total donations and confirmation rates
- Status breakdown (submitted, assigned, picked_up, delivered, confirmed, cancelled)
- Urgency level distribution
- Top performing charities
- Most donated categories
- Daily donation trends (30-day chart data)
- Average confirmation time
Query Parameters:
startDate(optional): Start date for custom date rangeendDate(optional): End date for custom date rangeperiod(optional): Predefined periods -7d,30d,90d,1y,all(default:30d)
Endpoint: GET /api/admin/reports/user-activity
Purpose: Monitor user registration trends, verification status, and platform engagement.
Key Metrics:
- Total users by time period
- User breakdown by role (donor, volunteer, charity, admin)
- Verification statistics for volunteers and charities
- Registration trends over time
- Active users (recent donations/pickup activity)
Query Parameters:
period(optional): Time period -7d,30d,90d,1y,all(default:30d)
Endpoint: GET /api/admin/reports/charity-performance
Purpose: Analyze charity engagement, response times, and service quality.
Key Metrics:
- Charity overview with donation counts and confirmation rates
- Average response times for donation confirmations
- Needs fulfillment analysis (how well donations match charity needs)
- Thank you note completion rates
- Overall charity performance summary
Endpoint: GET /api/admin/reports/volunteer-efficiency
Purpose: Track volunteer performance, pickup completion rates, and delivery efficiency.
Key Metrics:
- Volunteer overview with assignment and completion statistics
- Pickup status breakdown across all volunteers
- Average delivery times by volunteer
- Top performing volunteers
- Overall volunteer efficiency metrics
Endpoint: GET /api/admin/reports/system-health
Purpose: Monitor data quality, identify system issues, and track pending administrative actions.
Key Metrics:
- Data quality issues (missing coordinates, incomplete profiles)
- Incomplete donation flows (stuck submissions, delayed deliveries)
- Pending administrative actions (verifications, incomplete categories)
- System overview statistics
- Overall health score (0-100)
All admin reports require:
- Valid JWT token in Authorization header
- User must have
adminrole
Authorization: Bearer <admin_jwt_token>GET /api/admin/reports/donation-overview?period=30d
Authorization: Bearer <admin_token>Response:
{
"success": true,
"data": {
"summary": {
"totalDonations": 156,
"confirmedDonations": 142,
"confirmationRate": "91.0",
"avgConfirmationTimeHours": 18
},
"statusBreakdown": [
{ "_id": "confirmed", "count": 142 },
{ "_id": "delivered", "count": 8 },
{ "_id": "picked_up", "count": 4 },
{ "_id": "assigned", "count": 2 }
],
"urgencyBreakdown": [
{ "_id": "medium", "count": 89 },
{ "_id": "high", "count": 45 },
{ "_id": "low", "count": 22 }
],
"topCharities": [
{ "charityName": "Food Bank Central", "count": 34 },
{ "charityName": "Clothes for All", "count": 28 }
],
"categoryBreakdown": [
{ "categoryName": "Food items", "count": 67 },
{ "categoryName": "Clothing", "count": 45 }
],
"dailyTrends": [
{ "_id": "2024-01-01", "count": 5 },
{ "_id": "2024-01-02", "count": 8 }
],
"reportPeriod": {
"startDate": "2023-12-02T00:00:00.000Z",
"endDate": "Present",
"period": "30d"
}
}
}GET /api/admin/reports/system-health
Authorization: Bearer <admin_token>Response:
{
"success": true,
"data": {
"dataQuality": {
"usersWithMissingData": 3,
"donationsWithoutCoordinates": 0,
"charitiesWithoutLocation": 1
},
"incompleteFlows": {
"stuckSubmissions": 2,
"stuckPickups": 1,
"unconfirmedDeliveries": 5
},
"pendingActions": {
"pendingVerifications": 8,
"categoriesNeedingDescription": 2
},
"systemOverview": {
"totalUsers": 245,
"totalDonations": 156,
"totalPickupRequests": 134,
"totalCategories": 12
},
"healthScore": 87
}
}import React, { useState, useEffect } from 'react';
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
const AdminDashboard = () => {
const [reports, setReports] = useState({
donationOverview: null,
userActivity: null,
charityPerformance: null,
volunteerEfficiency: null,
systemHealth: null
});
const [loading, setLoading] = useState(true);
const [selectedPeriod, setSelectedPeriod] = useState('30d');
useEffect(() => {
fetchAllReports();
}, [selectedPeriod]);
const fetchAllReports = async () => {
setLoading(true);
try {
const [donation, user, charity, volunteer, system] = await Promise.all([
fetchReport('donation-overview', { period: selectedPeriod }),
fetchReport('user-activity', { period: selectedPeriod }),
fetchReport('charity-performance'),
fetchReport('volunteer-efficiency'),
fetchReport('system-health')
]);
setReports({
donationOverview: donation,
userActivity: user,
charityPerformance: charity,
volunteerEfficiency: volunteer,
systemHealth: system
});
} catch (error) {
console.error('Error fetching reports:', error);
} finally {
setLoading(false);
}
};
const fetchReport = async (reportType, params = {}) => {
const queryString = new URLSearchParams(params).toString();
const response = await fetch(`/api/admin/reports/${reportType}?${queryString}`, {
headers: {
'Authorization': `Bearer ${authToken}`,
'Content-Type': 'application/json'
}
});
const data = await response.json();
return data.success ? data.data : null;
};
if (loading) return <div className="loading">Loading admin dashboard...</div>;
return (
<div className="admin-dashboard">
{/* Header with Period Selector */}
<div className="dashboard-header">
<h1>Admin Dashboard</h1>
<select
value={selectedPeriod}
onChange={(e) => setSelectedPeriod(e.target.value)}
className="period-selector"
>
<option value="7d">Last 7 Days</option>
<option value="30d">Last 30 Days</option>
<option value="90d">Last 90 Days</option>
<option value="1y">Last Year</option>
<option value="all">All Time</option>
</select>
</div>
{/* Key Metrics Cards */}
<div className="metrics-grid">
<MetricCard
title="Total Donations"
value={reports.donationOverview?.summary.totalDonations || 0}
subtitle={`${reports.donationOverview?.summary.confirmationRate || 0}% confirmed`}
color="blue"
/>
<MetricCard
title="Active Users"
value={reports.userActivity?.summary.totalUsers || 0}
subtitle={`${reports.userActivity?.summary.pendingVerifications || 0} pending verification`}
color="green"
/>
<MetricCard
title="System Health"
value={`${reports.systemHealth?.healthScore || 0}%`}
subtitle="Overall platform health"
color={getHealthColor(reports.systemHealth?.healthScore)}
/>
<MetricCard
title="Avg Response Time"
value={`${reports.charityPerformance?.summary.avgResponseTimeHours || 0}h`}
subtitle="Charity response time"
color="purple"
/>
</div>
{/* Charts Section */}
<div className="charts-section">
{/* Donation Trends Chart */}
<div className="chart-container">
<h3>Donation Trends</h3>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={reports.donationOverview?.dailyTrends || []}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="_id" />
<YAxis />
<Tooltip />
<Bar dataKey="count" fill="#3b82f6" />
</BarChart>
</ResponsiveContainer>
</div>
{/* Status Distribution */}
<div className="chart-container">
<h3>Donation Status Distribution</h3>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={reports.donationOverview?.statusBreakdown || []}
dataKey="count"
nameKey="_id"
cx="50%"
cy="50%"
outerRadius={80}
fill="#8884d8"
label
>
{(reports.donationOverview?.statusBreakdown || []).map((entry, index) => (
<Cell key={`cell-${index}`} fill={getStatusColor(entry._id)} />
))}
</Pie>
<Tooltip />
</PieChart>
</ResponsiveContainer>
</div>
</div>
{/* Detailed Reports Section */}
<div className="reports-section">
<ReportTabs reports={reports} />
</div>
</div>
);
};
const MetricCard = ({ title, value, subtitle, color }) => (
<div className={`metric-card ${color}`}>
<h3>{title}</h3>
<div className="metric-value">{value}</div>
<div className="metric-subtitle">{subtitle}</div>
</div>
);
const ReportTabs = ({ reports }) => {
const [activeTab, setActiveTab] = useState('donations');
const tabs = [
{ id: 'donations', label: 'Donations', data: reports.donationOverview },
{ id: 'users', label: 'Users', data: reports.userActivity },
{ id: 'charities', label: 'Charities', data: reports.charityPerformance },
{ id: 'volunteers', label: 'Volunteers', data: reports.volunteerEfficiency },
{ id: 'system', label: 'System Health', data: reports.systemHealth }
];
return (
<div className="report-tabs">
<div className="tab-headers">
{tabs.map(tab => (
<button
key={tab.id}
className={`tab-header ${activeTab === tab.id ? 'active' : ''}`}
onClick={() => setActiveTab(tab.id)}
>
{tab.label}
</button>
))}
</div>
<div className="tab-content">
{tabs.find(tab => tab.id === activeTab)?.data && (
<ReportContent
type={activeTab}
data={tabs.find(tab => tab.id === activeTab).data}
/>
)}
</div>
</div>
);
};
// Helper functions
const getHealthColor = (score) => {
if (score >= 80) return 'green';
if (score >= 60) return 'yellow';
return 'red';
};
const getStatusColor = (status) => {
const colors = {
confirmed: '#10b981',
delivered: '#3b82f6',
picked_up: '#f59e0b',
assigned: '#8b5cf6',
submitted: '#6b7280',
cancelled: '#ef4444'
};
return colors[status] || '#6b7280';
};
export default AdminDashboard;.admin-dashboard {
padding: 24px;
max-width: 1400px;
margin: 0 auto;
}
.dashboard-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32px;
}
.dashboard-header h1 {
font-size: 2rem;
font-weight: bold;
color: #1f2937;
}
.period-selector {
padding: 8px 16px;
border: 1px solid #d1d5db;
border-radius: 6px;
background: white;
font-size: 14px;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 32px;
}
.metric-card {
background: white;
padding: 24px;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border-left: 4px solid;
}
.metric-card.blue { border-left-color: #3b82f6; }
.metric-card.green { border-left-color: #10b981; }
.metric-card.yellow { border-left-color: #f59e0b; }
.metric-card.red { border-left-color: #ef4444; }
.metric-card.purple { border-left-color: #8b5cf6; }
.metric-card h3 {
font-size: 0.875rem;
font-weight: 500;
color: #6b7280;
margin: 0 0 8px 0;
}
.metric-value {
font-size: 2rem;
font-weight: bold;
color: #1f2937;
margin-bottom: 4px;
}
.metric-subtitle {
font-size: 0.75rem;
color: #9ca3af;
}
.charts-section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 24px;
margin-bottom: 32px;
}
.chart-container {
background: white;
padding: 24px;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.chart-container h3 {
margin: 0 0 16px 0;
font-size: 1.125rem;
font-weight: 600;
color: #1f2937;
}
.reports-section {
background: white;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.tab-headers {
display: flex;
border-bottom: 1px solid #e5e7eb;
}
.tab-header {
padding: 16px 24px;
border: none;
background: none;
cursor: pointer;
font-weight: 500;
color: #6b7280;
transition: all 0.2s;
}
.tab-header:hover {
color: #3b82f6;
background: #f9fafb;
}
.tab-header.active {
color: #3b82f6;
border-bottom: 2px solid #3b82f6;
}
.tab-content {
padding: 24px;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 400px;
font-size: 1.125rem;
color: #6b7280;
}// Implement Redis caching for expensive aggregation queries
const cacheKey = `admin_report_${reportType}_${JSON.stringify(params)}`;
const cachedResult = await redis.get(cacheKey);
if (cachedResult) {
return JSON.parse(cachedResult);
}
// Generate report...
await redis.setex(cacheKey, 300, JSON.stringify(report)); // 5 min cache- Use MongoDB aggregation pipelines for complex queries
- Implement database indexes on frequently queried fields
- Add pagination for large datasets
- Use parallel Promise.all() for independent queries
// WebSocket integration for real-time dashboard updates
const socket = io();
socket.on('donation_status_changed', (data) => {
// Update relevant metrics without full refresh
updateDonationMetrics(data);
});const exportReport = async (reportType, format = 'csv') => {
const data = await fetchReport(reportType);
if (format === 'csv') {
return convertToCSV(data);
} else if (format === 'pdf') {
return generatePDF(data);
}
};Allow admins to select custom date ranges for more specific analysis.
Set up automated alerts for:
- System health score drops below threshold
- Unusual donation patterns
- High number of pending verifications
Compare metrics across different time periods to identify trends.
Different report sections for different admin levels.
These reports enable administrators to:
- Monitor Platform Health - Identify and resolve issues quickly
- Optimize Operations - Improve volunteer and charity performance
- Make Data-Driven Decisions - Use metrics to guide platform improvements
- Ensure Quality - Maintain high standards across all user interactions
- Scale Effectively - Understand growth patterns and resource needs
The comprehensive reporting system provides the insights needed to run a successful donation platform and maximize positive community impact.