import React, { useState, useEffect } from 'react'; import { useAuth } from '../../context/AuthContext'; import { Card } from '../../components/ui/card'; import { Button } from '../../components/ui/button'; import { Input } from '../../components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../components/ui/select'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '../../components/ui/dropdown-menu'; import { Badge } from '../../components/ui/badge'; import api from '../../utils/api'; import { toast } from 'sonner'; import { DollarSign, Heart, Users, Globe, Search, Loader2, Download, FileDown, Calendar } from 'lucide-react'; const AdminDonations = () => { const { hasPermission } = useAuth(); const [donations, setDonations] = useState([]); const [filteredDonations, setFilteredDonations] = useState([]); const [stats, setStats] = useState({}); const [loading, setLoading] = useState(true); const [exporting, setExporting] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [typeFilter, setTypeFilter] = useState('all'); const [statusFilter, setStatusFilter] = useState('all'); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); useEffect(() => { fetchData(); }, []); useEffect(() => { filterDonations(); }, [searchQuery, typeFilter, statusFilter, startDate, endDate, donations]); const fetchData = async () => { setLoading(true); try { const [donationsResponse, statsResponse] = await Promise.all([ api.get('/admin/donations'), api.get('/admin/donations/stats') ]); setDonations(donationsResponse.data); setStats(statsResponse.data); } catch (error) { console.error('Failed to fetch donation data:', error); toast.error('Failed to load donation data'); } finally { setLoading(false); } }; const filterDonations = () => { let filtered = [...donations]; // Search filter (donor name or email) if (searchQuery.trim()) { const query = searchQuery.toLowerCase(); filtered = filtered.filter(donation => donation.donor_name?.toLowerCase().includes(query) || donation.donor_email?.toLowerCase().includes(query) ); } // Type filter if (typeFilter !== 'all') { filtered = filtered.filter(donation => donation.donation_type === typeFilter); } // Status filter if (statusFilter !== 'all') { filtered = filtered.filter(donation => donation.status === statusFilter); } // Date range filter if (startDate) { filtered = filtered.filter(donation => new Date(donation.created_at) >= new Date(startDate) ); } if (endDate) { filtered = filtered.filter(donation => new Date(donation.created_at) <= new Date(endDate) ); } setFilteredDonations(filtered); }; const handleExport = async (exportType) => { setExporting(true); try { const params = exportType === 'current' ? { donation_type: typeFilter !== 'all' ? typeFilter : undefined, status: statusFilter !== 'all' ? statusFilter : undefined, start_date: startDate || undefined, end_date: endDate || undefined, search: searchQuery || undefined } : {}; const response = await api.get('/admin/donations/export', { params, responseType: 'blob' }); const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `donations_export_${new Date().toISOString().split('T')[0]}.csv`); document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); toast.success('Donations exported successfully'); } catch (error) { console.error('Failed to export donations:', error); toast.error('Failed to export donations'); } finally { setExporting(false); } }; const formatPrice = (cents) => { return `$${(cents / 100).toFixed(2)}`; }; const formatDate = (dateString) => { if (!dateString) return 'N/A'; return new Date(dateString).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); }; const getStatusBadgeVariant = (status) => { const variants = { completed: 'default', pending: 'secondary', failed: 'destructive' }; return variants[status] || 'outline'; }; const getTypeBadgeColor = (type) => { return type === 'member' ? 'bg-[var(--green-light)]' : 'bg-brand-purple '; }; if (loading) { return (
); } return (
{/* Header */}

Donation Management

Track and manage all donations from members and the public

{/* Stats Cards */}

Total Donations

{stats.total_donations || 0}

Member Donations

{stats.member_donations || 0}

Public Donations

{stats.public_donations || 0}

Total Amount

{stats.total_amount || '$0.00'}

{/* Filters and Actions */}
{/* Search and Export Row */}
setSearchQuery(e.target.value)} className="pl-10 rounded-full border-2 border-[var(--neutral-800)] focus:border-brand-purple " />
{hasPermission('donations.export') && ( handleExport('all')} className="cursor-pointer hover:bg-[var(--lavender-300)] rounded-lg p-3" > Export All Donations handleExport('current')} className="cursor-pointer hover:bg-[var(--lavender-300)] rounded-lg p-3" > Export Current View )}
{/* Filters Row */}
setStartDate(e.target.value)} className="rounded-full border-2 border-[var(--neutral-800)]" placeholder="Start Date" />
setEndDate(e.target.value)} className="rounded-full border-2 border-[var(--neutral-800)]" placeholder="End Date" />
{/* Active Filters Summary */} {(searchQuery || typeFilter !== 'all' || statusFilter !== 'all' || startDate || endDate) && (
Showing {filteredDonations.length} of {donations.length} donations
)}
{/* Donations Table */}
{filteredDonations.length === 0 ? ( ) : ( filteredDonations.map((donation) => ( )) )}
Donor Type Amount Status Date Payment Method

{donations.length === 0 ? 'No donations yet' : 'No donations match your filters'}

{donation.donor_name || 'Anonymous'}

{donation.donor_email || 'No email'}

{donation.donation_type === 'member' ? 'Member' : 'Public'}

{donation.amount}

{donation.status.charAt(0).toUpperCase() + donation.status.slice(1)}
{formatDate(donation.created_at)}

{donation.payment_method || 'N/A'}

{/* This Month Summary */} {stats.this_month_count > 0 && (

This Month's Donations

{stats.this_month_count} donations • {stats.this_month_amount}

)}
); }; export default AdminDonations;