summaryrefslogtreecommitdiff
path: root/components/data-table/data-table-pagination.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-06-01 13:52:21 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-06-01 13:52:21 +0000
commitbac0228d21b7195065e9cddcc327ae33659c7bcc (patch)
tree8f3016ae4533c8706d0c00a605d9b1d41968c2bc /components/data-table/data-table-pagination.tsx
parent2fdce8d7a57c792bba0ac36fa554dca9c9cc31e3 (diff)
(대표님) 20250601까지 작업사항
Diffstat (limited to 'components/data-table/data-table-pagination.tsx')
-rw-r--r--components/data-table/data-table-pagination.tsx219
1 files changed, 70 insertions, 149 deletions
diff --git a/components/data-table/data-table-pagination.tsx b/components/data-table/data-table-pagination.tsx
index 922dacf1..4ed63a1b 100644
--- a/components/data-table/data-table-pagination.tsx
+++ b/components/data-table/data-table-pagination.tsx
@@ -7,7 +7,6 @@ import {
ChevronRight,
ChevronsLeft,
ChevronsRight,
- Infinity,
} from "lucide-react"
import { Button } from "@/components/ui/button"
@@ -22,99 +21,57 @@ import {
interface DataTablePaginationProps<TData> {
table: Table<TData>
pageSizeOptions?: Array<number | "All">
- // 무한 스크롤 관련 props
- infiniteScroll?: {
- enabled: boolean
- hasNextPage: boolean
- isLoadingMore: boolean
- totalCount?: number | null
- onLoadMore?: () => void
- }
- // 페이지 크기 변경 콜백 (필수!)
- onPageSizeChange?: (pageSize: number) => void
}
export function DataTablePagination<TData>({
table,
pageSizeOptions = [10, 20, 30, 40, 50, "All"],
- infiniteScroll,
- onPageSizeChange,
}: DataTablePaginationProps<TData>) {
// 현재 테이블 pageSize
const currentPageSize = table.getState().pagination.pageSize
- const isInfiniteMode = infiniteScroll?.enabled || currentPageSize >= 1_000_000
- // "All"을 1,000,000으로 처리하고, 무한 스크롤 모드 표시
- const selectValue = isInfiniteMode ? "All" : String(currentPageSize)
-
- const handlePageSizeChange = (value: string) => {
- if (!onPageSizeChange) {
- console.warn('DataTablePagination: onPageSizeChange prop is required for page size changes to work')
- return
- }
-
- if (value === "All") {
- // "All" 선택 시 무한 스크롤 모드로 전환
- onPageSizeChange(1_000_000) // URL 상태 업데이트만 수행
- } else {
- const newSize = Number(value)
- onPageSizeChange(newSize) // URL 상태 업데이트만 수행
- }
-
- // table.setPageSize()는 호출하지 않음!
- // URL 상태 변경이 테이블 상태로 자동 반영됨
- }
+ // "All"을 1,000,000으로 처리할 것이므로,
+ // 만약 현재 pageSize가 1,000,000이면 화면상 "All"로 표시
+ const selectValue =
+ currentPageSize === 1_000_000
+ ? "All"
+ : String(currentPageSize)
return (
<div className="flex w-full flex-col-reverse items-center justify-between gap-4 overflow-auto p-1 sm:flex-row sm:gap-8">
- {/* 선택된 행 및 총 개수 정보 */}
<div className="flex-1 whitespace-nowrap text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
- {isInfiniteMode ? (
- // 무한 스크롤 모드일 때
- <>
- {table.getRowModel().rows.length} row(s) selected.
- {infiniteScroll?.totalCount !== null && (
- <span className="ml-4">
- Total: {infiniteScroll.totalCount?.toLocaleString()} records
- <span className="ml-2 text-xs">
- ({table.getRowModel().rows.length.toLocaleString()} loaded)
- </span>
- </span>
- )}
- </>
- ) : (
- // 페이지네이션 모드일 때
- <>
- {table.getFilteredRowModel().rows.length} row(s) selected.
- <span className="ml-4">Total: {table.getRowCount()} records</span>
- </>
- )}
+ {table.getFilteredRowModel().rows.length} row(s) selected.
+ <span className="ml-4">Total: {table.getRowCount()} records</span>
</div>
-
<div className="flex flex-col-reverse items-center gap-4 sm:flex-row sm:gap-6 lg:gap-8">
{/* Rows per page Select */}
<div className="flex items-center space-x-2">
- <p className="whitespace-nowrap text-sm font-medium">
- {isInfiniteMode ? "View mode" : "Rows per page"}
- </p>
- <Select value={selectValue} onValueChange={handlePageSizeChange}>
+ <p className="whitespace-nowrap text-sm font-medium">Rows per page</p>
+ <Select
+ value={selectValue}
+ onValueChange={(value) => {
+ if (value === "All") {
+ // "All"을 1,000,000으로 치환
+ table.setPageSize(1_000_000)
+ } else {
+ table.setPageSize(Number(value))
+ }
+ }}
+ >
<SelectTrigger className="h-8 w-[4.5rem]">
<SelectValue placeholder={selectValue} />
</SelectTrigger>
<SelectContent side="top">
{pageSizeOptions.map((option) => {
+ // 화면에 표시할 라벨
const label = option === "All" ? "All" : String(option)
+ // value도 문자열화
const val = option === "All" ? "All" : String(option)
return (
<SelectItem key={val} value={val}>
- <div className="flex items-center space-x-2">
- {option === "All" && (
- <Infinity className="h-3 w-3 text-muted-foreground" />
- )}
- <span>{label}</span>
- </div>
+ {label}
</SelectItem>
)
})}
@@ -122,90 +79,54 @@ export function DataTablePagination<TData>({
</Select>
</div>
- {/* 페이지네이션 모드일 때만 페이지 정보 표시 */}
- {!isInfiniteMode && (
- <>
- {/* 현재 페이지 / 전체 페이지 */}
- <div className="flex items-center justify-center text-sm font-medium">
- Page {table.getState().pagination.pageIndex + 1} of{" "}
- {table.getPageCount()}
- </div>
-
- {/* 페이지 이동 버튼 */}
- <div className="flex items-center space-x-2">
- <Button
- aria-label="Go to first page"
- variant="outline"
- className="hidden size-8 p-0 lg:flex"
- onClick={() => table.setPageIndex(0)}
- disabled={!table.getCanPreviousPage()}
- >
- <ChevronsLeft className="size-4" aria-hidden="true" />
- </Button>
- <Button
- aria-label="Go to previous page"
- variant="outline"
- size="icon"
- className="size-8"
- onClick={() => table.previousPage()}
- disabled={!table.getCanPreviousPage()}
- >
- <ChevronLeft className="size-4" aria-hidden="true" />
- </Button>
- <Button
- aria-label="Go to next page"
- variant="outline"
- size="icon"
- className="size-8"
- onClick={() => table.nextPage()}
- disabled={!table.getCanNextPage()}
- >
- <ChevronRight className="size-4" aria-hidden="true" />
- </Button>
- <Button
- aria-label="Go to last page"
- variant="outline"
- size="icon"
- className="hidden size-8 lg:flex"
- onClick={() => table.setPageIndex(table.getPageCount() - 1)}
- disabled={!table.getCanNextPage()}
- >
- <ChevronsRight className="size-4" aria-hidden="true" />
- </Button>
- </div>
- </>
- )}
+ {/* 현재 페이지 / 전체 페이지 */}
+ <div className="flex items-center justify-center text-sm font-medium">
+ Page {table.getState().pagination.pageIndex + 1} of{" "}
+ {table.getPageCount()}
+ </div>
- {/* 무한 스크롤 모드일 때 로드 더 버튼 */}
- {isInfiniteMode && infiniteScroll && (
- <div className="flex items-center space-x-2">
- {infiniteScroll.hasNextPage && (
- <Button
- variant="outline"
- size="sm"
- onClick={infiniteScroll.onLoadMore}
- disabled={infiniteScroll.isLoadingMore}
- >
- {infiniteScroll.isLoadingMore ? (
- <>
- <div className="mr-2 h-3 w-3 animate-spin rounded-full border-2 border-current border-t-transparent" />
- Loading...
- </>
- ) : (
- <>
- <ChevronRight className="mr-2 h-3 w-3" />
- Load More
- </>
- )}
- </Button>
- )}
- {!infiniteScroll.hasNextPage && table.getRowModel().rows.length > 0 && (
- <span className="text-xs text-muted-foreground">
- All data loaded
- </span>
- )}
- </div>
- )}
+ {/* 페이지 이동 버튼 */}
+ <div className="flex items-center space-x-2">
+ <Button
+ aria-label="Go to first page"
+ variant="outline"
+ className="hidden size-8 p-0 lg:flex"
+ onClick={() => table.setPageIndex(0)}
+ disabled={!table.getCanPreviousPage()}
+ >
+ <ChevronsLeft className="size-4" aria-hidden="true" />
+ </Button>
+ <Button
+ aria-label="Go to previous page"
+ variant="outline"
+ size="icon"
+ className="size-8"
+ onClick={() => table.previousPage()}
+ disabled={!table.getCanPreviousPage()}
+ >
+ <ChevronLeft className="size-4" aria-hidden="true" />
+ </Button>
+ <Button
+ aria-label="Go to next page"
+ variant="outline"
+ size="icon"
+ className="size-8"
+ onClick={() => table.nextPage()}
+ disabled={!table.getCanNextPage()}
+ >
+ <ChevronRight className="size-4" aria-hidden="true" />
+ </Button>
+ <Button
+ aria-label="Go to last page"
+ variant="outline"
+ size="icon"
+ className="hidden size-8 lg:flex"
+ onClick={() => table.setPageIndex(table.getPageCount() - 1)}
+ disabled={!table.getCanNextPage()}
+ >
+ <ChevronsRight className="size-4" aria-hidden="true" />
+ </Button>
+ </div>
</div>
</div>
)