"use client" import Link from "next/link" import { memo, useState, useTransition } from "react" import { useRouter } from "next/navigation" import { toast } from "sonner" import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from "@/shared/components/ui/card" import { Badge } from "@/shared/components/ui/badge" import { Button } from "@/shared/components/ui/button" import { EmptyState } from "@/shared/components/ui/empty-state" import { Input } from "@/shared/components/ui/input" import { Label } from "@/shared/components/ui/label" import { BookOpen, Building2, Inbox, CalendarDays, User, PlusCircle, PenTool, Mail, School } from "lucide-react" import type { StudentEnrolledClass } from "@/modules/classes/types" import { joinClassByInvitationCodeAction } from "@/modules/classes/actions" const ClassCard = memo(function ClassCard({ c }: { c: StudentEnrolledClass }) { return (
{c.name} Grade {c.grade} {c.homeroom && ( <> {c.homeroom} )}
Active
{c.schoolName && (
{c.schoolName}
)} {c.teacherName && (
{c.teacherName}
)} {c.teacherEmail && (
{c.teacherEmail}
)} {c.room && (
Room {c.room}
)}
) }) export function StudentCoursesView({ classes, }: { classes: StudentEnrolledClass[] }) { const router = useRouter() const [code, setCode] = useState("") const [isPending, startTransition] = useTransition() const handleJoin = async (formData: FormData) => { startTransition(async () => { try { const res = await joinClassByInvitationCodeAction(null, formData) if (res.success) { toast.success(res.message || "Joined class") setCode("") router.refresh() } else { toast.error(res.message || "Failed to join class") } } catch (err) { console.error("[joinClass] failed:", err) toast.error("Failed to join class") } }) } return (
{classes.length > 0 && (
{classes.map((c) => ( ))}
)} {classes.length === 0 && ( )} {/* 加入班级表单:无课程时置顶,有课程时置底 */}

Join a Class

Enter the invitation code provided by your teacher to enroll.

setCode(e.target.value)} maxLength={6} pattern="\d{6}" className="max-w-md font-mono tracking-widest" required />
) }