Skip to content

Latest commit

 

History

History
145 lines (111 loc) · 4.78 KB

File metadata and controls

145 lines (111 loc) · 4.78 KB

Dashboard Data Wiring Implementation Summary

Overview

Fixed the hardcoded dashboard stats issue by connecting to real data sources:

  • GET /api/me for learner profile via new useLearnerProfile hook
  • Learn Token contract for real LRN balance via existing useLearnToken hook
  • Course Milestone contract for enrolled courses & milestone progress via existing useCourse hook
  • Added skeleton loaders during data fetching
  • Graceful handling of unauthenticated state (wallet not connected)

Changes Made

1. Created useLearnerProfile Hook

File: src/hooks/useLearnerProfile.ts

  • Queries GET /api/me endpoint to fetch authenticated learner profile
  • Returns { profile, isLoading, error, address }
  • Automatically disabled when no wallet is connected
  • Uses React Query for caching with 5-minute stale time
  • Extensible interface for future profile fields (bio, avatar, etc.)

Key features:

export interface LearnerProfile {
	address: string
}

export function useLearnerProfile() {
	// Fetches from GET /api/me with Bearer token auth
	// Caches for 5 minutes
	// Auto-disabled when address is undefined
}

2. Updated Dashboard.tsx

File: src/pages/Dashboard.tsx

Removed Hardcoded Values:

  • Removed static stats array with hardcoded LRN balance (142), courses (2), milestones (14)
  • Removed static enrolledCourses array with fake course data

Added Real Data Sources:

// Fetch learner profile from backend
const { profile, isLoading: isLoadingProfile } = useLearnerProfile()

// Fetch LRN balance from contract (converts stroops → LRN)
const { balance: lrnBalance, isLoading: isLoadingBalance } =
	useLearnToken(address)

// Fetch enrolled courses and milestone progress from contract
const { enrolledCourses, progressMap, isCompletingMilestone } = useCourse()

Dynamic Stats Calculation:

  • LRN Balance: From contract; converts stroops to human-readable format with locale formatting
  • Courses Enrolled: From enrolledCourses.length
  • Milestones: Calculated from progressMap by summing completed milestone IDs
  • Gov Tokens: Placeholder (remains 0)

Skeleton Loaders:

  • 4 placeholder cards during loading state
  • 2 placeholder course cards during loading state
  • Using CSS animate-pulse with .glass-card styling for consistency

Unauthenticated State Handling:

if (!address) {
	return (
		<div className="min-h-screen flex items-center justify-center px-4">
			<div className="max-w-md text-center">
				<h1>Connect Your Wallet</h1>
				<p>To view your learning dashboard...</p>
				<Link to="/">Connect Wallet &rarr;</Link>
			</div>
		</div>
	)
}

Acceptance Criteria - All Met ✅

Criteria Status Implementation
LRN balance from contract, not hardcoded useLearnToken(address) with stroops-to-LRN conversion
Enrolled courses from backend/contract, not static array useCourse().enrolledCourses
Skeleton loaders shown while fetching Conditional rendering: isLoading ? <Skeleton /> : <Data />
Unauthenticated users see connect-wallet prompt Renders connect wallet CTA instead of returning null
All hardcoded stat values removed All stats now calculated from real data sources

Data Flow

Dashboard Component
├─ useLearnerProfile()
│  └─ GET /api/me → { address: string }
│
├─ useLearnToken(address)
│  └─ learn_token contract → balance: bigint (stroops)
│
└─ useCourse()
   ├─ course_milestone contract → enrolledCourses: Course[]
   └─ Returns progressMap with completed milestone counts

Stats Calculation:
- LRN Balance: convertStroopsToLRN(balance)
- Courses: enrolledCourses.length
- Milestones: sum(progressMap[courseId].completedMilestoneIds)

Testing Plan

  1. Wallet Connected Scenario:

    • Verify stats Display shows loading state
    • Verify real LRN balance appears (from contract)
    • Verify enrolled courses display (from useCourse)
    • Verify milestone count calculated correctly
  2. Wallet Not Connected Scenario:

    • Verify "Connect Your Wallet" prompt displays
    • Verify link to "/" works
  3. Loading States:

    • Verify skeleton loaders show while useLearnToken/useCourse hooks are loading
    • Verify proper transition from skeleton to real data
  4. Data Updates:

    • Verify stats update when new milestones are completed
    • Verify new course enrollments appear in the list