"use client"; import { useState } from "react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Header } from "@/components/layout/header"; import { Footer } from "@/components/layout/footer"; import { PracticeSection } from "@/components/practice/practice-section"; import { useCollapsibleSidebar, SidebarBackdrop, SidebarToggle, sidebarAsideClass, sidebarNavClass } from "@/components/layout/collapsible-sidebar"; import { curriculum, type Unit, type Topic } from "@/lib/curriculum"; import { cn } from "@/lib/utils"; import type { Difficulty, MathProblem } from "@/lib/problems/types"; import { generateFractionAddSubtract, generateFractionMultiply, generateFractionDivide, generateFractionOfQuantity, generateWholeFromFraction, generateFractionBodmas, generateSignedFraction } from "@/lib/problems/generators/fraction-problems"; import { generateDecimalCompareOrder, generateDecimalRounding, generateStandardForm, generateDecimalAddSubtract, generateDecimalMultiplyDivide, generateDecimalConversion } from "@/lib/problems/generators/decimal-problems"; import { generateSimplifyRatio, generateDivideInRatio, generateRatioWordProblem, generateDefineRatio, generateFractionsAndRatios } from "@/lib/problems/generators/ratio-problems"; import { generateIntegerAddSubtractMixed, generateIntegerMultiplyDivide, generateIntegerOrderCompare } from "@/lib/problems/generators/integer-problems"; import { generateDigitValue, generateBinaryToDenary, generateQuaternaryToDenary } from "@/lib/problems/generators/number-system-problems"; import { generateIdentityInverse, generateExponentEvaluate, generateDistributive } from "@/lib/problems/generators/number-properties-problems"; type UnitColor = Unit["color"]; type PracticeUnitColor = Exclude; type Generator = (difficulty: Difficulty) => MathProblem; /** * Practice for each curriculum topic. "lesson-only" topics (the coordinate grid) * need the interactive visual, so they link to their lesson instead of a * fill-in-the-answer generator. Keyed by `${unitSlug}/${topicSlug}`. */ const PRACTICE_BY_TOPIC: Record = { "unit-1-fractions/add-subtract": generateFractionAddSubtract, "unit-1-fractions/multiply": generateFractionMultiply, "unit-1-fractions/divide": generateFractionDivide, "unit-1-fractions/mixed-operations": generateFractionBodmas, "unit-1-fractions/fraction-of-quantity": generateFractionOfQuantity, "unit-1-fractions/whole-from-fractions": generateWholeFromFraction, "unit-2-decimals/compare-order": generateDecimalCompareOrder, "unit-2-decimals/approximate": generateDecimalRounding, "unit-2-decimals/standard-form": generateStandardForm, "unit-3-decimal-operations/convert": generateDecimalConversion, "unit-3-decimal-operations/add-subtract": generateDecimalAddSubtract, "unit-3-decimal-operations/multiply-divide": generateDecimalMultiplyDivide, "unit-4-ratio-proportion/define-ratio": generateDefineRatio, "unit-4-ratio-proportion/fractions-and-ratios": generateFractionsAndRatios, "unit-4-ratio-proportion/simplify-ratios": generateSimplifyRatio, "unit-4-ratio-proportion/divide-in-ratio": generateDivideInRatio, "unit-4-ratio-proportion/word-problems": generateRatioWordProblem, "unit-5-integers/order-compare": generateIntegerOrderCompare, "unit-5-integers/add-subtract": generateIntegerAddSubtractMixed, "unit-5-integers/multiply-divide": generateIntegerMultiplyDivide, "unit-5-integers/negative-fractions": generateSignedFraction, "unit-6-number-system/place-value": generateDigitValue, "unit-6-number-system/binary": generateBinaryToDenary, "unit-6-number-system/quaternary": generateQuaternaryToDenary, "unit-7-coordinates/plot-points": "lesson-only", "unit-7-coordinates/read-coordinates": "lesson-only", "unit-8-number-properties/identity-inverse": generateIdentityInverse, "unit-8-number-properties/number-laws": generateDistributive, "unit-8-number-properties/exponents": generateExponentEvaluate, }; function practiceFor(unit: Unit, topic: Topic): Generator | "lesson-only" { return PRACTICE_BY_TOPIC[`${unit.slug}/${topic.slug}`] ?? "lesson-only"; } interface UnitStyle { heading: string; dot: string; accent: string; iconBg: string; hover: string; activeItem: string; headingHover: string; } const UNIT_STYLE: Record = { "unit-1": { heading: "text-unit-1-dark", dot: "bg-unit-1", accent: "border-l-unit-1", iconBg: "bg-unit-1-light text-unit-1-dark", hover: "hover:border-unit-1/40", activeItem: "bg-unit-1-light text-unit-1-dark border-unit-1/20", headingHover: "hover:bg-unit-1-light/50" }, "unit-2": { heading: "text-unit-2-dark", dot: "bg-unit-2", accent: "border-l-unit-2", iconBg: "bg-unit-2-light text-unit-2-dark", hover: "hover:border-unit-2/40", activeItem: "bg-unit-2-light text-unit-2-dark border-unit-2/20", headingHover: "hover:bg-unit-2-light/50" }, "unit-3": { heading: "text-unit-3-dark", dot: "bg-unit-3", accent: "border-l-unit-3", iconBg: "bg-unit-3-light text-unit-3-dark", hover: "hover:border-unit-3/40", activeItem: "bg-unit-3-light text-unit-3-dark border-unit-3/20", headingHover: "hover:bg-unit-3-light/50" }, "unit-4": { heading: "text-unit-4-dark", dot: "bg-unit-4", accent: "border-l-unit-4", iconBg: "bg-unit-4-light text-unit-4-dark", hover: "hover:border-unit-4/40", activeItem: "bg-unit-4-light text-unit-4-dark border-unit-4/20", headingHover: "hover:bg-unit-4-light/50" }, "unit-5": { heading: "text-unit-5-dark", dot: "bg-unit-5", accent: "border-l-unit-5", iconBg: "bg-unit-5-light text-unit-5-dark", hover: "hover:border-unit-5/40", activeItem: "bg-unit-5-light text-unit-5-dark border-unit-5/20", headingHover: "hover:bg-unit-5-light/50" }, "unit-6": { heading: "text-unit-6-dark", dot: "bg-unit-6", accent: "border-l-unit-6", iconBg: "bg-unit-6-light text-unit-6-dark", hover: "hover:border-unit-6/40", activeItem: "bg-unit-6-light text-unit-6-dark border-unit-6/20", headingHover: "hover:bg-unit-6-light/50" }, "unit-7": { heading: "text-unit-7-dark", dot: "bg-unit-7", accent: "border-l-unit-7", iconBg: "bg-unit-7-light text-unit-7-dark", hover: "hover:border-unit-7/40", activeItem: "bg-unit-7-light text-unit-7-dark border-unit-7/20", headingHover: "hover:bg-unit-7-light/50" }, "unit-8": { heading: "text-unit-8-dark", dot: "bg-unit-8", accent: "border-l-unit-8", iconBg: "bg-unit-8-light text-unit-8-dark", hover: "hover:border-unit-8/40", activeItem: "bg-unit-8-light text-unit-8-dark border-unit-8/20", headingHover: "hover:bg-unit-8-light/50" }, }; interface Selection { unit: Unit; topic: Topic; } function PlayIcon({ className }: { className?: string }) { return ( ); } // ── Sidebar (mirrors the lessons sidebar) ──────────────────────────────────── function PracticeSidebar({ selected, onSelect, onAllTopics, mobileOpen, desktopCollapsed, }: { selected: Selection | null; onSelect: (s: Selection) => void; onAllTopics: () => void; mobileOpen: boolean; desktopCollapsed: boolean; }) { const [open, setOpen] = useState>(() => new Set([curriculum[0].number])); function toggle(num: number) { setOpen((prev) => { const next = new Set(prev); if (next.has(num)) next.delete(num); else next.add(num); return next; }); } return ( ); } // ── Topic browser (main area, all topics) ──────────────────────────────────── function TopicBrowser({ onSelect }: { onSelect: (s: Selection) => void }) { return (
{curriculum.map((unit) => { const style = UNIT_STYLE[unit.color]; return (

Unit {unit.number}: {unit.title}

{unit.topics.length}
{unit.topics.map((topic) => ( ))}
); })}
); } // ── Panel for topics that are practised in the interactive lesson ──────────── function LessonOnlyPanel({ unit, topic }: { unit: Unit; topic: Topic }) { return (

{topic.title}

This topic uses the interactive coordinate grid, so it's best practised right in the lesson.

); } // ── Page ───────────────────────────────────────────────────────────────────── export default function PracticePage() { const [selected, setSelected] = useState(null); const { mobileOpen, desktopCollapsed, toggle, closeMobile } = useCollapsibleSidebar(); function select(s: Selection) { setSelected(s); closeMobile(); } const generator = selected ? practiceFor(selected.unit, selected.topic) : null; return (
{ setSelected(null); closeMobile(); }} mobileOpen={mobileOpen} desktopCollapsed={desktopCollapsed} />
{!selected ? ( <>

Practice

Pick a topic and build your confidence with fresh questions each round.

) : ( <> {generator === "lesson-only" || generator === null ? ( ) : ( )} )}
); }