feat(classes): optimize teacher dashboard ui and implement grade management
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
import { BookOpen, CheckCircle2, PenTool, TriangleAlert } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { BookOpen, PenTool, TriangleAlert, Trophy, TrendingUp } from "lucide-react"
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
|
||||
import { cn } from "@/shared/lib/utils"
|
||||
import type { StudentRanking } from "@/modules/homework/types"
|
||||
|
||||
type Stat = {
|
||||
title: string
|
||||
value: string
|
||||
description: string
|
||||
icon: typeof BookOpen
|
||||
href: string
|
||||
color?: string
|
||||
}
|
||||
|
||||
export function StudentStatsGrid({
|
||||
@@ -14,52 +19,64 @@ export function StudentStatsGrid({
|
||||
dueSoonCount,
|
||||
overdueCount,
|
||||
gradedCount,
|
||||
ranking,
|
||||
}: {
|
||||
enrolledClassCount: number
|
||||
dueSoonCount: number
|
||||
overdueCount: number
|
||||
gradedCount: number
|
||||
ranking: StudentRanking | null
|
||||
}) {
|
||||
const stats: readonly Stat[] = [
|
||||
const stats: Stat[] = [
|
||||
{
|
||||
title: "My Classes",
|
||||
value: String(enrolledClassCount),
|
||||
description: "Enrolled classes",
|
||||
icon: BookOpen,
|
||||
title: "Average Score",
|
||||
value: ranking ? `${Math.round(ranking.percentage)}%` : "-",
|
||||
description: ranking ? "Overall performance" : "No grades yet",
|
||||
icon: TrendingUp,
|
||||
href: "/student/learning/assignments",
|
||||
color: "text-blue-500",
|
||||
},
|
||||
{
|
||||
title: "Class Rank",
|
||||
value: ranking ? `${ranking.rank}/${ranking.classSize}` : "-",
|
||||
description: ranking ? "Current position" : "No ranking yet",
|
||||
icon: Trophy,
|
||||
href: "/student/learning/assignments",
|
||||
color: "text-purple-500",
|
||||
},
|
||||
{
|
||||
title: "Due Soon",
|
||||
value: String(dueSoonCount),
|
||||
description: "Next 7 days",
|
||||
icon: PenTool,
|
||||
href: "/student/learning/assignments",
|
||||
color: dueSoonCount > 0 ? "text-orange-500" : undefined,
|
||||
},
|
||||
{
|
||||
title: "Overdue",
|
||||
value: String(overdueCount),
|
||||
description: "Needs attention",
|
||||
icon: TriangleAlert,
|
||||
},
|
||||
{
|
||||
title: "Graded",
|
||||
value: String(gradedCount),
|
||||
description: "With score",
|
||||
icon: CheckCircle2,
|
||||
href: "/student/learning/assignments",
|
||||
color: overdueCount > 0 ? "text-red-500" : undefined,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
||||
{stats.map((stat) => (
|
||||
<Card key={stat.title}>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">{stat.title}</CardTitle>
|
||||
<stat.icon className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold tabular-nums">{stat.value}</div>
|
||||
<div className="text-xs text-muted-foreground">{stat.description}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Link key={stat.title} href={stat.href}>
|
||||
<Card className="hover:bg-muted/50 transition-colors cursor-pointer h-full">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">{stat.title}</CardTitle>
|
||||
<stat.icon className={cn("h-4 w-4 text-muted-foreground", stat.color)} />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className={cn("text-2xl font-bold tabular-nums", stat.color)}>{stat.value}</div>
|
||||
<div className="text-xs text-muted-foreground">{stat.description}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user