"use client" import { useEffect, useState } from "react" import { Card, CardContent } from "@/components/ui/card" import { Check, RefreshCw } from "lucide-react" import Link from "next/link" import { useActiveUser } from "@/hooks/useActiveUser" export function StudyPlanCard() { const [tasks, setTasks] = useState([]) const [loading, setLoading] = useState(true) const { userId, loading: userLoading } = useActiveUser(); useEffect(() => { if (userLoading || !userId) return; async function fetchPlan() { try { const res = await fetch(`/api/ai-coach/study-plan/today?user_id=${userId}`) if (!res.ok) { // If no plan is generated yet, fallback to mock silently throw new Error("silent_fallback") } const data = await res.json() setTasks(data.tasks || []) } catch (err: any) { if (err.message !== "silent_fallback") { console.error("Study plan fetch error:", err) } // Mock fallback if celery hasn't seeded yet setTasks([ { type: "DPS", description: "DPS — Electrostatics + Kinematics", duration_minutes: 20, status: "Done" }, { type: "Mistake_Review", description: "Mistake Review — Thermodynamics", duration_minutes: 10, status: "Done" }, { type: "Micro_test", description: "Micro-test — GOC (General Organic Chemistry)", duration_minutes: 5, status: "Pending" }, { type: "Test", description: "Weekly Test — Full Syllabus", duration_minutes: 180, status: "Pending" }, { type: "Revision", description: "Revise — Circles + Straight Lines", duration_minutes: 15, status: "Pending" } ]) } finally { setLoading(false) } } fetchPlan() }, [userId, userLoading]) const toggleTask = (idx: number, newStatus: string) => { setTasks(prev => { const copy = [...prev] copy[idx] = { ...copy[idx], status: newStatus } return copy }) } const completedTasks = tasks.filter(t => t.status === "Done").length const totalTasks = tasks.length const progressPercent = totalTasks === 0 ? 0 : Math.round((completedTasks / totalTasks) * 100) const getTagStyle = (type: string) => { switch(type) { case "Revision": return "bg-yellow-500/10 text-yellow-500" case "Mistake_Review": return "bg-red-500/10 text-red-500" case "DPS": return "bg-[#00F0FF]/10 text-[#00F0FF]" case "Micro_test": return "bg-green-500/10 text-green-500" case "Test": return "bg-purple-500/10 text-purple-500" default: return "bg-secondary text-muted-foreground" } } const getDisplayType = (type: string) => { switch(type) { case "Revision": return "Revision" case "Mistake_Review": return "Review" case "DPS": return "Practice" case "Micro_test": return "Micro-test" case "Test": return "Test" default: return "Task" } } return (

📅 Today's Study Plan

{new Date().toLocaleDateString('en-US', { weekday: 'long', day: 'numeric', month: 'short' })}
{progressPercent}% Completed
{/* Progress bar */}
{loading ? (
Loading schedule...
) : (
{tasks.map((task, idx) => { const isDone = task.status === "Done" const isCurrent = idx === completedTasks && !isDone // First pending task is current return (
toggleTask(idx, isDone ? "Pending" : "Done")} className={`flex items-center gap-3 px-4 py-2.5 transition-colors cursor-pointer border-l-[3px] ${ isDone ? "opacity-60 border-green-500 hover:bg-white/5" : isCurrent ? "border-[#00F0FF] bg-[#00F0FF]/5 hover:bg-[#00F0FF]/10" : "border-transparent hover:bg-white/5" }`} > {/* Custom Checkbox */}
{isDone && }
{task.description}
{task.type.replace('_', ' ')} • Active Session
{getDisplayType(task.type)}
{task.duration_minutes}m
) })}
)}