feat(settings): 设置与个人信息模块审计重构 — i18n + 服务注入解耦 + Error Boundary + 流式渲染
- 新增 SettingsService 接口 + Context 注入,组件层不再直接 import users/messaging actions - 新增 resolveRoleSettingsConfig 配置驱动角色路由,删除 parent/student/teacher-settings-view 冗余文件 - 新增 SettingsSectionErrorBoundary,每个 TabsContent + profile 角色概览区块均包裹 - 新增 ProfileStudentOverview/ProfileTeacherOverview 异步 Server Component + 骨架屏,支持流式渲染 - 抽取 buildStudentOverviewData 等纯函数到 lib/student-overview-data.ts,便于单元测试 - 新增 settings.json 翻译文件(zh-CN + en),所有组件改用 useTranslations/getTranslations - 重构 profile/page.tsx:i18n 适配 + Suspense 分区加载 + 业务逻辑抽离 - 同步更新架构图 004/005
This commit is contained in:
93
src/modules/settings/components/profile-student-overview.tsx
Normal file
93
src/modules/settings/components/profile-student-overview.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import type { ReactElement } from "react"
|
||||
import { getTranslations } from "next-intl/server"
|
||||
|
||||
import { StudentGradesCard } from "@/modules/dashboard/components/student-dashboard/student-grades-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 { getStudentClasses, getStudentSchedule } from "@/modules/classes/data-access"
|
||||
import { getStudentDashboardGrades, getStudentHomeworkAssignments } from "@/modules/homework/data-access"
|
||||
import { buildStudentOverviewData } from "@/modules/settings/lib/student-overview-data"
|
||||
import { Separator } from "@/shared/components/ui/separator"
|
||||
|
||||
interface ProfileStudentOverviewProps {
|
||||
userId: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 学生概览区块(Server Component)
|
||||
*
|
||||
* 独立获取学生数据并渲染,可被 Suspense + ErrorBoundary 包裹实现流式渲染与局部容错。
|
||||
*/
|
||||
export async function ProfileStudentOverview({
|
||||
userId,
|
||||
}: ProfileStudentOverviewProps): Promise<ReactElement> {
|
||||
const t = await getTranslations("settings.profilePage.studentOverview")
|
||||
|
||||
const [classes, schedule, assignmentsAll, grades] = await Promise.all([
|
||||
getStudentClasses(userId),
|
||||
getStudentSchedule(userId),
|
||||
getStudentHomeworkAssignments(userId),
|
||||
getStudentDashboardGrades(userId),
|
||||
])
|
||||
|
||||
const data = buildStudentOverviewData({
|
||||
classes,
|
||||
schedule,
|
||||
assignments: assignmentsAll,
|
||||
grades,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<Separator />
|
||||
<div className="space-y-1">
|
||||
<h2 className="text-xl font-semibold tracking-tight">{t("title")}</h2>
|
||||
<div className="text-sm text-muted-foreground">{t("description")}</div>
|
||||
</div>
|
||||
|
||||
<StudentStatsGrid
|
||||
enrolledClassCount={data.enrolledClassCount}
|
||||
dueSoonCount={data.dueSoonCount}
|
||||
overdueCount={data.overdueCount}
|
||||
gradedCount={data.gradedCount}
|
||||
ranking={data.grades.ranking}
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
<StudentUpcomingAssignmentsCard upcomingAssignments={data.upcomingAssignments} />
|
||||
<StudentGradesCard grades={data.grades} />
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<StudentTodayScheduleCard items={data.todayScheduleItems} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 学生概览骨架屏
|
||||
*/
|
||||
export function ProfileStudentOverviewSkeleton(): ReactElement {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<Separator />
|
||||
<div className="space-y-2">
|
||||
<div className="h-6 w-40 animate-pulse rounded bg-muted" />
|
||||
<div className="h-4 w-64 animate-pulse rounded bg-muted" />
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
||||
{Array.from({ length: 4 }).map((_, i) => (
|
||||
<div key={i} className="h-24 animate-pulse rounded-lg bg-muted" />
|
||||
))}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div className="lg:col-span-2 h-64 animate-pulse rounded-lg bg-muted" />
|
||||
<div className="h-64 animate-pulse rounded-lg bg-muted" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user