Files
NextEdu/src/app/(dashboard)/settings/page.tsx
SpecialX 5d42495480 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
2026-06-22 16:15:36 +08:00

90 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { redirect } from "next/navigation"
import { getTranslations } from "next-intl/server"
import { requireAuth } from "@/shared/lib/auth-guard"
import { SettingsView } from "@/modules/settings/components/settings-view"
import { SettingsServiceProvider } from "@/modules/settings/components/settings-service-context"
import { resolveRoleSettingsConfig } from "@/modules/settings/config/role-settings-config"
import type { SettingsService } from "@/modules/settings/types"
import { getUserProfile } from "@/modules/users/data-access"
import { updateUserProfile } from "@/modules/users/actions"
import { getNotificationPreferences } from "@/modules/notifications/preferences"
import { updateNotificationPreferencesAction } from "@/modules/messaging/actions"
import type { UpdateNotificationPreferencesInput } from "@/modules/notifications/types"
export const dynamic = "force-dynamic"
export const metadata = {
title: "Settings",
}
/**
* 将通知偏好输入对象转换为 FormData适配 updateNotificationPreferencesAction 的签名。
* Action 内部通过 formData.get(key) === "on" 解析布尔值。
*/
function buildNotificationFormData(input: UpdateNotificationPreferencesInput): FormData {
const formData = new FormData()
const booleanFields: Array<keyof UpdateNotificationPreferencesInput> = [
"emailEnabled",
"smsEnabled",
"pushEnabled",
"homeworkNotifications",
"gradeNotifications",
"announcementNotifications",
"messageNotifications",
"attendanceNotifications",
"quietHoursEnabled",
]
for (const field of booleanFields) {
const value = input[field]
if (value === true) formData.set(field, "on")
}
if (input.quietHoursStart) formData.set("quietHoursStart", input.quietHoursStart)
if (input.quietHoursEnd) formData.set("quietHoursEnd", input.quietHoursEnd)
return formData
}
export default async function SettingsPage() {
const ctx = await requireAuth()
const userId = ctx.userId
const userProfile = await getUserProfile(userId)
if (!userProfile) redirect("/login")
const roles = ctx.roles
const notificationPrefs = await getNotificationPreferences(userId)
const t = await getTranslations("settings")
const config = resolveRoleSettingsConfig(roles)
const description = t(config?.descriptionKey ?? "title")
const backHref = config?.backHref ?? "/dashboard"
const generalExtra = config?.generalExtra
// 构建 SettingsService 实现,注入到 SettingsServiceProvider
// 组件层通过 useSettingsService() 消费,不直接 import users/messaging actions
const service: SettingsService = {
profile: {
getProfile: async () => getUserProfile(userId),
updateProfile: async (input) => updateUserProfile(input),
},
notifications: {
getPreferences: async () => getNotificationPreferences(userId),
updatePreferences: async (input) =>
updateNotificationPreferencesAction(null, buildNotificationFormData(input)),
},
}
return (
<SettingsServiceProvider service={service}>
<SettingsView
description={description}
backHref={backHref}
user={userProfile}
notificationPreferences={notificationPrefs}
generalExtra={generalExtra}
/>
</SettingsServiceProvider>
)
}