This commit is contained in:
2026-01-12 20:37:38 -06:00
parent 7694532d53
commit 9c2d516f9d
74 changed files with 1842 additions and 1842 deletions

View File

@@ -167,13 +167,13 @@ const AdminDonations = () => {
};
const getTypeBadgeColor = (type) => {
return type === 'member' ? 'bg-var(--green-light)' : 'bg-var(--purple-lavender)';
return type === 'member' ? 'bg-[var(--green-light)]' : 'bg-[var(--purple-lavender)]';
};
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen">
<Loader2 className="h-12 w-12 animate-spin text-var(--purple-lavender)" />
<Loader2 className="h-12 w-12 animate-spin text-[var(--purple-lavender)]" />
</div>
);
}
@@ -182,93 +182,93 @@ const AdminDonations = () => {
<div className="space-y-8">
{/* Header */}
<div>
<h1 className="text-3xl font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
<h1 className="text-3xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Donation Management
</h1>
<p className="text-var(--purple-lavender) mt-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-[var(--purple-lavender)] mt-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Track and manage all donations from members and the public
</p>
</div>
{/* Stats Cards */}
<div className="grid md:grid-cols-4 gap-6">
<Card className="p-6 bg-background rounded-2xl border-2 border-var(--neutral-800)">
<Card className="p-6 bg-background rounded-2xl border-2 border-[var(--neutral-800)]">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Total Donations
</p>
<p className="text-3xl font-bold text-var(--purple-ink) mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="text-3xl font-bold text-[var(--purple-ink)] mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
{stats.total_donations || 0}
</p>
</div>
<div className="p-3 bg-var(--neutral-800)/20 rounded-full">
<Heart className="h-6 w-6 text-var(--purple-lavender)" />
<div className="p-3 bg-[var(--neutral-800)]/20 rounded-full">
<Heart className="h-6 w-6 text-[var(--purple-lavender)]" />
</div>
</div>
</Card>
<Card className="p-6 bg-background rounded-2xl border-2 border-var(--neutral-800)">
<Card className="p-6 bg-background rounded-2xl border-2 border-[var(--neutral-800)]">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Member Donations
</p>
<p className="text-3xl font-bold text-var(--green-light) mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="text-3xl font-bold text-[var(--green-light)] mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
{stats.member_donations || 0}
</p>
</div>
<div className="p-3 bg-var(--green-light)/10 rounded-full">
<Users className="h-6 w-6 text-var(--green-light)" />
<div className="p-3 bg-[var(--green-light)]/10 rounded-full">
<Users className="h-6 w-6 text-[var(--green-light)]" />
</div>
</div>
</Card>
<Card className="p-6 bg-background rounded-2xl border-2 border-var(--neutral-800)">
<Card className="p-6 bg-background rounded-2xl border-2 border-[var(--neutral-800)]">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Public Donations
</p>
<p className="text-3xl font-bold text-var(--purple-lavender) mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="text-3xl font-bold text-[var(--purple-lavender)] mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
{stats.public_donations || 0}
</p>
</div>
<div className="p-3 bg-var(--neutral-800)/20 rounded-full">
<Globe className="h-6 w-6 text-var(--purple-lavender)" />
<div className="p-3 bg-[var(--neutral-800)]/20 rounded-full">
<Globe className="h-6 w-6 text-[var(--purple-lavender)]" />
</div>
</div>
</Card>
<Card className="p-6 bg-background rounded-2xl border-2 border-var(--neutral-800)">
<Card className="p-6 bg-background rounded-2xl border-2 border-[var(--neutral-800)]">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Total Amount
</p>
<p className="text-3xl font-bold text-var(--purple-ink) mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="text-3xl font-bold text-[var(--purple-ink)] mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
{stats.total_amount || '$0.00'}
</p>
</div>
<div className="p-3 bg-var(--neutral-800)/20 rounded-full">
<DollarSign className="h-6 w-6 text-var(--purple-lavender)" />
<div className="p-3 bg-[var(--neutral-800)]/20 rounded-full">
<DollarSign className="h-6 w-6 text-[var(--purple-lavender)]" />
</div>
</div>
</Card>
</div>
{/* Filters and Actions */}
<Card className="p-6 bg-background rounded-2xl border-2 border-var(--neutral-800)">
<Card className="p-6 bg-background rounded-2xl border-2 border-[var(--neutral-800)]">
<div className="space-y-4">
{/* Search and Export Row */}
<div className="flex flex-col md:flex-row gap-4 justify-between">
<div className="flex-1 relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-5 w-5 text-var(--purple-lavender)" />
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-5 w-5 text-[var(--purple-lavender)]" />
<Input
placeholder="Search by donor name or email..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10 rounded-full border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)"
className="pl-10 rounded-full border-2 border-[var(--neutral-800)] focus:border-[var(--purple-lavender)]"
/>
</div>
{hasPermission('donations.export') && (
@@ -276,26 +276,26 @@ const AdminDonations = () => {
<DropdownMenuTrigger asChild>
<Button
disabled={exporting}
className="bg-var(--green-light) text-white hover:bg-var(--green-soft) rounded-full px-6 py-3 flex items-center gap-2"
className="bg-[var(--green-light)] text-white hover:bg-[var(--green-soft)] rounded-full px-6 py-3 flex items-center gap-2"
>
<Download className="h-4 w-4" />
{exporting ? 'Exporting...' : 'Export'}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56 bg-background rounded-xl border-2 border-var(--neutral-800) shadow-lg">
<DropdownMenuContent align="end" className="w-56 bg-background rounded-xl border-2 border-[var(--neutral-800)] shadow-lg">
<DropdownMenuItem
onClick={() => handleExport('all')}
className="cursor-pointer hover:bg-var(--lavender-300) rounded-lg p-3"
className="cursor-pointer hover:bg-[var(--lavender-300)] rounded-lg p-3"
>
<FileDown className="h-4 w-4 mr-2 text-var(--purple-lavender)" />
<span className="text-var(--purple-ink)">Export All Donations</span>
<FileDown className="h-4 w-4 mr-2 text-[var(--purple-lavender)]" />
<span className="text-[var(--purple-ink)]">Export All Donations</span>
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleExport('current')}
className="cursor-pointer hover:bg-var(--lavender-300) rounded-lg p-3"
className="cursor-pointer hover:bg-[var(--lavender-300)] rounded-lg p-3"
>
<FileDown className="h-4 w-4 mr-2 text-var(--purple-lavender)" />
<span className="text-var(--purple-ink)">Export Current View</span>
<FileDown className="h-4 w-4 mr-2 text-[var(--purple-lavender)]" />
<span className="text-[var(--purple-ink)]">Export Current View</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
@@ -306,7 +306,7 @@ const AdminDonations = () => {
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div>
<Select value={typeFilter} onValueChange={setTypeFilter}>
<SelectTrigger className="rounded-full border-2 border-var(--neutral-800)">
<SelectTrigger className="rounded-full border-2 border-[var(--neutral-800)]">
<SelectValue placeholder="All Types" />
</SelectTrigger>
<SelectContent>
@@ -319,7 +319,7 @@ const AdminDonations = () => {
<div>
<Select value={statusFilter} onValueChange={setStatusFilter}>
<SelectTrigger className="rounded-full border-2 border-var(--neutral-800)">
<SelectTrigger className="rounded-full border-2 border-[var(--neutral-800)]">
<SelectValue placeholder="All Statuses" />
</SelectTrigger>
<SelectContent>
@@ -336,7 +336,7 @@ const AdminDonations = () => {
type="date"
value={startDate}
onChange={(e) => setStartDate(e.target.value)}
className="rounded-full border-2 border-var(--neutral-800)"
className="rounded-full border-2 border-[var(--neutral-800)]"
placeholder="Start Date"
/>
</div>
@@ -346,7 +346,7 @@ const AdminDonations = () => {
type="date"
value={endDate}
onChange={(e) => setEndDate(e.target.value)}
className="rounded-full border-2 border-var(--neutral-800)"
className="rounded-full border-2 border-[var(--neutral-800)]"
placeholder="End Date"
/>
</div>
@@ -354,7 +354,7 @@ const AdminDonations = () => {
{/* Active Filters Summary */}
{(searchQuery || typeFilter !== 'all' || statusFilter !== 'all' || startDate || endDate) && (
<div className="text-sm text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<div className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Showing {filteredDonations.length} of {donations.length} donations
</div>
)}
@@ -362,38 +362,38 @@ const AdminDonations = () => {
</Card>
{/* Donations Table */}
<Card className="bg-background rounded-2xl border-2 border-var(--neutral-800) overflow-hidden">
<Card className="bg-background rounded-2xl border-2 border-[var(--neutral-800)] overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-var(--lavender-300) border-b-2 border-var(--neutral-800)">
<thead className="bg-[var(--lavender-300)] border-b-2 border-[var(--neutral-800)]">
<tr>
<th className="px-6 py-4 text-left text-sm font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
<th className="px-6 py-4 text-left text-sm font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Donor
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
<th className="px-6 py-4 text-left text-sm font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Type
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
<th className="px-6 py-4 text-left text-sm font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Amount
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
<th className="px-6 py-4 text-left text-sm font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Status
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
<th className="px-6 py-4 text-left text-sm font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Date
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
<th className="px-6 py-4 text-left text-sm font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
Payment Method
</th>
</tr>
</thead>
<tbody className="divide-y divide-var(--neutral-800)">
<tbody className="divide-y divide-[var(--neutral-800)]">
{filteredDonations.length === 0 ? (
<tr>
<td colSpan="6" className="px-6 py-12 text-center">
<div className="flex flex-col items-center gap-3">
<Heart className="h-12 w-12 text-var(--neutral-800)" />
<p className="text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<Heart className="h-12 w-12 text-[var(--neutral-800)]" />
<p className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{donations.length === 0 ? 'No donations yet' : 'No donations match your filters'}
</p>
</div>
@@ -401,13 +401,13 @@ const AdminDonations = () => {
</tr>
) : (
filteredDonations.map((donation) => (
<tr key={donation.id} className="hover:bg-var(--lavender-400) transition-colors">
<tr key={donation.id} className="hover:bg-[var(--lavender-400)] transition-colors">
<td className="px-6 py-4">
<div>
<p className="font-medium text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="font-medium text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
{donation.donor_name || 'Anonymous'}
</p>
<p className="text-sm text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-sm text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{donation.donor_email || 'No email'}
</p>
</div>
@@ -421,7 +421,7 @@ const AdminDonations = () => {
</Badge>
</td>
<td className="px-6 py-4">
<p className="font-semibold text-var(--purple-ink) text-lg" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="font-semibold text-[var(--purple-ink)] text-lg" style={{ fontFamily: "'Inter', sans-serif" }}>
{donation.amount}
</p>
</td>
@@ -431,7 +431,7 @@ const AdminDonations = () => {
</Badge>
</td>
<td className="px-6 py-4">
<div className="flex items-center gap-2 text-var(--purple-lavender)">
<div className="flex items-center gap-2 text-[var(--purple-lavender)]">
<Calendar className="h-4 w-4" />
<span style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{formatDate(donation.created_at)}
@@ -439,7 +439,7 @@ const AdminDonations = () => {
</div>
</td>
<td className="px-6 py-4">
<p className="text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-[var(--purple-lavender)]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{donation.payment_method || 'N/A'}
</p>
</td>
@@ -453,18 +453,18 @@ const AdminDonations = () => {
{/* This Month Summary */}
{stats.this_month_count > 0 && (
<Card className="p-6 bg-gradient-to-r from-var(--lavender-400) to-var(--lavender-300) rounded-2xl border-2 border-var(--neutral-800)">
<Card className="p-6 bg-gradient-to-r from-[var(--lavender-400)] to-[var(--lavender-300)] rounded-2xl border-2 border-[var(--neutral-800)]">
<div className="flex items-center justify-between">
<div>
<p className="text-var(--purple-lavender) font-medium" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
<p className="text-[var(--purple-lavender)] font-medium" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
This Month's Donations
</p>
<p className="text-2xl font-bold text-var(--purple-ink) mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
<p className="text-2xl font-bold text-[var(--purple-ink)] mt-2" style={{ fontFamily: "'Inter', sans-serif" }}>
{stats.this_month_count} donations • {stats.this_month_amount}
</p>
</div>
<div className="p-4 bg-background rounded-full shadow-sm">
<Heart className="h-8 w-8 text-var(--orange-light)" />
<Heart className="h-8 w-8 text-[var(--orange-light)]" />
</div>
</div>
</Card>