Settings
Settings
Component File: src/features/admin/components/Settings.tsx Route / navigation: Browser path `/settings` (PageView settings; PageRouter renders Settings — no separate *Tool enum). Access Level: All authenticated users Last Updated: March 22, 2026
> Implementation Note: The live page is a standalone settings route in the current router. The implementation uses Supabase clients plus store/auth hooks rather than AppContext.
Overview
The Settings component provides a comprehensive user settings interface with five tabs: Profile, Notifications, Security, Preferences, and Organization. Users can manage their personal information, notification preferences, security settings, application preferences, and organization details (if authorized). The interface adapts based on user role and permissions.
UI Features
Main Features
- 5-Tab Interface:
- Profile
- Notifications
- Security
- Preferences
- Organization
- Back Button: Returns to Administration Hub (if accessed from there)
- Responsive Design: Mobile-friendly tab layout
Tab 1: Profile
- Avatar Section:
- Current profile picture (initials fallback)
- Change Photo button
- File upload (JPG, PNG, GIF, max 5MB)
- Personal Information:
- First Name
- Last Name
- Email Address
- Phone Number
- Job Title
- Role (dropdown)
- Save Changes button
Tab 2: Notifications
Implemented by `NotificationPreferences` (src/components/shared/NotificationPreferences.tsx), loaded from `user_preferences.notification_settings` via saveNotificationSettings / fetchUserPreferences.
- Channels: Email on/off, in-app on/off. (Browser push is not implemented; no push toggle is shown.)
- Role-based categories: Expandable sections depend on position (
director,bookkeeper,assistant,custom, etc.) — e.g. donation thresholds, financial report emails, expenses, messaging alerts. Bookkeepers include a Financial Reports block (weekly donation summary, monthly statement, quarterly, year-end) aligned with edge functions. Assistants include Weekly Summaries (weekly_reports) for weekly email eligibility. - Digest / frequency: There is no user-facing “real-time vs daily digest” control. Stored
digest.frequencyis normalized to `realtime`; donation alert emails send immediately when email is on and amount/category rules pass (seesend-donation-alert). - Save: “Save Notification Preferences” persists the full JSON blob to
user_preferences.notification_settings.
Tab 3: Security
- Password Management:
- Current password field
- New password field
- Confirm password field
- Change Password button
- Reauthentication required for password changes
- Two-Factor Authentication:
- Enable/disable 2FA
- QR code for setup
- Requires current password to disable 2FA
- Active Sessions:
- Current device session details only
- Multi-device history planned
Tab 4: Preferences
- Language & Region:
- Language selector (English, Spanish, etc.)
- Timezone selector
- Date format selector (MM/DD/YYYY, DD/MM/YYYY, YYYY-MM-DD)
- Currency format
- Display Preferences:
- Theme toggle (Light/Dark) - syncs with global theme
- Compact mode
- Default view settings
- Save Preferences button
Tab 5: Organization
- Organization Details Card:
- Organization Name (editable)
- EIN (Tax ID) (editable)
- Address (editable)
- Phone Number (editable)
- Description (editable)
- Logo + Social media links (editable)
- Save Organization Details button
- Access Control:
- Parent org admins can edit master organization details.
- Enterprise fund users can edit their fund's overrides only if they are directors with read/write access.
- Read-only users see a read-only notice.
- Inheritance: Fund organizations can leave fields blank to inherit from the parent org (all fields).
- Scope: Parent org edits apply to all funds; fund edits are overrides for that fund only.
- Billing & Subscription Card:
- Current Plan badge (Beta Access)
- Coming Soon placeholder for:
- Subscription management
- Invoice history
- Payment method updates
- *Note: Stripe billing integration planned for future release*
Settings Layout
┌─────────────────────────────────────────────────┐
│ [Profile] [Notifications] [Security] [Preferences] [Organization] │
├─────────────────────────────────────────────────┤
│ │
│ Profile Information │
│ ┌─────────────────────────────────────┐ │
│ │ [Avatar] Change Photo │ │
│ └─────────────────────────────────────┘ │
│ │
│ First Name: [John ] │
│ Last Name: [Doe ] │
│ Email: [john@... ] │
│ Phone: [+1 555... ] │
│ │
│ [Save Changes] │
└─────────────────────────────────────────────────┘Data Requirements
User Profile
- user_id (uuid)
- first_name (string)
- last_name (string)
- email (string)
- phone (string, nullable)
- job_title (string, nullable)
- role (enum) - 'parent_org', 'fund_user', 'donor', 'volunteer'
- position (enum) - 'director', 'bookkeeper', 'assistant', 'custom'
- access_level (enum) - 'read_write', 'read_only'
- avatar_url (string, nullable)
Notification Preferences
- notification_settings (
jsonbonuser_preferences) - channels:
email,in_app(push may exist in legacy JSON but is unused) - categories: position-specific keys (
donations,fund_donations,financial_reports,weekly_reports,messaging, etc.) withenabledflags and thresholds - digest:
{ frequency, quiet_hours_start, quiet_hours_end }— frequency is always treated as `realtime` in product behavior (UI does not offer daily batching for donation alerts)
Security Settings
- two_factor_enabled (boolean)
- active_session (object) - Current device, browser, OS
- session_history (planned)
User Preferences
- language (string) - 'en', 'es', 'fr', etc.
- timezone (string) - IANA timezone
- date_format (string) - 'MM/DD/YYYY', 'DD/MM/YYYY', 'YYYY-MM-DD'
- theme (enum) - 'light', 'dark', 'system'
Organization Settings
- organization_id (uuid) - Parent organization ID or selected fund ID
- organization_name (string) - Editable by parent_org admins; fund users edit overrides when authorized
- ein (string) - Tax ID, editable by parent_org admins; fund overrides allowed when authorized
- address (string) - Physical address, editable by parent_org admins; fund overrides allowed when authorized
- phone (string) - Contact phone, editable by parent_org admins; fund overrides allowed when authorized
- description (string) - Organization description, editable by parent_org admins; fund overrides allowed when authorized
- Billing fields (planned):
- subscription_plan (string)
- subscription_cost (decimal)
- subscription_status (enum) - 'active', 'past_due', 'canceled'
- next_billing_date (date)
Request/Response Schemas
interface UserProfile {
user_id: string;
first_name: string;
last_name: string;
email: string;
phone?: string;
job_title?: string;
role: 'admin' | 'manager' | 'staff' | 'donor' | 'volunteer';
avatar_url?: string;
}
interface NotificationPreferences {
notification_settings: {
channels: {
email: boolean;
push: boolean;
in_app: boolean;
};
categories: {
donations?: { enabled: boolean; threshold?: number; include_recurring?: boolean };
fund_donations?: { enabled: boolean; threshold?: number; include_recurring?: boolean };
};
digest?: { frequency: 'realtime' | 'daily' };
};
}
interface UserPreferences {
language: string;
timezone: string;
date_format: string;
theme: 'light' | 'dark' | 'system';
}
interface OrganizationSettings {
organization_id: string;
organization_name: string;
ein: string;
address: string;
phone: string;
subscription: {
plan: string;
cost: number;
status: 'active' | 'past_due' | 'canceled';
next_billing_date: string;
};
api_key: string;
}Authentication & Authorization
Required Permissions
profile:read- View own profileprofile:update- Update own profileorganization:read- View organization settings (admin only)organization:update- Update organization settings (admin only)
Role-Based Access
- All Users: Can access Profile, Notifications, Security, Preferences tabs
- Parent Org Admin (role='parent_org'): Can access Organization tab and edit parent org details
- Fund User (role='fund_user'): Can access Organization tab for their fund only; edit requires director + read_write + eligible tier
- Donor/Volunteer: Organization tab hidden
Business Logic & Validations
Frontend Validations
- Email format validation
- Phone format validation
- Password strength requirements (min 8 chars, uppercase, lowercase, number, special char)
- Password confirmation match
- File size limit for avatar (5MB)
- Accepted file types for avatar (JPG, PNG, GIF)
- File size limit for organization logo (10MB)
- Accepted file types for logo (JPG, PNG, SVG, WebP)
Backend Validations (Supabase)
- Unique email check
- Valid timezone
- Valid language code
- Valid date format
- Password complexity requirements (Supabase Auth)
- Current password verification for password change (reauthentication)
- Organization access authorization
Business Rules
- Theme preference syncs with global theme state
- Notification preferences affect email/push delivery
- 2FA required for admin users (future)
- API key regeneration invalidates old key
- Organization settings only visible to authorized users
- Profile changes logged in audit trail
State Management
Local State
emailNotifications- Email togglepushNotifications- Push toggledonationAlerts- Donation alerts toggleweeklyReports- Weekly reports togglemonthlyReports- Monthly reports togglelanguage- Selected languagetimezone- Selected timezonedateFormat- Selected date format
Global State (Zustand Store)
selectedEntity- Current organization (fromuseAppStore)administrationTool- Current admin tool (fromuseAppStore)setAdministrationTool- Navigation function (fromuseAppStore)
Theme Context
theme- Global theme setting (fromuseTheme)toggleTheme- Theme toggle function (fromuseTheme)
Dependencies
Internal Dependencies
useAppStore- Zustand global stateuseAuth- Current user and refreshUser functionuseTheme- Theme contextfetchUserPreferences,upsertUserPreferences- Preferences from SupabaseupdateUser,uploadProfilePhoto,updateUserPassword- User managementfetchParentOrganization,updateOrganization- Organization management (db.ts)- UI components (Card, Button, Input, Switch, Tabs, etc.)
External Libraries
lucide-react- Iconssonner- Toast notifications
Error Handling
Error Scenarios
1. Network Error: Show toast "Unable to save settings" 2. Invalid Email: Show error "Invalid email format" 3. Weak Password: Show error "Password too weak" 4. Password Mismatch: Show error "Passwords don't match" 5. Wrong Current Password: Show toast "Current password incorrect" 6. Avatar Too Large: Show error "Image file is too large. Please use an image under 5MB." 7. Logo Too Large: Show error "Logo file is too large. Please use an image under 10MB." 8. Logo RLS Denied: Show error "Permission denied. Only organization directors can upload logos." 9. Logo Invalid Type: Show error "Invalid file type. Please upload a JPG, PNG, SVG, or WebP image." 10. Unauthorized: Show toast "You don't have permission"
Loading States
- Initial load: Skeleton form fields
- Save actions: Button loading state
- Avatar upload: Progress indicator
- Tab switching: Instant (no loading)
Migration Notes
Phase 1: Profile/Data Integration
1. Create/expand Supabase user/profile helpers and edge-function wiring where needed 2. Implement profile endpoints 3. Test CRUD operations 4. Add avatar upload
Phase 2: Preferences
1. Implement notification preferences 2. Implement user preferences 3. Test theme synchronization 4. Add validation
Phase 3: Security
1. Implement password change 2. Add 2FA setup 3. Add session management 4. Implement security log
Phase 4: Organization ✅ COMPLETE (January 2025)
1. ✅ Implement organization settings (name, EIN, address, phone, description) 2. 🔲 Add billing integration (Stripe - planned) 3. 🔲 Implement API key management (planned) 4. 🔲 Add usage analytics (planned)
Related Documentation
Additional Notes
Theme Synchronization
The theme toggle in Settings syncs with the global theme state in AppContext. Changes apply immediately across the entire application.
Notification Delivery
- Email notifications sent via configured email service
- Push notifications require browser permission
- Preferences stored per user
- Can be overridden by organization-level settings
Security Best Practices
- Passwords hashed with bcrypt
- 2FA using TOTP (Time-based One-Time Password)
- Session tokens with expiration
- Security events logged
- Failed login attempts tracked
Organization Tab Visibility & Permissions
The Organization tab is visible to parent_org and fund_user user types, but with different access levels:
- Parent Org Admin (parent_org + director): Full edit access to parent organization details (name, EIN, address, phone, description, logo, social links). Changes apply to all sub-funds.
- Fund User (director + read_write on enterprise/pro): Can edit their fund's overrides only, including uploading a fund-specific logo. Leaving fields blank inherits from the parent org.
- Fund User (non-director or read_only): Can view the Organization tab but sees a read-only notice.
- Donor/Volunteer: Organization tab is hidden from navigation.
API Key Usage
- Used for programmatic API access
- Should be kept secret
- Regeneration invalidates old key
- Rate limited per key
- Logged for audit purposes
Organization Logo Upload
- Storage bucket:
org-logos(public read) - File path:
{organization_id}/logo.{ext} - Max size: 10MB (bucket-enforced)
- Accepted types: JPG, PNG, SVG, WebP
- RLS policies:
- INSERT/UPDATE/DELETE:
is_parent_org_admin()OR fund director (role=fund_user, position=director, access_level=read_write) for their own org folder - SELECT: Public (anyone can view logos)
- Upsert: Uses
upsert: trueso re-uploads overwrite the existing file - Inheritance: Fund orgs with no logo display the parent org's logo
Changelog
Feb 10, 2026 — Logo Upload Fix
- P0 Fix: Added storage RLS INSERT/UPDATE/DELETE policies for fund directors on
org-logosbucket (was parent_org-only, blocking all fund user uploads) - P1 Fix: Increased bucket file size limit from 2MB to 10MB
- P2 Fix: Added WebP to accepted MIME types (bucket + frontend validation + file input)
- P2 Fix: Improved error messaging — specific toast messages for RLS denial, file too large, invalid type (was generic "Failed to upload logo")
Synced from IFMmvp-Frontend documentation: pages/administration/02-SETTINGS.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