File name
Commit message
Commit date
08-14
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>
);
}