Files
codetutor/frontend/src/app/progress/page.tsx
T

122 lines
3.4 KiB
TypeScript

"use client";
import { useState, useEffect, useCallback } from "react";
import Link from "next/link";
import { getProgressData } from "@/lib/progress";
import { getReviewSuggestions } from "@/lib/spaced-repetition";
import { getQuestions, getPatterns } from "@/lib/api";
import {
ProgressOverview,
PatternProgress,
ReviewSuggestions,
ProgressExport,
} from "@/components/progress";
import type {
ProgressData,
Pattern,
QuestionListItem,
ReviewCandidate,
} from "@/types";
import { Loader2 } from "lucide-react";
export default function ProgressPage() {
const [progressData, setProgressData] = useState<ProgressData | null>(null);
const [questions, setQuestions] = useState<QuestionListItem[]>([]);
const [patterns, setPatterns] = useState<Pattern[]>([]);
const [reviewCandidates, setReviewCandidates] = useState<ReviewCandidate[]>(
[]
);
const [isLoading, setIsLoading] = useState(true);
const loadData = useCallback(async () => {
setIsLoading(true);
try {
const progress = getProgressData();
setProgressData(progress);
const [questionsRes, patternsRes] = await Promise.all([
getQuestions({ limit: 1000 }),
getPatterns(),
]);
setQuestions(questionsRes.items);
setPatterns(patternsRes.items);
const candidates = getReviewSuggestions(progress, questionsRes.items);
setReviewCandidates(candidates);
} catch (error) {
console.error("Failed to load progress data:", error);
} finally {
setIsLoading(false);
}
}, []);
useEffect(() => {
loadData();
}, [loadData]);
const handleImportSuccess = () => {
loadData();
};
if (isLoading || !progressData) {
return (
<div className="flex items-center justify-center py-16">
<Loader2 className="h-8 w-8 animate-spin text-[var(--primary)]" />
</div>
);
}
const hasProgress = Object.keys(progressData.questions).length > 0;
return (
<div className="space-y-8">
<div>
<h1 className="text-3xl font-bold">Progress Dashboard</h1>
<p className="text-[var(--muted-foreground)] mt-2">
Track your learning journey and review questions using spaced
repetition.
</p>
</div>
<ProgressOverview
progressData={progressData}
totalQuestions={questions.length}
/>
{!hasProgress && (
<div className="rounded-lg border border-[var(--border)] bg-[var(--card)] p-8 text-center">
<h2 className="text-lg font-semibold mb-2">Get Started</h2>
<p className="text-[var(--muted-foreground)] mb-4">
Complete some questions to start tracking your progress. Your data
is stored locally in your browser.
</p>
<Link
href="/questions"
className="inline-flex items-center px-4 py-2 text-sm font-medium rounded bg-[var(--primary)] text-[var(--primary-foreground)] hover:opacity-90 transition-opacity"
>
Browse Questions
</Link>
</div>
)}
{hasProgress && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
<ReviewSuggestions
candidates={reviewCandidates}
questions={questions}
/>
<PatternProgress
progressData={progressData}
patterns={patterns}
questions={questions}
/>
</div>
)}
<ProgressExport onImportSuccess={handleImportSuccess} />
</div>
);
}