feat(classes): optimize teacher dashboard ui and implement grade management
This commit is contained in:
@@ -4,14 +4,16 @@ import { redirect } from "next/navigation"
|
||||
import { auth } from "@/auth"
|
||||
import { getStudentClasses, getStudentSchedule } from "@/modules/classes/data-access"
|
||||
import { StudentGradesCard } from "@/modules/dashboard/components/student-dashboard/student-grades-card"
|
||||
import { StudentRankingCard } from "@/modules/dashboard/components/student-dashboard/student-ranking-card"
|
||||
import { StudentStatsGrid } from "@/modules/dashboard/components/student-dashboard/student-stats-grid"
|
||||
import { StudentTodayScheduleCard } from "@/modules/dashboard/components/student-dashboard/student-today-schedule-card"
|
||||
import { StudentUpcomingAssignmentsCard } from "@/modules/dashboard/components/student-dashboard/student-upcoming-assignments-card"
|
||||
import { getStudentDashboardGrades, getStudentHomeworkAssignments } from "@/modules/homework/data-access"
|
||||
import { getUserProfile } from "@/modules/users/data-access"
|
||||
import { Badge } from "@/shared/components/ui/badge"
|
||||
import { Button } from "@/shared/components/ui/button"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/shared/components/ui/card"
|
||||
import { Separator } from "@/shared/components/ui/separator"
|
||||
import { User, Mail, Phone, MapPin, Calendar, Clock, Shield } from "lucide-react"
|
||||
|
||||
export const dynamic = "force-dynamic"
|
||||
|
||||
@@ -20,17 +22,31 @@ const toWeekday = (d: Date): 1 | 2 | 3 | 4 | 5 | 6 | 7 => {
|
||||
return (day === 0 ? 7 : day) as 1 | 2 | 3 | 4 | 5 | 6 | 7
|
||||
}
|
||||
|
||||
const formatDate = (date: Date | null) => {
|
||||
if (!date) return "-"
|
||||
return new Intl.DateTimeFormat("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
}).format(date)
|
||||
}
|
||||
|
||||
export default async function ProfilePage() {
|
||||
const session = await auth()
|
||||
if (!session?.user) redirect("/login")
|
||||
|
||||
const name = session.user.name ?? "User"
|
||||
const email = session.user.email ?? "-"
|
||||
const role = String(session.user.role ?? "teacher")
|
||||
const userId = String(session.user.id ?? "").trim()
|
||||
const userProfile = await getUserProfile(userId)
|
||||
|
||||
if (!userProfile) {
|
||||
redirect("/login")
|
||||
}
|
||||
|
||||
const role = userProfile.role || "student"
|
||||
const isStudent = role === "student"
|
||||
|
||||
const studentData =
|
||||
role === "student" && userId
|
||||
isStudent
|
||||
? await (async () => {
|
||||
const [classes, schedule, assignmentsAll, grades] = await Promise.all([
|
||||
getStudentClasses(userId),
|
||||
@@ -96,36 +112,104 @@ export default async function ProfilePage() {
|
||||
<div className="flex flex-col justify-between gap-4 md:flex-row md:items-center">
|
||||
<div className="space-y-1">
|
||||
<h1 className="text-3xl font-bold tracking-tight">Profile</h1>
|
||||
<div className="text-sm text-muted-foreground">Your account information.</div>
|
||||
<div className="text-sm text-muted-foreground">Manage your personal and account information.</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button asChild variant="outline">
|
||||
<Link href="/settings">Open settings</Link>
|
||||
<Link href="/settings">Edit Profile</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Account</CardTitle>
|
||||
<CardDescription>Signed-in user details from session.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<div className="text-sm font-medium">{name}</div>
|
||||
<Badge variant="secondary" className="capitalize">
|
||||
{role}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">{email}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<div className="grid gap-6 md:grid-cols-2">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<User className="h-5 w-5" />
|
||||
Personal Information
|
||||
</CardTitle>
|
||||
<CardDescription>Basic personal details.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Full Name</div>
|
||||
<div className="text-sm font-medium">{userProfile.name ?? "-"}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Gender</div>
|
||||
<div className="text-sm capitalize">{userProfile.gender ?? "-"}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Age</div>
|
||||
<div className="text-sm">{userProfile.age ?? "-"}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Phone</div>
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
{userProfile.phone ? <Phone className="h-3 w-3 text-muted-foreground" /> : null}
|
||||
{userProfile.phone ?? "-"}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-1 sm:col-span-2 space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Address</div>
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
{userProfile.address ? <MapPin className="h-3 w-3 text-muted-foreground" /> : null}
|
||||
{userProfile.address ?? "-"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Shield className="h-5 w-5" />
|
||||
Account Information
|
||||
</CardTitle>
|
||||
<CardDescription>System account details.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<div className="col-span-1 sm:col-span-2 space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Email</div>
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Mail className="h-3 w-3 text-muted-foreground" />
|
||||
{userProfile.email}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Role</div>
|
||||
<Badge variant="secondary" className="capitalize">
|
||||
{userProfile.role}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Member Since</div>
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Calendar className="h-3 w-3 text-muted-foreground" />
|
||||
{formatDate(userProfile.createdAt)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-muted-foreground">Onboarded At</div>
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Clock className="h-3 w-3 text-muted-foreground" />
|
||||
{formatDate(userProfile.onboardedAt)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{studentData ? (
|
||||
<div className="space-y-6">
|
||||
<Separator />
|
||||
<div className="space-y-1">
|
||||
<h2 className="text-xl font-semibold tracking-tight">Student</h2>
|
||||
<div className="text-sm text-muted-foreground">Your learning overview.</div>
|
||||
<h2 className="text-xl font-semibold tracking-tight">Student Overview</h2>
|
||||
<div className="text-sm text-muted-foreground">Your academic performance and schedule.</div>
|
||||
</div>
|
||||
|
||||
<StudentStatsGrid
|
||||
@@ -133,16 +217,17 @@ export default async function ProfilePage() {
|
||||
dueSoonCount={studentData.dueSoonCount}
|
||||
overdueCount={studentData.overdueCount}
|
||||
gradedCount={studentData.gradedCount}
|
||||
ranking={studentData.grades.ranking}
|
||||
/>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<StudentGradesCard grades={studentData.grades} />
|
||||
<StudentRankingCard ranking={studentData.grades.ranking} />
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-7">
|
||||
<StudentTodayScheduleCard items={studentData.todayScheduleItems} />
|
||||
<StudentUpcomingAssignmentsCard upcomingAssignments={studentData.upcomingAssignments} />
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
<StudentUpcomingAssignmentsCard upcomingAssignments={studentData.upcomingAssignments} />
|
||||
<StudentGradesCard grades={studentData.grades} />
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<StudentTodayScheduleCard items={studentData.todayScheduleItems} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user