"use client"; import { CardResponse, DeckResponse } from "@/lib/types/cards"; import React, { ReactNode, useCallback, useEffect, useState, useTransition, } from "react"; import { Button } from "../ui/button"; import { ChevronLeftIcon, ChevronRightIcon, RotateCcwIcon } from "lucide-react"; import "./cards.css"; type CardData = { id: number; front: ReactNode; back: ReactNode; }; // --- Main App Component --- function Deck({ data, cards }: { data: any; cards: CardData[] }) { const [currentPage, setCurrentPage] = useState(0); const [currentIndex, setCurrentIndex] = useState(0); const [isFlipped, setIsFlipped] = useState(false); const [animationDirection, setAnimationDirection] = useState< "enter-left" | "enter-right" | "exit-left" | "exit-right" | "none" >("none"); const [isAnimating, setIsAnimating] = useState(false); const handleFlip = () => { if (isAnimating) return; setIsFlipped(!isFlipped); }; const handleNext = useCallback(() => { if (isAnimating || currentIndex >= cards.length - 1) return; setIsAnimating(true); setIsFlipped(false); // Flip back to front before changing card setAnimationDirection("exit-left"); setTimeout(() => { setCurrentIndex((prevIndex) => Math.min(prevIndex + 1, cards.length - 1)); setAnimationDirection("enter-right"); setTimeout(() => { setAnimationDirection("none"); setIsAnimating(false); }, 200); // Duration of enter animation }, 200); // Duration of exit animation }, [currentIndex, cards.length, isAnimating]); const handlePrev = useCallback(() => { if (isAnimating || currentIndex <= 0) return; setIsAnimating(true); setIsFlipped(false); // Flip back to front setAnimationDirection("exit-right"); setTimeout(() => { setCurrentIndex((prevIndex) => Math.max(prevIndex - 1, 0)); setAnimationDirection("enter-left"); setTimeout(() => { setAnimationDirection("none"); setIsAnimating(false); }, 200); // Duration of enter animation }, 200); // Duration of exit animation }, [currentIndex, isAnimating]); // Keyboard navigation useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (isAnimating) return; if (event.key === "ArrowRight") { handleNext(); } else if (event.key === "ArrowLeft") { handlePrev(); } else if (event.key === " " || event.key === "Enter") { // Space or Enter to flip event.preventDefault(); // Prevent scrolling if space is pressed handleFlip(); } }; window.addEventListener("keydown", handleKeyDown); return () => { window.removeEventListener("keydown", handleKeyDown); }; }, [handleNext, handlePrev, isAnimating]); const [isPending, startTransition] = useTransition(); const shuffle = () => { startTransition(async () => { "use server"; console.log("shuffling deck..."); }); }; if (cards.length === 0) { return (

No flashcards available.

); } const currentCard = cards[currentIndex]; if (!currentCard) return

wtf

; return (

Deck: {data.lesson.name}

{data.lesson.description}

{/* This div is for positioning the card and managing overflow during animations */}

Card {currentIndex + 1} of {cards.length}

Use Arrow Keys (← →) to navigate, Space/Enter to flip.
); } export default Deck; interface FlashcardProps { isFlipped: boolean; onFlip: () => void; animationDirection: | "enter-left" | "enter-right" | "exit-left" | "exit-right" | "none"; } interface ServerCards { front: ReactNode; back: ReactNode; } function FlashCard({ isFlipped, onFlip, animationDirection, front, back, }: FlashcardProps & ServerCards) { const getAnimationClass = () => { switch (animationDirection) { case "enter-right": return "animate-slide-in-right"; case "enter-left": return "animate-slide-in-left"; case "exit-right": return "animate-slide-out-right"; case "exit-left": return "animate-slide-out-left"; default: return ""; } }; return (
{front} {back}
); }