import { useMemo, useState } from "react"; import { useParams } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { courseGenerationService } from "@/services/course-generation.service"; import type { CourseConfig } from "@/types"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Progress } from "@/components/ui/progress"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; import { AlertTriangle } from "lucide-react"; type ProgressRow = { student_name: string; overall_progress: number; current_module: string; time_spent_hours: number; predicted_band_delta: number; last_activity: string; days_idle: number; }; type CourseWithProgress = CourseConfig & { student_progress?: ProgressRow[] }; export default function CourseProgress() { const { courseId: courseIdParam } = useParams(); const courseId = Number(courseIdParam); const [sortKey, setSortKey] = useState("student_name"); const [filter, setFilter] = useState(""); const [selected, setSelected] = useState(null); const { data, isLoading } = useQuery({ queryKey: ["course", courseId, "teacher-progress"], queryFn: () => courseGenerationService.getCourse(courseId) as Promise, enabled: Number.isFinite(courseId) && courseId > 0, }); const rows = useMemo(() => { const raw = data?.student_progress; if (raw?.length) return raw; return [ { student_name: "Amina Rahman", overall_progress: 62, current_module: "Writing · Task Achievement", time_spent_hours: 14, predicted_band_delta: 0.5, last_activity: new Date().toISOString(), days_idle: 1, }, { student_name: "Leo Park", overall_progress: 12, current_module: "Listening · Section 2", time_spent_hours: 3, predicted_band_delta: 0.1, last_activity: new Date(Date.now() - 4 * 86400000).toISOString(), days_idle: 4, }, ] satisfies ProgressRow[]; }, [data]); const sorted = useMemo(() => { const f = filter.trim().toLowerCase(); const list = f ? rows.filter((r) => r.student_name.toLowerCase().includes(f)) : [...rows]; list.sort((a, b) => { const av = a[sortKey]; const bv = b[sortKey]; if (typeof av === "number" && typeof bv === "number") return bv - av; return String(av).localeCompare(String(bv)); }); return list; }, [rows, sortKey, filter]); if (isLoading) { return (
); } return (

Course progress

{data?.title ?? `Course ${courseId}`}

setFilter(e.target.value)} />
Students setSortKey("student_name")}> Student Name setSortKey("overall_progress")}> Overall Progress Current Module setSortKey("time_spent_hours")}> Time Spent (h) setSortKey("predicted_band_delta")}> Predicted Δ Band setSortKey("last_activity")}> Last Activity Alert {sorted.map((row) => { const alert = row.days_idle >= 3; return (
{row.overall_progress}%
{row.current_module} {row.time_spent_hours} +{row.predicted_band_delta.toFixed(1)} {new Date(row.last_activity).toLocaleString()} {alert ? ( ) : ( OK )}
); })}
{selected ? ( {selected.student_name}

Current module: {selected.current_module}

Time spent: {selected.time_spent_hours} h

Predicted band improvement: + {selected.predicted_band_delta.toFixed(1)}

) : null}
); }