'use client'; import type { LearningViewProps } from '@contractspec/example.learning-journey-ui-shared'; import { Card, CardContent, CardHeader, CardTitle, } from '@contractspec/lib.ui-kit-web/ui/card'; import { DayCalendar } from '../components/DayCalendar'; export function Timeline({ track, progress }: LearningViewProps) { // Check if this is a quest with day unlocks const hasQuestDays = track.steps.some( (s) => s.availability?.unlockOnDay !== undefined ); if (hasQuestDays) { // Quest-style calendar view const totalDays = Math.max( ...track.steps.map((s) => s.availability?.unlockOnDay ?? 1), 7 ); const completedDays = track.steps .filter((s) => progress.completedStepIds.includes(s.id)) .map((s) => s.availability?.unlockOnDay ?? 1); // Current day is the first incomplete day const currentDay = track.steps.find((s) => !progress.completedStepIds.includes(s.id)) ?.availability?.unlockOnDay ?? 1; return (
{/* Header */}

{track.name}

Complete each day's challenge to progress

{/* Calendar Grid */} 📅 Your Journey {/* Daily Steps */} 📝 Daily Challenges
{track.steps.map((step) => { const day = step.availability?.unlockOnDay ?? 1; const isCompleted = progress.completedStepIds.includes(step.id); const isLocked = day > currentDay; return (
{isCompleted ? '✓' : isLocked ? '🔒' : day}

{step.title}

{step.description}

{step.xpReward && ( +{step.xpReward} XP )}
); })}
); } // Drill-style timeline (step order) return (
{/* Header */}

Learning Path

Follow the steps to master this skill

{/* Timeline */}
{/* Vertical line */}
{/* Steps */}
{track.steps.map((step, index) => { const isCompleted = progress.completedStepIds.includes(step.id); const isCurrent = !isCompleted && track.steps .slice(0, index) .every((s) => progress.completedStepIds.includes(s.id)); return (
{/* Node */}
{isCompleted ? '✓' : index + 1}
{/* Content */}

{step.title}

{step.description}

{step.xpReward && ( +{step.xpReward} XP )}
); })}
); }