Files
NextEdu/src/app/(dashboard)/messages/page.tsx
SpecialX 21142f9b99 feat(app): add error/loading boundaries across all dashboard routes and new routes
- Add error.tsx and loading.tsx boundaries for admin, parent, student, teacher routes

- Add admin announcements edit, audit-logs overview, curriculum-map, invitation-codes, permissions, questions, roles routes

- Add admin elective detail and components, files, course-plans, users, scheduling boundaries

- Add messages group-compose route

- Add parent course-plans, elective, grades report-card, practice routes

- Add student course-plans, elective detail, error-book dialogs, grades report-card, learning study-path, leave, schedule boundaries

- Add teacher attendance report, classes boundaries, course-plans boundaries, elective, exams analytics/edit-rich/all/create/new, grades report-card, homework boundaries, leave, lesson-plans calendar

- Add auth loading, onboarding loading, api cron
2026-07-03 10:26:25 +08:00

81 lines
3.0 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 { Suspense } from "react"
import type { JSX } from "react"
import { getTranslations } from "next-intl/server"
import { requirePermission } from "@/shared/lib/auth-guard"
import { Permissions } from "@/shared/types/permissions"
import { SectionErrorBoundary } from "@/shared/components/section-error-boundary"
import { getNotifications } from "@/modules/notifications/data-access"
import { NotificationList } from "@/modules/notifications/components/notification-list"
import { MessageListSection } from "@/modules/messaging/components/message-list-section"
import { MessageListSkeleton } from "@/modules/messaging/components/message-list-skeleton"
import { Card, CardContent, CardHeader } from "@/shared/components/ui/card"
import { Skeleton } from "@/shared/components/ui/skeleton"
export const dynamic = "force-dynamic"
export async function generateMetadata() {
const t = await getTranslations("messages")
return { title: t("title.list") }
}
/**
* P2-9: 通知列表区块骨架屏Suspense fallback
*/
function NotificationListSkeleton(): JSX.Element {
return (
<div className="space-y-4" role="status" aria-label="Loading notifications">
<Skeleton className="h-10 w-48" />
{Array.from({ length: 3 }).map((_, i) => (
<Card key={i} aria-hidden="true">
<CardHeader className="space-y-2 pb-3">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-3 w-1/2" />
</CardHeader>
<CardContent className="pt-0">
<Skeleton className="h-3 w-full" />
</CardContent>
</Card>
))}
</div>
)
}
/**
* P2-9: 通知列表区块Server Component流式加载
*/
async function NotificationListSection({ userId }: { userId: string }): Promise<JSX.Element> {
const result = await getNotifications(userId, { page: 1, pageSize: 20 })
return <NotificationList notifications={result.items} />
}
export default async function MessagesPage(): Promise<JSX.Element> {
const t = await getTranslations("messages")
const ctx = await requirePermission(Permissions.MESSAGE_READ)
return (
<div className="flex h-full flex-col space-y-8 p-8">
<div>
<h2 className="text-2xl font-bold tracking-tight">{t("title.list")}</h2>
<p className="text-muted-foreground">
{t("description.list")}
</p>
</div>
{/* P2-8 + P2-9: 消息列表区块独立 Suspense + ErrorBoundary局部失败不影响通知区块 */}
<Suspense fallback={<MessageListSkeleton />}>
<SectionErrorBoundary namespace="messages">
<MessageListSection userId={ctx.userId} canGroupSend={ctx.dataScope.type === "class_taught"} />
</SectionErrorBoundary>
</Suspense>
{/* P2-8 + P2-9: 通知列表区块独立 Suspense + ErrorBoundary */}
<Suspense fallback={<NotificationListSkeleton />}>
<SectionErrorBoundary namespace="notifications">
<NotificationListSection userId={ctx.userId} />
</SectionErrorBoundary>
</Suspense>
</div>
)
}