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
This commit is contained in:
SpecialX
2026-07-03 10:26:25 +08:00
parent e9a5264fe7
commit 21142f9b99
280 changed files with 7137 additions and 1855 deletions

View File

@@ -10,6 +10,7 @@ import { AvatarUpload } from "@/modules/settings/components/avatar-upload"
import { ProfileStudentOverview, ProfileStudentOverviewSkeleton } from "@/modules/settings/components/profile-student-overview"
import { ProfileTeacherOverview, ProfileTeacherOverviewSkeleton } from "@/modules/settings/components/profile-teacher-overview"
import { SettingsSectionErrorBoundary } from "@/modules/settings/components/settings-section-error-boundary"
import { resolveProfileOverviewType } from "@/modules/settings/config/profile-overview-config"
import { Badge } from "@/shared/components/ui/badge"
import { Button } from "@/shared/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/shared/components/ui/card"
@@ -19,7 +20,7 @@ import { formatDate } from "@/shared/lib/utils"
export const dynamic = "force-dynamic"
export async function generateMetadata() {
const t = await getTranslations("settings.profilePage")
const t = await getTranslations("settings.profile.page")
return { title: t("title") }
}
@@ -34,9 +35,8 @@ export default async function ProfilePage(): Promise<ReactElement> {
}
const roles = ctx.roles
const isStudent = roles.includes("student")
const isTeacher = roles.includes("teacher")
const t = await getTranslations("settings.profilePage")
const overviewType = resolveProfileOverviewType(roles)
const t = await getTranslations("settings.profile.page")
return (
<div className="flex h-full flex-col gap-8 p-8">
@@ -50,11 +50,13 @@ export default async function ProfilePage(): Promise<ReactElement> {
}
/>
<AvatarUpload
currentImage={userProfile.image}
name={userProfile.name}
email={userProfile.email}
/>
<SettingsSectionErrorBoundary>
<AvatarUpload
currentImage={userProfile.image}
name={userProfile.name}
email={userProfile.email}
/>
</SettingsSectionErrorBoundary>
<div className="grid gap-6 md:grid-cols-2">
<Card>
@@ -139,7 +141,7 @@ export default async function ProfilePage(): Promise<ReactElement> {
</Card>
</div>
{isStudent ? (
{overviewType === "student" ? (
<SettingsSectionErrorBoundary>
<Suspense fallback={<ProfileStudentOverviewSkeleton />}>
<ProfileStudentOverview userId={userId} />
@@ -147,7 +149,7 @@ export default async function ProfilePage(): Promise<ReactElement> {
</SettingsSectionErrorBoundary>
) : null}
{isTeacher ? (
{overviewType === "teacher" ? (
<SettingsSectionErrorBoundary>
<Suspense fallback={<ProfileTeacherOverviewSkeleton />}>
<ProfileTeacherOverview />