Skip to main content

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 = false for the current user
  • Read/Unread tracking: Items can be marked as read (stored in pending_item_reads table)
  • 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 item
  • item_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 navigation
  • setHighlightedTodoId() - 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_goals table
  • 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) in src/lib/db/donations.ts — used by RecentDonationsTable.tsx with React Query key ['recentDonations', selectedEntity, timePeriod].
  • Legacy / other consumers: fetchRecentDonationsForDashboard(entityId, limit) in src/lib/db/dashboard.tsHook: useRecentDonations() in src/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 todos
  • todos:write - Create and edit todos
  • todos: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 visibility
  • isLayoutEditing - Layout edit mode

Global State (AppContext)

  • selectedEntity - Current organization
  • timePeriod - Selected time period
  • dashboardLayout - Component order array
  • currentPage - Current page ('dashboard')
  • theme - Light/dark mode
  • todos - Todo list

Dependencies

Internal Dependencies

  • useAppStore - Zustand global state management
  • useDashboardMetrics.ts - React Query hooks for data fetching
  • UI components (Card, Button, Select, etc.)
  • Chart library (Recharts)

External Libraries

  • lucide-react - Icons
  • recharts - 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 cards
  • useDashboardMetrics() - Raw metrics data
  • useRecentDonations() - Recent donations
  • useTopDonors() - Top donors
  • useDonationsByPeriod() - Chart data

Global Fund Management Integration

  • Entity mapping via getOrgId() / getEntityId() in entityMapping.ts
  • All queries filter by organization_id when entity selected
  • 'all' returns data across all organizations

Related Documentation

Additional Notes

Dashboard Component Types

Core Components (always in default layout, cannot be removed):

  • donations-chart - Donation trends line chart
  • recent-donations - Recent donations table
  • to-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_layout in 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 fetchTopDonors function 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

Ready to get started?Start Plus Trial