References: plan.md, spec.md, UI.md
Summary: This file lists reusable React components, their props, state, events, data binding and responsive behavior.
Purpose: Global top navigation, brand, primary actions, user menu. Props:
- navItems: Array<{ label: string; href: string; icon?: ReactNode }>
- user?: { id: string; username: string; display_name?: string; avatarUrl?: string; account_type?: 'individual'|'ngo'|'brand' }
- onSignOut?: () => void
- onNavigate?: (href: string) => void State:
- isMobileMenuOpen: boolean
- isProfileMenuOpen: boolean Events:
- onNavigate(href)
- onSignOut Data binding:
- Reads auth state from context (Supabase Auth) or props; pulls notification counts and unread messages via hooks. Responsive behavior:
- Desktop: full nav inline.
- Tablet/Mobile: hamburger → off-canvas drawer; profile collapses to avatar menu.
- Sticky on scroll with compact header variant.
Purpose: Site links, legal, partners. Props:
- columns: Array<{ title: string; links: { label: string; href: string }[] }>
- socialLinks?: Array<{ provider: string; href: string }> State: none (pure presentational) Events: none aside from link clicks Data binding:
- Static content from CMS/config (/api/settings/footer) Responsive behavior:
- 3-column grid desktop, stacked single column on mobile; compact spacing. Note: Always display a small trusted-payment footer line — “Payments are securely processed by Paystack.”
Purpose: Compact campaign preview for feeds and search results. Props:
- campaign: { id, title, short_description, images: string[], goal, raised, creator: { username, display_name, avatarUrl, account_type }, is_published, status }
- onClick?: (campaignId: string) => void
- onDonate?: (campaignId: string) => void State:
- imageLoaded: boolean
- isFavorited?: boolean Events:
- onClick
- onFavoriteToggle Data binding:
- From /api/campaigns list or useCampaigns() hook.
- Progress computed client-side (raised / goal * 100). Responsive behavior:
- 3-column grid desktop, 2-column tablet, 1-column mobile.
- Hide long text on small screens; show compact progress bar. Notes:
- Verified creators aren’t visually marked publicly; account_type badge displayed below title.
Purpose: Donation input UI used in campaign sidebar and modal. Props:
- campaignId: string
- initialUsername?: string
- presets?: number[] (quick amounts)
- minAmount?: number (default ₦50)
- onSuccess?: (donationId: string) => void
- paystackPublicKey?: string State:
- username: string
- email?: string
- amount: number | null
- anonymous: boolean
- platformFee: number
- netAmount: number
- isSubmitting: boolean Events:
- onValidate
- onInitiate
- onPaymentSuccess
- onPaymentError Data binding:
- Fetches platform_fee_percent from /api/fees and previews net payout.
- Posts to /api/donations/initiate then opens Paystack flow; webhook updates donation record. Responsive behavior:
- Fixed sidebar on desktop; collapsible sticky card or modal on mobile.
- Inputs stacked vertically on narrow view; preset buttons scroll horizontally. Notes:
- Username validated with regex:
/^[A-Za-z0-9_]{3,30}$/- Anonymous toggle hides username publicly.
- After success, show donation receipt with paystack_reference, fee, and net amount.
- Show message: “Funds become available for withdrawal after 24 hours.”
Purpose: Display leaderboard entry for donor or campaign. Props:
- entry: { rank: number; username: string; display_name?: string; amount: number; period?: 'daily'|'weekly'|'monthly' }
- highlight?: boolean
- variant?: 'donor'|'campaign' State: none Events:
- onClickProfile(username) Data binding:
- From /api/leaderboards?period={period} or campaign-specific /api/leaderboards?campaignId. Responsive behavior:
- Compact single-line on mobile; avatar hidden on extra-small.
- Highlight current user if highlight=true. Notes:
- Leaderboards refresh every 24h; show “Updated {timestamp}”.
UpdateBlock Purpose: Show campaign updates (author posts). Props:
- update: { id, author: { username, display_name, avatarUrl }, title?, body, images?: string[], created_at }
- onOpenComments?: (updateId) => void State:
- isExpanded: boolean
- imageGalleryOpen: boolean Events:
- expand/collapse
- open gallery Data binding:
- /api/campaigns/:id/updates Responsive behavior:
- single column; images in 2-column grid mobile, 3 desktop.
CommentThread Props:
- campaignId: string
- updateId?: string
- comments: Comment[] Comment object:
- { id, parent_id?, author, body, created_at, is_anonymous } State:
- comments, replyDrafts, collapsedParents Events:
- onPost, onReply, onDelete, onEdit Data binding:
- /api/campaigns/:id/comments (GET/POST) Responsive behavior:
- Nested up to depth 5; collapsible replies on mobile. Notes:
- Guests can comment with optional name; “Post Anonymously” toggle.
- Realtime updates via Supabase subscription optional.
Purpose: Dashboard navigation and content switching. DashboardTabs Props:
- tabs: Array<{ key: string; label: string; badgeCount?: number }>
- activeKey: string
- onChange: (key) => void Sidebar Props:
- items: Array<{ key:string; label:string; icon?:ReactNode; href?:string }>
- collapsed?: boolean
- onCollapseToggle?: () => void State:
- activeKey, isCollapsed, isMobileOpen Events:
- onNavigate, onCollapseToggle Data binding:
- Tab counts from /api/dashboard/metrics. Responsive behavior:
- Desktop: sidebar fixed.
- Tablet/mobile: slide-over drawer; tabs horizontal scroll on narrow screens. Notes:
- Sidebar includes “Start New Assist”, “My Campaigns”, “My Donations”, “Verification”, “Withdrawals”, “Settings”.
Purpose: Show Dojah and Paystack BVN verification statuses and actions. Props:
- status: { dojah: 'pending'|'passed'|'failed', bvn: 'pending'|'matched'|'mismatch' }
- onRetry?: (source: 'dojah'|'bvn') => void State:
- optional isTooltipOpen Events:
- onRetry Data binding:
- /api/verifications for latest; Dojah/Paystack webhook updates. Responsive behavior:
- Inline badges desktop; stacked with text mobile. Notes:
- Show timestamps and next-step hints (“Upload ID”, “Retry BVN match”).
- On “Retry”, call verification endpoint.
Purpose: Request payout with BVN and bank selection and fee preview. Props:
- userId: string
- banks: Array<{ code:string; name:string }>
- minAmount?: number (default ₦5000)
- onSubmit?: (payload) => Promise State:
- selectedBankCode, accountNumber, bvn, amount, feePreview, isSubmitting, errors Events:
- onValidateAccount, onCalculateFee, onSubmit Data binding:
- Fetch /api/fees for platform/withdrawal fees.
- Validate BVN + bank via Paystack /api/paystack/resolve.
- Submit /api/withdrawals/request. Responsive behavior:
- Two-column (bank+amount) desktop; stacked mobile.
- Fee preview fixed below amount. Notes:
- Mask BVN input; do not persist full BVN client-side.
- Show “Funds eligible for withdrawal 24h after donation confirmation.”
- On success, show toast and refresh withdrawal history.
Purpose: Charts for donation trends, revenue, campaigns. Props:
- data: { labels: string[]; series: { name: string; values: number[] }[] }
- height?: number
- onFilterChange?: (filters) => void State:
- selectedRange, loading, hoveredPoint Events:
- onPointHover, onRangeSelect, onExportCSV Data binding:
- /api/admin/analytics endpoint. Responsive behavior:
- Full chart + legend desktop; legend collapses mobile. Implementation:
- Recharts or ApexCharts with responsive container. Notes:
- Add “Platform Revenue” and “Total Donations” charts per admin dashboard spec.
Purpose: Admin form to edit platform and withdrawal fees. Props:
- initial: { platform_fee_percent: number; withdrawal_fee_percent:number; withdrawal_fee_fixed:number }
- onSave: (newSettings) => Promise State:
- draftSettings, isSaving, validationErrors, lastSavedAt Events:
- onChange, onSave, onReset Data binding:
- /api/admin/settings (GET/POST). Responsive behavior:
- Single column mobile; inline desktop. Notes:
- Validate 0–100%.
- Changes affect new donations only.
- Show “Last updated by” (admin email) if metadata returned.
Purpose: Upload up to 5 images and one Mux video for campaign creation or updates. Props:
- maxImages?: number (default 5)
- allowVideo?: boolean (default true)
- onChange?: (uploadedMeta) => void
- uploadImageUrlFn?: (file) => Promise<{ uploadUrl, path }>
- createMuxUploadUrlFn?: (meta) => Promise<{ uploadUrl, uploadId }> State:
- images: Array<{ file, previewUrl, status:'pending'|'uploading'|'done'|'error', path? }>
- video: { file?, previewUrl?, status, muxUploadId?, muxAssetId?, duration? }
- queueProgress: number Events:
- onAddFiles, onRemoveFile, onStartUpload, onUploadProgress, onUploadComplete, onError Data binding:
- Images upload to Supabase Storage via signed URLs.
- Video uploaded to Mux via direct PUT; webhook updates status. Responsive behavior:
- Desktop: drag-and-drop grid thumbnails with progress bars.
- Mobile: vertical list; tap to upload; show warnings for file size/network. Notes:
- Validate image types, ≤10 MB each, ≤5 images.
- Validate video ≤200 MB, ≤120 s.
- Show inline accessible error messages.
Purpose: Admin tool to review webhook and system event logs. Props:
- logs: Array<{ id:string; source:'paystack'|'dojah'|'mux'; event_type:string; status:'success'|'failed'; created_at:string; payload_excerpt:string }>
- onRetry?: (id:string) => void State:
- expandedRow?: string Events:
- onRetry, row expand/collapse Data binding:
- /api/admin/webhooks (GET/POST for retry). Responsive behavior:
- Table desktop; stacked cards mobile. Notes:
- Mask sensitive fields (e.g., BVN).
- Color-code sources; failed rows red border.
- Allow CSV export of filtered logs.
Purpose: Show notifications (new donations, verification updates, withdrawals). Props:
- notifications: Array<{ id:string; type:string; message:string; created_at:string; read:boolean }>
- onMarkRead?: (id:string) => void
- onViewAll?: () => void State:
- isOpen, highlightedId? Events:
- onMarkRead, onViewAll Data binding:
- /api/notifications (GET/PATCH). Responsive behavior:
- Popover on desktop, full-screen sheet mobile. Notes:
- Unread indicator badge in Header icon.
- Auto-mark as read when opened.
Purpose: Show confirmed donation summary after Paystack success. Props:
- donation: { id, campaignTitle, amount, platform_fee, net_amount, paystack_reference, created_at }
- onClose: () => void State: none Events:
- onClose
- share link Data binding:
- Receives data from donation success callback. Responsive behavior:
- Centered modal desktop, full-screen mobile. Notes:
- Include “Share this campaign” CTA.
- Display “Funds available to creator after 24 h hold.”
End of components spec.