- audit: update retention.ts, types.ts, audit-retention-settings.tsx - auth: update actions.ts and types.ts - course-plans: update actions.ts, course-plan-detail.tsx, template-picker-dialog.tsx, add lib/track-event.ts - announcements: update page.tsx, announcement-list.tsx, announcement-pagination.tsx - exams: update actions.ts
69 lines
2.3 KiB
TypeScript
69 lines
2.3 KiB
TypeScript
import type { Metadata } from "next"
|
||
import { getTranslations } from "next-intl/server"
|
||
|
||
import { requirePermission } from "@/shared/lib/auth-guard"
|
||
import { Permissions } from "@/shared/types/permissions"
|
||
import { getUserAnnouncementsPageData } from "@/modules/announcements/data-access"
|
||
import { AnnouncementList } from "@/modules/announcements/components/announcement-list"
|
||
import { AnnouncementsServiceProvider } from "@/modules/announcements/components/announcements-service-context"
|
||
|
||
export const dynamic = "force-dynamic"
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const t = await getTranslations("announcements")
|
||
return { title: t("title.list"), description: t("description.list") }
|
||
}
|
||
|
||
const PAGE_SIZE = 12
|
||
|
||
export default async function AnnouncementsPage({
|
||
searchParams,
|
||
}: {
|
||
searchParams: Promise<{ page?: string; status?: string }>
|
||
}) {
|
||
const t = await getTranslations("announcements")
|
||
const ctx = await requirePermission(Permissions.ANNOUNCEMENT_READ)
|
||
|
||
const sp = await searchParams
|
||
const requestedPage = Number(sp.page)
|
||
const page = Number.isFinite(requestedPage) && requestedPage > 0 ? Math.floor(requestedPage) : 1
|
||
|
||
const { items, total, page: currentPage, pageSize } = await getUserAnnouncementsPageData(
|
||
ctx.userId,
|
||
ctx.dataScope,
|
||
page,
|
||
PAGE_SIZE
|
||
)
|
||
|
||
// v3: 不再将 buildPageHref 函数传给 Client Component(Server Component 不能传函数)。
|
||
// 改为传 basePath + statusFilter,由 AnnouncementPagination 在客户端自行构建 URL。
|
||
const statusFilter = sp.status === "published" || sp.status === "draft" || sp.status === "archived"
|
||
? sp.status
|
||
: "all"
|
||
|
||
return (
|
||
<AnnouncementsServiceProvider>
|
||
<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>
|
||
<AnnouncementList
|
||
announcements={items}
|
||
detailHrefPrefix="/announcements"
|
||
initialStatus={statusFilter}
|
||
pagination={{
|
||
page: currentPage,
|
||
pageSize,
|
||
total,
|
||
basePath: "/announcements",
|
||
statusFilter,
|
||
}}
|
||
/>
|
||
</div>
|
||
</AnnouncementsServiceProvider>
|
||
)
|
||
}
|