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
File name
Commit message
Commit date
'use client';
import { useRouter } from 'next/navigation';
import type { ChangeEvent } from 'react';
import { Button } from '@/components/ui/button';
import { Select } from '@/components/ui/select';
import {
STUDENT_MEMBERS_EXCEL_PATH,
STUDENT_MEMBER_PAGE_SIZE_OPTIONS,
STUDENT_MEMBER_SORT_OPTIONS,
buildStudentMemberHref,
type StudentMemberPageSize,
type StudentMemberQuery,
type StudentMemberSortOption,
} from '@/lib/domain/student-member-query';
interface StudentListToolbarProps {
query: StudentMemberQuery;
}
/**
* 목록 툴바 — 정렬/페이지 크기 select는 변경 즉시 URL을 갱신해 서버 데이터를 다시 조회하게
* 한다(select의 onChange가 필요해 이 컴포넌트만 최말단 클라이언트 경계로 분리했다). 두 값 모두
* 바뀌면 1페이지로 되돌린다(기존 페이지 번호가 새 정렬·크기 기준으로는 의미가 달라지므로).
* 엑셀다운로드는 이번 범위에서 버튼 배치만 하고 동작은 구현하지 않는다(사용자 지시) —
* disabled로 두어 클릭해도 아무 일도 일어나지 않게 한다.
*
* 정렬 select는 URL의 `sort`만 바꾸고, 그 값을 어떻게 만족시킬지는 Repository가 정한다 —
* 가입일순은 백엔드의 고정 순서와 같아 그대로 받아오고, 이름순은 백엔드에 정렬 파라미터가 없어
* 전체를 받아 서버에서 정렬한다. 화면은 그 차이를 알 필요가 없다.
*/
export function StudentListToolbar({ query }: StudentListToolbarProps) {
const router = useRouter();
function handleSortChange(event: ChangeEvent<HTMLSelectElement>) {
const sort = event.target.value as StudentMemberSortOption;
router.replace(buildStudentMemberHref(query, { sort, page: 1 }));
}
function handlePageSizeChange(event: ChangeEvent<HTMLSelectElement>) {
const pageSize = Number(event.target.value) as StudentMemberPageSize;
router.replace(buildStudentMemberHref(query, { pageSize, page: 1 }));
}
return (
<div className="flex flex-wrap items-center justify-between gap-3">
{/* 네이티브 GET 폼 제출 — 응답이 첨부파일(Content-Disposition: attachment)이라 브라우저가
현재 화면을 그대로 둔 채 파일만 내려받는다. 라우터 내비게이션(router.push)으로는
첨부파일 응답을 처리할 수 없고, Button은 <button>이라 링크로 쓸 수 없어 폼으로 감쌌다.
검색·페이징 값을 hidden으로 싣지 않는 것이 사양이다 — 파일은 항상 전체 데이터다. */}
<form action={STUDENT_MEMBERS_EXCEL_PATH} method="get">
<Button type="submit" variant="primary">
엑셀다운로드
</Button>
</form>
<div className="flex items-center gap-3">
<Select
name="sort"
aria-label="정렬"
defaultValue={query.sort}
onChange={handleSortChange}
>
{STUDENT_MEMBER_SORT_OPTIONS.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</Select>
<Select
name="pageSize"
aria-label="페이지 크기"
defaultValue={query.pageSize}
onChange={handlePageSizeChange}
>
{STUDENT_MEMBER_PAGE_SIZE_OPTIONS.map((size) => (
<option key={size} value={size}>
{size}개씩
</option>
))}
</Select>
</div>
</div>
);
}