Files
NextEdu/src/modules/dashboard/components/student-dashboard/student-today-schedule-card.tsx
SpecialX 138b6f1b00 feat(dashboard,diagnostic,elective): add widgets, layout, parent dashboard, role-config, services, elective components
dashboard:

- Add comparison-badge, dashboard-notification-widget, dashboard-responsive-layout, dashboard-time-range-filter

- Add parent-dashboard components directory

- Add config, hooks, and services directories

diagnostic:

- Add role-config and services directory

elective:

- Add elective-course-detail, elective-stats-cards, parent-selection-view components

- Add data-access-settings and data-access-stats
2026-07-03 10:25:46 +08:00

97 lines
3.3 KiB
TypeScript

"use client"
import { useMemo } from "react"
import Link from "next/link"
import { CalendarDays, CalendarX } from "lucide-react"
import { useTranslations } from "next-intl"
import { Button } from "@/shared/components/ui/button"
import { Badge } from "@/shared/components/ui/badge"
import { ScheduleList } from "@/shared/components/schedule/schedule-list"
import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
import { EmptyState } from "@/shared/components/ui/empty-state"
import { useCurrentTime } from "@/shared/hooks"
import { cn } from "@/shared/lib/utils"
import { timeToMinutes } from "@/modules/dashboard/lib/dashboard-utils"
import type { StudentTodayScheduleItem } from "@/modules/dashboard/types"
export function StudentTodayScheduleCard({ items }: { items: StudentTodayScheduleItem[] }) {
const t = useTranslations("dashboard")
const hasSchedule = items.length > 0
const now = useCurrentTime()
const { currentId, nextId } = useMemo(() => {
const nowMin = now.getHours() * 60 + now.getMinutes()
let currentId: string | null = null
let nextId: string | null = null
for (const item of items) {
const start = timeToMinutes(item.startTime)
const end = timeToMinutes(item.endTime)
if (nowMin >= start && nowMin < end) {
currentId = item.id
break
}
if (nowMin < start) {
nextId = item.id
break
}
}
return { currentId, nextId }
}, [items, now])
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle className="flex items-center gap-2">
<CalendarDays className="h-4 w-4 text-muted-foreground" />
{t("sections.todaySchedule")}
</CardTitle>
<Button asChild variant="outline" size="sm">
<Link href="/student/schedule">{t("quickActions.viewAll")}</Link>
</Button>
</CardHeader>
<CardContent>
{!hasSchedule ? (
<EmptyState
icon={CalendarX}
title={t("empty.noClassesToday")}
description={t("empty.noClassesTodayDesc")}
action={{ label: t("quickActions.viewSchedule"), href: "/student/schedule" }}
className="border-none h-72"
/>
) : (
<ScheduleList
items={items}
variant="separator"
spacingClassName="space-y-4"
renderTrailing={(item) => {
const isCurrent = item.id === currentId
const isNext = item.id === nextId
if (isCurrent) {
return (
<Badge className="shrink-0 bg-emerald-500 text-white hover:bg-emerald-500">
{t("badge.inProgress")}
</Badge>
)
}
if (isNext) {
return (
<Badge variant="outline" className="shrink-0 border-primary text-primary">
{t("badge.upNext")}
</Badge>
)
}
return item.className ? (
<Badge variant="secondary" className="shrink-0">
{item.className}
</Badge>
) : null
}}
className={cn(currentId && "[&_div:first-child]:bg-emerald-50/50")}
/>
)}
</CardContent>
</Card>
)
}