File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
import type { Metadata } from 'next';
import Link from 'next/link';
import { Alert } from '@/components/ui/alert';
import { Pagination } from '@/components/ui/pagination';
import { verifySession } from '@/lib/auth/dal';
import { fetchStudentMembers } from '@/lib/data/repositories/student-member-repository';
import { buildStudentMemberHref, parseStudentMemberQuery } from '@/lib/domain/student-member-query';
import { StudentListToolbar } from './_components/student-list-toolbar';
import { StudentSearchBar } from './_components/student-search-bar';
import { StudentTable } from './_components/student-table';
export const metadata: Metadata = {
title: '학생 회원',
};
interface PageProps {
searchParams: Promise<Record<string, string | string[] | undefined>>;
}
export default async function Page({ searchParams }: PageProps) {
await verifySession();
const query = parseStudentMemberQuery(await searchParams);
const { items, totalCount, isTotalCountExact } =
await fetchStudentMembers(query);
// 전체 건수가 확정되지 않았다면(백엔드가 count를 주지 않아 하한값만 아는 상태) 다음 페이지를
// 한 칸 열어 둔다 — 열어 두지 않으면 가득 찬 페이지 뒤의 데이터에 접근할 방법이 없어진다.
const totalPages = isTotalCountExact
? Math.max(1, Math.ceil(totalCount / query.pageSize))
: query.page + 1;
const currentPage = Math.min(query.page, totalPages);
return (
<section className="flex flex-1 flex-col gap-6 p-8">
<h1 className="text-headline-sm text-foreground">학생 회원 목록</h1>
<StudentSearchBar query={query} />
<StudentListToolbar query={query} />
<p className="text-body-md text-foreground-muted">
총 {totalCount}명{isTotalCountExact ? '' : ' 이상'} | 현재페이지{' '}
{currentPage}
{isTotalCountExact ? `/${totalPages}` : ''}
</p>
{items.length === 0 ? (
<Alert
title="검색 결과가 없습니다."
actions={
<Link
href={buildStudentMemberHref(query, { keyword: '', page: 1 })}
className="bg-foreground px-4 py-2 text-background"
>
확인
</Link>
}
>
다른 검색어로 다시 시도해 주세요.
</Alert>
) : (
<>
{/* 표의 순번 기준은 요청 페이지(query.page)가 아니라 화면이 실제로 보여주는
페이지(currentPage)다 — 백엔드가 범위를 벗어난 페이지 요청을 clamp해서 응답하면
둘이 어긋나 "현재페이지 1/1"인데 순번은 31부터 시작하는 상태가 된다. */}
<StudentTable
items={items}
page={currentPage}
pageSize={query.pageSize}
/>
<Pagination
currentPage={currentPage}
totalPages={totalPages}
buildHref={(page: number) => buildStudentMemberHref(query, { page })}
/>
</>
)}
</section>
);
}