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>; } 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 (

학생 회원 목록

총 {totalCount}명{isTotalCountExact ? '' : ' 이상'} | 현재페이지{' '} {currentPage} {isTotalCountExact ? `/${totalPages}` : ''}

{items.length === 0 ? ( 확인 } > 다른 검색어로 다시 시도해 주세요. ) : ( <> {/* 표의 순번 기준은 요청 페이지(query.page)가 아니라 화면이 실제로 보여주는 페이지(currentPage)다 — 백엔드가 범위를 벗어난 페이지 요청을 clamp해서 응답하면 둘이 어긋나 "현재페이지 1/1"인데 순번은 31부터 시작하는 상태가 된다. */} buildStudentMemberHref(query, { page })} /> )}
); }