Main Dashboard
Main Dashboard
Component Files: src/features/dashboard/components/* Route / navigation: Browser path `/dashboard` (PageView dashboard; root / may redirect per app shell). See navigationSlice.ts / AppSidebar.tsx. Access Level: All authenticated users Data Layer: Supabase client + React Query hooks (no REST API)
Overview
The Main Dashboard is the landing page of the application, providing an at-a-glance view of key metrics, donation trends, recent activity, and tasks. It features a customizable layout with quick reordering, time period filtering, and integrates with the global entity selector. The dashboard aggregates data from across the system to give users a comprehensive overview of their nonprofit's performance.
UI Features
Main Features
- Metrics Cards (4 cards):
- Total Donations (with trend)
- Recurring Monthly (with trend)
- Total Donors (with trend)
- Pending Items (count, opens panel)
- Time Period Selector:
- Day
- Week
- Month
- Year to Date (YTD)
- Last Year (with dynamic year label)
- Q1-Q4 (with dynamic year labels, e.g., "Q1 2026 (Jan-Mar)")
- Customizable Layout:
- Up/down arrow buttons for component reordering
- Simple vertical stack layout (all components full-width)
- "Change Layout" button to enter edit mode
- "Done" and "Reset" buttons in edit mode
- Remove button (trash icon) for addable components
- Dashboard Components (Core - Default Layout):
- Donation Trends Chart (line/bar/area)
- Recent Donations Table
- To-Do List
- Dashboard Components (Addable):
- Top Donors Widget (ranked list with progress bars)
- Fund Summary (cash balance with YoY indicator)
- Quick Actions (late donors, overdue pledges, overdue grants)
Metrics Cards
Each metric card displays:
- Label: Metric name
- Value: Current value (formatted)
- Trend Badge: Percentage change with up/down/neutral indicator
- Icon: Visual identifier
Pending Items Card & Panel
The "Pending Items" metric card is clickable and opens a modal panel showing actionable items:
Pending Items Panel Features:
- Modal size: 672px max width (
max-w-2xl), 85vh max height - Item types displayed:
- Pending Expenses: Expenses with
status = 'pending' - Incomplete Todos: Todos with
completed = falsefor the current user - Read/Unread tracking: Items can be marked as read (stored in
pending_item_readstable) - Mark all as read: Button to mark all items as read at once
- Navigation on click:
- Expenses → Accounting Hub > Expenses Manager
- Todos → Dashboard with todo highlighted and scrolled into view
- Organization filtering:
- Parent org view: Shows ALL expenses from child funds
- Specific fund view: Shows only that fund's expenses
- Todos: Always filtered by current user (created by or assigned to)
Todo Highlighting: When clicking a todo from the Pending Items panel: 1. Panel closes 2. Dashboard navigates to view 3. Todo scrolls into view with smooth animation 4. Todo is highlighted with primary color ring for 3 seconds 5. Highlight automatically clears
Database Tables:
pending_item_reads- Tracks which items a user has "read"user_id(UUID) - The user who read the itemitem_type(VARCHAR) - 'expense' or 'todo'item_id(UUID) - The ID of the item- Unique constraint on
(user_id, item_type, item_id)
State Management:
highlightedTodoId(UISlice) - ID of todo to highlight from pending items navigationsetHighlightedTodoId()- Action to set/clear highlighted todo
Donation Trends Chart
- Line chart showing donation amounts over time
- X-axis: Time periods (days, weeks, months)
- Y-axis: Donation amounts (formatted as $Xk)
- Responsive design
- Dark mode support
- Tooltip on hover
- Annual Goal Feature:
- Click target icon to set annual donation goal
- Goal line displayed on chart (dashed green)
- "On Pace" / "Behind Pace" badge based on year progress
- Goal is seasonally adjusted based on prior year patterns
- Stored per organization/fund and year in
donation_goalstable - Uses
getActualOrgId()to ensure consistent org ID for save/fetch - Parent org and individual funds can set goals; only "All Organizations" view disables goal setting
- Input Validation (Jan 19, 2026):
- Input restricted to numeric characters only (digits, commas, decimals)
- Real-time inline validation with error message display
- Save button disabled when input is empty or invalid
- Mobile-friendly with
inputMode="decimal"for numeric keyboard - Chart Type Selector:
- Toggle between Line, Bar, and Area chart visualizations
- Selection persisted to localStorage
Recent Donations Table
- Date
- Donor Name
- Amount
- Payment Method
- Status Badge
- Quick actions (View, Receipt)
- Pagination
- Sortable columns
Top Donors Table
- Rank
- Donor Name
- Total Donated (lifetime)
- Last Donation Date
- Donation Count
- Quick actions (View Profile)
To-Do List
- Task description
- Due date
- Priority badge
- Checkbox to mark complete
- Add new task button
- Filter by status (All, Active, Completed)
Data Requirements
Dashboard Metrics Data
- total_donations (decimal) - Total donations for period
- total_donations_change (decimal) - Percentage change vs previous period
- recurring_monthly (decimal) - Current month recurring total
- recurring_monthly_change (decimal) - Percentage change vs previous month
- total_donors (integer) - Number of donors in period
- total_donors_change (decimal) - Percentage change vs previous period
- pending_items (integer) - Pending expenses + incomplete todos
Donation Trends Data
- period (string) - Time period label
- amount (decimal) - Donation amount for period
- Array of data points based on selected time period
Recent Donations Data
- id (uuid) - Donation ID
- date (date) - Donation date
- donor_name (string) - Donor name
- amount (decimal) - Donation amount
- type (string) - 'one-time', 'recurring', 'event'
- purpose (string) - Purpose name (fund view)
- fund_name (string) - Fund name (parent org view)
Top Donors Data
- donor_id (uuid) - Donor ID
- donor_name (string) - Donor name
- total_donated (decimal) - Total donations in selected period
- last_donation_date (date) - Most recent donation in period
- donation_count (integer) - Number of donations in period
To-Do Data
- id (uuid) - Todo ID
- description (string) - Task description
- due_date (date, nullable) - Due date
- priority (string) - 'high', 'medium', 'low'
- status (string) - 'pending', 'completed'
- created_by_id (uuid) - User who created
- assigned_to_id (uuid, nullable) - User assigned to
Data Mutations
- Update Layout: Save dashboard component order
- Create Todo: Add new task
- Update Todo: Edit task or mark complete
- Delete Todo: Remove task
Data Functions (Supabase Client)
> Note: The dashboard uses Supabase client functions directly via React Query hooks. There is no REST API layer.
Dashboard Metrics
Function: fetchDashboardMetrics(entityId, timePeriod) in src/lib/db/dashboard.ts (via src/lib/db barrel) Hook: useDashboardMetrics() in src/hooks/useDashboardMetrics.ts
Returns aggregated metrics for the selected entity and time period:
- Total donations with period-over-period change
- Recurring monthly (current month from recurring donors)
- Unique donor count
- Pending items (expenses + todos)
Parent org selection: Uses `getOrgId(entityId)` only (DEVELOPER-PLAYBOOK §11). For parent_org entities, getOrgId is null and get_dashboard_metrics_v2 receives p_org_id: null, aggregating across the user’s org tree — consistent with fetchDonationTrends. Do not use getActualOrgId() as a read fallback on these queries.
Donation Trends
Function: fetchDonationTrends(entityId, timePeriod) in src/lib/db.ts Hook: Used directly in RevenueChart.tsx
Returns time-series data for the donation chart with:
- Current period amounts
- Prior period amounts (for YoY comparison)
- Dynamic grouping (daily/weekly/monthly based on period)
Recent Donations
- Main dashboard widget:
fetchRecentDonations(entityId, limit)insrc/lib/db/donations.ts— used byRecentDonationsTable.tsxwith React Query key['recentDonations', selectedEntity, timePeriod]. - Legacy / other consumers:
fetchRecentDonationsForDashboard(entityId, limit)insrc/lib/db/dashboard.ts— Hook:useRecentDonations()insrc/hooks/useDashboardMetrics.ts.
Both use `getOrgId` only for read scoping (§11); parent org shows gifts across child funds (RLS + hidden-org rules where applicable).
Top Donors
Function: fetchTopDonors(entityId, limit, startDate, endDate) in src/lib/db.ts Hook: useTopDonors(entityId, timePeriod, startDate, endDate) in src/hooks/useDashboardMetrics.ts RPC: get_top_donors(p_org_id, p_hidden_org_ids, p_start_date, p_end_date, p_limit) — server-side aggregation
Fund Summary
Function: fetchFundSummaryData(entityId, startDate, endDate) in src/lib/db.ts Hook: useFundSummary() in src/hooks/useDashboardMetrics.ts
Returns net income with YoY comparison using get_income_statement_data RPC.
Quick Actions
Function: fetchQuickActionsData(entityId, limit) in src/lib/db.ts Hook: useQuickActions() in src/hooks/useDashboardMetrics.ts
Returns actionable items: late donors, overdue pledges, overdue grants.
Donation Goals
Functions: fetchDonationGoal(), upsertDonationGoal() in src/lib/db.ts
Stored in donation_goals table per organization/year.
Todos
Functions: fetchTodos(), createTodo(), updateTodo(), deleteTodo() in src/lib/db.ts
Direct Supabase client operations on todos table.
Dashboard Layout
Functions: fetchUIPreferences(), saveUIPreferences() in src/lib/db.ts
Layout stored in user_preferences.ui_preferences.dashboardLayout as JSON.
Request/Response Schemas
DashboardMetrics Schema
interface DashboardMetrics {
total_donations: MetricValue;
recurring_monthly: MetricValue;
total_donors: MetricValue;
pending_items: MetricValue;
}
interface MetricValue {
value: number | string;
change: number;
trend: 'up' | 'down' | 'neutral';
}
interface DonationTrend {
period: string;
amount: number;
}
interface Todo {
id: string;
description: string;
due_date?: string;
priority: 'high' | 'medium' | 'low';
status: 'pending' | 'completed';
created_by: string;
assigned_to?: string;
created_at: string;
}Authentication & Authorization
Required Permissions
dashboard:read- View dashboard (all users)todos:read- View todostodos:write- Create and edit todostodos:delete- Delete todos
Role-Based Access
- Admin: Full access, sees all organizations
- Manager: Full access to assigned organizations
- Staff: Full access to assigned organizations
- Volunteer: Limited view, own todos only
Business Logic & Validations
Frontend Validations
- Time period selection required
- Organization selection handled by global entity selector (outside dashboard layout)
- Todo description required
- Due date must be in future (for new todos)
Backend Validations (Supabase RLS)
- Valid organization access via RLS policies
- Valid time period values
- Todo description max length (500 chars)
- User can only update own todos (unless admin/manager)
- Dashboard layout component IDs validated client-side
Business Rules
- Metrics calculated based on selected time period
- Comparison period is previous equivalent period
- "All Organizations" shows consolidated data
- Dashboard layout saved per user (global)
- Todos can be assigned to other users
- Completed todos remain visible
- Chart data aggregated by selected time period
- Recent donations limited by query limit (latest records)
- Top donors ranked by total giving in selected period
State Management
Local State
sidebarOpen- Mobile sidebar visibilityisLayoutEditing- Layout edit mode
Global State (AppContext)
selectedEntity- Current organizationtimePeriod- Selected time perioddashboardLayout- Component order arraycurrentPage- Current page ('dashboard')theme- Light/dark modetodos- Todo list
Dependencies
Internal Dependencies
useAppStore- Zustand global state managementuseDashboardMetrics.ts- React Query hooks for data fetching- UI components (Card, Button, Select, etc.)
- Chart library (Recharts)
External Libraries
lucide-react- Iconsrecharts- Charts@tanstack/react-query- Data fetching and caching
Error Handling
Error Scenarios
1. Network Error: Show toast "Unable to load dashboard", retry 2. No Data: Show empty state "No data available for this period" 3. Invalid Period: Default to 'month' 4. Layout Save Failed: Show toast "Failed to save layout" 5. Todo Create Failed: Show error message 6. Permission Error: Show toast "You don't have permission"
Loading States
- Initial load: Skeleton cards and charts
- Metrics refresh: Shimmer effect on cards
- Chart loading: Loading spinner overlay
- Todo actions: Disable buttons, show spinner
- Layout save: Brief loading indicator
Implementation Status
Last Updated: March 25, 2026
| Component | Status | Notes |
|-----------|--------|-------|
| Metrics Cards | ✅ Complete | Uses `fetchDashboardMetrics()` with RPC fallback; parent org = tree aggregate (`getOrgId` null) |
| Revenue Chart | ✅ Complete | Uses `fetchDonationTrends()` with React Query |
| Recent Donations | ✅ Complete | `RecentDonationsTable`: `fetchRecentDonations()` + client pagination; §11 read scoping |
| Top Donors | ✅ Complete | Uses `fetchTopDonors()` with React Query |
| Fund Summary | ✅ Complete | Uses `fetchFundSummaryData()` |
| Quick Actions | ✅ Complete | Uses `fetchQuickActionsData()` |
| Todo List | ✅ Complete | Full CRUD via `useTodos`, `useCreateTodo`, etc. |
| Time Period Filter | ✅ Complete | Day/Week/Month/YTD with trend calculation |
| Layout Editing | ✅ Complete | Vertical stack with add/remove + reordering |
Database Functions (src/lib/db barrel → dashboard.ts / donations.ts)
| Function | Purpose |
|----------|---------|
| `fetchDashboardMetrics()` | Metrics cards (donations, donors, pending items) |
| `fetchDonationTrends()` | Revenue chart data |
| `fetchRecentDonations()` | Recent donations table (dashboard widget) |
| `fetchRecentDonationsForDashboard()` | Alternate recent-donations shape for `useRecentDonations` hook |
| `fetchTopDonors()` | Top donors table |
| `fetchFundSummaryData()` | Fund summary card data |
| `fetchQuickActionsData()` | Quick actions card data |
| `fetchTodos()` | Todo list |
| `createTodo()` | Add new todo |
| `updateTodo()` | Edit/toggle todo |
| `deleteTodo()` | Delete todo |
React Query Hooks (src/hooks/useDashboardMetrics.ts)
useMetrics()- Formatted metrics for cardsuseDashboardMetrics()- Raw metrics datauseRecentDonations()- Recent donationsuseTopDonors()- Top donorsuseDonationsByPeriod()- Chart data
Global Fund Management Integration
- Entity mapping via
getOrgId()/getEntityId()inentityMapping.ts - All queries filter by
organization_idwhen entity selected 'all'returns data across all organizations
Related Documentation
- ../donor-hub/02-DONATIONS-MANAGER.md - Donation data source
- ../donor-hub/01-DONORS-CRM.md - Donor data source
- ../people/03-VOLUNTEERS-CRM.md - Volunteer hours source
- 01-DATA-SCHEMA.md - Historical data models
- 02-API-REQUIREMENTS.md - Historical API overview
Additional Notes
Dashboard Component Types
Core Components (always in default layout, cannot be removed):
donations-chart- Donation trends line chartrecent-donations- Recent donations tableto-do-list- To-Do list widget
Addable Components (optional, can be added/removed via edit mode):
top-donors- Top 5 donors by lifetime giving with progress bars
Layout Edit Mode
In edit mode, users can: 1. Reorder - Use the up/down arrow buttons (▲/▼) to move components 2. Add components - Click "Add Component" button to add optional charts 3. Remove components - Click the trash icon (only for addable components)
Layout State Structure
The dashboard layout is stored as a simple array of component IDs:
type DashboardLayoutItem = DashboardComponent;
// Example: ['donations-chart', 'recent-donations', 'to-do-list']Default layout (core components only):
['donations-chart', 'recent-donations', 'to-do-list']Layout Persistence
- Layout is saved to
user_preferences.dashboard_layoutin the database - Also cached in localStorage for fast initial load
- Synced across devices via Supabase
- Migration support: old object format
{ id, size }[]automatically converted to new string format
Addable Component Data Behavior
Top Donors Widget:
- Shows top 5 donors ranked by total giving in the selected period
- Clickable rows - Click any donor to navigate to their profile in DonorsCRM
- Uses
setSelectedDonor()+navigateTo('donors', 'donors')pattern - Uses existing
fetchTopDonorsfunction from db.ts - Displays donor name, total amount, donation count, and progress bar
- Filters by organization when specific entity selected
- Keyboard accessible (Enter key triggers navigation)
Fund Summary Card:
- Cash balance from balance sheet RPC with YoY comparison
- Status indicator (ahead/on-track/caution/behind)
- Jumpoff to Balance Sheet report
Quick Actions Card:
- Late recurring donors, overdue pledges, overdue grants
- Sorted by urgency, top 5 items shown
- Jumpoffs route to the relevant hub
Time Period Calculations
- Day: Last 24 hours, hourly breakdown
- Week: Last 7 days, daily breakdown
- Month: Last 4 weeks, weekly breakdown
- YTD: January 1 to today, monthly breakdown
- Last Year: January 1 - December 31 of previous year, monthly breakdown
- Q1-Q4: Uses smart year detection (see below), weekly breakdown
Smart Quarter Year Detection
Quarterly views use intelligent year detection to always show the most relevant data:
- If the quarter has started or passed in the current year → shows current year's quarter
- If the quarter has not yet started in the current year → shows last year's quarter
Example (today = January 5, 2026, which is Q1):
| Selection | Displayed Period | Comparison Period |
|-----------|------------------|-------------------|
| Q1 | Q1 2026 (Jan-Mar) | Q1 2025 |
| Q2 | Q2 2025 (Apr-Jun) | Q2 2024 |
| Q3 | Q3 2025 (Jul-Sep) | Q3 2024 |
| Q4 | Q4 2025 (Oct-Dec) | Q4 2024 |
UI Labels: Dropdown and chart labels dynamically include the year (e.g., "Q1 2026 (Jan-Mar)") so users always know which period they're viewing.
Implementation: The getSmartQuarterDateRange() function in src/lib/dateUtils.ts handles this logic centrally. All date range calculations for quarters use this utility.
Metrics Comparison Logic
- Compare current period to previous equivalent period
- Example: This month vs last month, Q1 2026 vs Q1 2025
- Trend calculated as: ((current - previous) / previous) * 100
- Quarterly comparisons: Always compare same quarter year-over-year (e.g., Q2 2025 vs Q2 2024)
Multi-Organization View
When "All Organizations" is selected:
- Metrics aggregated across all accessible organizations
- Charts show combined data
- Tables include organization column
- Todos from all organizations shown
Synced from IFMmvp-Frontend documentation: pages/dashboard/01-MAIN-DASHBOARD.md
Ready to Get Started?
See how Alignmint can simplify your nonprofit's operations. Schedule a free demo with our team and we'll walk you through everything.
Questions? Email us at steven@getalignmint.org