Skip to content

Add donation donor chart#82

Open
ItsEricSun wants to merge 10 commits intomainfrom
75-Donation-Donor-Stats-Chart
Open

Add donation donor chart#82
ItsEricSun wants to merge 10 commits intomainfrom
75-Donation-Donor-Stats-Chart

Conversation

@ItsEricSun
Copy link
Contributor

@ItsEricSun ItsEricSun commented Feb 19, 2026

Description

Added chart.tsx and dropdown-menu.tsx shadcn components.
Added getDonations to frontend apiClient to fetch all donations for the chart.
Added DonorStatsChart.tsx as a component to show the chart with the donation data.
Updated app.tsx to add the chart display under /chart as an admin-protected page.

Changes Made

  • Backend changes
  • Frontend changes
  • Database schema changes
  • Configuration updates
  • Other

Testing & Verification

  • Unit tests pass
  • Manual testing completed
  • No breaking changes

Verification Steps:

Run yarn to install new packages needed for new shadcn components.
Run this SQL in adminer to add in sample data into the donations table:

-- Sample donation data for testing the DonorStatsChart
-- Mix of one-time and recurring donations across the last 3 months

INSERT INTO donations (
  "firstName", 
  "lastName", 
  email, 
  amount, 
  "isAnonymous", 
  "donationType", 
  "recurringInterval", 
  "dedicationMessage", 
  "showDedicationPublicly", 
  status, 
  "transactionId", 
  "createdAt", 
  "updatedAt"
) VALUES
-- Recent one-time donations (last 2 weeks)
('John', 'Smith', 'john.smith@example.com', 5000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260218001', '2026-02-18 10:30:00', '2026-02-18 10:30:00'),
('Sarah', 'Johnson', 'sarah.j@example.com', 10000, false, 'one_time', NULL, 'In memory of my grandmother', true, 'succeeded', 'txn_20260217001', '2026-02-17 14:20:00', '2026-02-17 14:20:00'),
('Michael', 'Brown', 'mbrown@example.com', 2500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260216001', '2026-02-16 09:15:00', '2026-02-16 09:15:00'),
('Emily', 'Davis', 'emily.davis@example.com', 7500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260215001', '2026-02-15 16:45:00', '2026-02-15 16:45:00'),
('Anonymous', 'Donor', 'anon1@example.com', 15000, true, 'one_time', NULL, 'For the children', true, 'succeeded', 'txn_20260214001', '2026-02-14 11:30:00', '2026-02-14 11:30:00'),
('David', 'Wilson', 'dwilson@example.com', 3000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260213001', '2026-02-13 13:20:00', '2026-02-13 13:20:00'),
('Lisa', 'Martinez', 'lisa.m@example.com', 5000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260212001', '2026-02-12 10:00:00', '2026-02-12 10:00:00'),
('James', 'Anderson', 'james.a@example.com', 8000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260211001', '2026-02-11 15:30:00', '2026-02-11 15:30:00'),

-- Recurring donations (established over last 3 months)
-- Feb 10 - 3 new recurring donors
('Robert', 'Taylor', 'robert.t@example.com', 2500, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20260210001', '2026-02-10 09:00:00', '2026-02-10 09:00:00'),
('Jennifer', 'Thomas', 'jen.thomas@example.com', 5000, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20260210002', '2026-02-10 14:15:00', '2026-02-10 14:15:00'),
('William', 'Jackson', 'wjackson@example.com', 1000, false, 'recurring', 'weekly', NULL, false, 'succeeded', 'txn_20260210003', '2026-02-10 16:45:00', '2026-02-10 16:45:00'),
-- Feb 7 - 2 new recurring donors
('Mary', 'White', 'mary.white@example.com', 10000, false, 'recurring', 'quarterly', 'Supporting education', true, 'succeeded', 'txn_20260207001', '2026-02-07 10:30:00', '2026-02-07 10:30:00'),
('Richard', 'Harris', 'rharris@example.com', 3000, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20260207002', '2026-02-07 16:00:00', '2026-02-07 16:00:00'),

-- January donations (1-4 weeks ago)
('Patricia', 'Martin', 'patricia.m@example.com', 4500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260201001', '2026-02-01 12:00:00', '2026-02-01 12:00:00'),
('Charles', 'Thompson', 'charles.t@example.com', 6000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260130001', '2026-01-30 14:30:00', '2026-01-30 14:30:00'),
-- Jan 28 - 2 new recurring donors
('Linda', 'Garcia', 'linda.g@example.com', 2000, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20260128001', '2026-01-28 09:20:00', '2026-01-28 09:20:00'),
('Susan', 'Lee', 'susan.lee@example.com', 5000, false, 'recurring', 'bimonthly', NULL, false, 'succeeded', 'txn_20260128002', '2026-01-28 15:45:00', '2026-01-28 15:45:00'),
('Joseph', 'Rodriguez', 'joseph.r@example.com', 7500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260125001', '2026-01-25 11:00:00', '2026-01-25 11:00:00'),
('Daniel', 'Walker', 'daniel.w@example.com', 3500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260120001', '2026-01-20 10:15:00', '2026-01-20 10:15:00'),
('Karen', 'Hall', 'karen.h@example.com', 8500, false, 'one_time', NULL, 'In honor of my parents', true, 'succeeded', 'txn_20260118001', '2026-01-18 13:30:00', '2026-01-18 13:30:00'),
-- Jan 15 - 4 new recurring donors
('Thomas', 'Allen', 'thomas.a@example.com', 4000, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20260115001', '2026-01-15 09:45:00', '2026-01-15 09:45:00'),
('Betty', 'Wright', 'betty.w@example.com', 1500, false, 'recurring', 'weekly', NULL, false, 'succeeded', 'txn_20260115002', '2026-01-15 11:00:00', '2026-01-15 11:00:00'),
('Angela', 'Foster', 'angela.f@example.com', 3500, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20260115003', '2026-01-15 14:30:00', '2026-01-15 14:30:00'),
('Brian', 'Murphy', 'brian.m@example.com', 2000, false, 'recurring', 'weekly', NULL, false, 'succeeded', 'txn_20260115004', '2026-01-15 16:20:00', '2026-01-15 16:20:00'),
('Nancy', 'Young', 'nancy.y@example.com', 6500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260112001', '2026-01-12 14:20:00', '2026-01-12 14:20:00'),
('Christopher', 'King', 'chris.king@example.com', 2500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260110001', '2026-01-10 11:30:00', '2026-01-10 11:30:00'),
('Matthew', 'Lopez', 'matthew.l@example.com', 9000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20260105001', '2026-01-05 10:00:00', '2026-01-05 10:00:00'),

-- December donations (2-3 months ago)
('Margaret', 'Hill', 'margaret.h@example.com', 5500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20251228001', '2025-12-28 12:45:00', '2025-12-28 12:45:00'),
-- Dec 25 - 2 new recurring donors
('Donald', 'Scott', 'donald.s@example.com', 3000, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20251225001', '2025-12-25 09:30:00', '2025-12-25 09:30:00'),
('Ashley', 'Baker', 'ashley.b@example.com', 6000, false, 'recurring', 'quarterly', NULL, false, 'succeeded', 'txn_20251225002', '2025-12-25 15:00:00', '2025-12-25 15:00:00'),
('Sandra', 'Green', 'sandra.g@example.com', 7000, false, 'one_time', NULL, 'Season of giving', true, 'succeeded', 'txn_20251220001', '2025-12-20 14:15:00', '2025-12-20 14:15:00'),
('Paul', 'Adams', 'paul.a@example.com', 4500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20251215001', '2025-12-15 11:20:00', '2025-12-15 11:20:00'),
('Mark', 'Nelson', 'mark.n@example.com', 8000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20251205001', '2025-12-05 10:30:00', '2025-12-05 10:30:00'),
-- Dec 1 - 3 new recurring donors
('Dorothy', 'Carter', 'dorothy.c@example.com', 2000, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20251201001', '2025-12-01 13:45:00', '2025-12-01 13:45:00'),
('Michelle', 'Cooper', 'michelle.c@example.com', 2500, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20251201002', '2025-12-01 10:20:00', '2025-12-01 10:20:00'),
('Frank', 'Richardson', 'frank.r@example.com', 1800, false, 'recurring', 'weekly', NULL, false, 'succeeded', 'txn_20251201003', '2025-12-01 16:30:00', '2025-12-01 16:30:00'),

-- November donations (3 months ago)
('Steven', 'Mitchell', 'steven.m@example.com', 5000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20251125001', '2025-11-25 09:15:00', '2025-11-25 09:15:00'),
-- Nov 20 - 2 new recurring donors
('Donna', 'Perez', 'donna.p@example.com', 3500, false, 'recurring', 'annually', 'Annual contribution', false, 'succeeded', 'txn_20251120001', '2025-11-20 14:30:00', '2025-11-20 14:30:00'),
('Kenneth', 'Phillips', 'kenneth.p@example.com', 2500, false, 'recurring', 'monthly', NULL, false, 'succeeded', 'txn_20251120002', '2025-11-20 10:45:00', '2025-11-20 10:45:00'),
('George', 'Roberts', 'george.r@example.com', 4000, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20251115001', '2025-11-15 11:00:00', '2025-11-15 11:00:00'),
('Carol', 'Turner', 'carol.t@example.com', 6500, false, 'one_time', NULL, NULL, false, 'succeeded', 'txn_20251110001', '2025-11-10 16:20:00', '2025-11-10 16:20:00'),

-- A few failed/pending donations (should not appear in chart)
('Test', 'Pending', 'pending@example.com', 5000, false, 'one_time', NULL, NULL, false, 'pending', NULL, '2026-02-18 09:00:00', '2026-02-18 09:00:00'),
('Test', 'Failed', 'failed@example.com', 3000, false, 'one_time', NULL, NULL, false, 'failed', 'txn_20260217002', '2026-02-17 10:00:00', '2026-02-17 10:00:00'),
('Test', 'Cancelled', 'cancelled@example.com', 2000, false, 'recurring', 'monthly', NULL, false, 'cancelled', 'txn_20260216002', '2026-02-16 11:00:00', '2026-02-16 11:00:00');

Then go to /admin and login with an admin account and view the graph.

Screenshots (if relevant)

Frontend.And.97.More.Pages.-.Personal.-.Microsoft.Edge.2026-02-18.19-37-07.mp4

Future Improvements/Notes

Related Issues

Closes #75

@ItsEricSun ItsEricSun self-assigned this Feb 19, 2026
@thaninbew thaninbew self-requested a review February 19, 2026 02:34
@thaninbew
Copy link
Collaborator

cool, looks like this when i fixed the tailwind issue:
image

@ItsEricSun
Copy link
Contributor Author

OHH thats so much better haha

Copy link
Collaborator

@thaninbew thaninbew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the file DonorStatsChart.tsx, there's a problem with the first useEffect. It has activeChart in its dependency array, which means every time you click a tab to switch charts, it makes a new API call to fetch donation data. This is wasteful because the data is already stored in the component's state.

The second useEffect already handles switching between the two chart views when activeChart changes, so we don't need the first one to re-run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Donation/Donor Stats Chart

2 participants

Comments