From f243847216279cbd43879de8b5ef6dcceb3a2f1d Mon Sep 17 00:00:00 2001 From: polwex Date: Thu, 29 May 2025 14:08:02 +0700 Subject: lets see --- src/components/Flashcard/StudySession.tsx | 229 ++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 src/components/Flashcard/StudySession.tsx (limited to 'src/components/Flashcard/StudySession.tsx') diff --git a/src/components/Flashcard/StudySession.tsx b/src/components/Flashcard/StudySession.tsx new file mode 100644 index 0000000..1f79e09 --- /dev/null +++ b/src/components/Flashcard/StudySession.tsx @@ -0,0 +1,229 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { DeckResponse, CardResponse } from "@/lib/types/cards"; +import { startStudySession, getUserStudyStats } from "@/actions/srs"; +import StudyCard from "./StudyCard"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { Progress } from "@/components/ui/progress"; +import { Skeleton } from "@/components/ui/skeleton"; +import { cn } from "@/lib/utils"; + +interface StudySessionProps { + userId: number; + lessonId: number; + initialData?: DeckResponse; +} + +export default function StudySession({ userId, lessonId, initialData }: StudySessionProps) { + const [deckData, setDeckData] = useState(initialData || null); + const [currentCardIndex, setCurrentCardIndex] = useState(0); + const [reviewedCards, setReviewedCards] = useState([]); + const [isLoading, setIsLoading] = useState(!initialData); + const [isCompleted, setIsCompleted] = useState(false); + const [stats, setStats] = useState(null); + const [error, setError] = useState(null); + + // Load the deck data if not provided + useEffect(() => { + if (!initialData) { + loadDeck(); + } + + // Load user stats + loadStats(); + }, []); + + // Load deck data + const loadDeck = async () => { + setIsLoading(true); + setError(null); + + try { + const result = await startStudySession(userId, lessonId, true); + + if ('error' in result) { + setError(result.error); + setDeckData(null); + } else { + setDeckData(result); + } + } catch (error) { + console.error("Error loading deck:", error); + setError("Failed to load study session. Please try again later."); + } finally { + setIsLoading(false); + } + }; + + // Load user stats + const loadStats = async () => { + try { + const userStats = await getUserStudyStats(userId); + setStats(userStats); + } catch (error) { + console.error("Error loading stats:", error); + } + }; + + // Handle card completion + const handleCardComplete = (updatedCard: CardResponse) => { + // Add to reviewed cards + setReviewedCards(prev => [...prev, updatedCard]); + + // Move to next card + if (deckData && currentCardIndex < deckData.cards.length - 1) { + setCurrentCardIndex(currentCardIndex + 1); + } else { + // End of deck + setIsCompleted(true); + } + + // Refresh stats + loadStats(); + }; + + // Skip current card + const handleSkip = () => { + if (deckData && currentCardIndex < deckData.cards.length - 1) { + setCurrentCardIndex(currentCardIndex + 1); + } + }; + + // Restart session + const handleRestart = () => { + setCurrentCardIndex(0); + setReviewedCards([]); + setIsCompleted(false); + loadDeck(); + }; + + // Calculate completion percentage + const getCompletionPercentage = () => { + if (!deckData) return 0; + return (reviewedCards.length / deckData.cards.length) * 100; + }; + + // Get current card + const getCurrentCard = (): CardResponse | null => { + if (!deckData || !deckData.cards || deckData.cards.length === 0) return null; + return deckData.cards[currentCardIndex]; + }; + + // Render loading state + if (isLoading) { + return ( +
+ +
+ + +
+ + +
+
+
+
+ ); + } + + // Render error state + if (error) { + return ( +
+ +
{error}
+ +
+
+ ); + } + + // Render completion state + if (isCompleted || !getCurrentCard()) { + return ( +
+ +
+

Study Session Completed!

+
+

You've reviewed {reviewedCards.length} cards.

+ {stats && ( +
+

Total cards: {stats.totalCards}

+

Mastered cards: {stats.masteredCards}

+

Due cards remaining: {stats.dueCards}

+
+ )} +
+
+ + +
+
+
+
+ ); + } + + // Render study session + return ( +
+
+
+

+ {deckData?.lesson.name} +

+
+ {reviewedCards.length} / {deckData?.cards.length} cards +
+
+ +
+ + + +
+ + +
+ + {stats && ( +
+

Your Progress

+
+
+
{stats.totalCards}
+
Total Cards
+
+
+
{stats.masteredCards}
+
Mastered
+
+
+
{stats.dueCards}
+
Due Today
+
+
+
{stats.streakDays}
+
Day Streak
+
+
+
+ )} +
+ ); +} \ No newline at end of file -- cgit v1.2.3