@@ -10,195 +10,400 @@ import {
ColumnDef ,
SortingState ,
ColumnFiltersState ,
FilterFn ,
} from '@tanstack/react-table' ;
import { rankItem } from '@tanstack/match-sorter-util s';
import { IconImageFile , IconVideoFile , IconAudioFile , IconEye , IconDownload , IconShield , DoubleArrowRight , ArrowRight , DoubleArrowLeft , ArrowLeft , ArrowUp , ArrowDown , Filter } from '@/app/ui/icons/icon s';
import { useTranslations } from 'next-intl' ;
import DropDownList from '@/app/components/dropDownList' ;
// Типы данных
type Person = {
type FileType = 'image' | 'video' | 'audio' ;
type FileItem = {
id : number ;
name : string ;
age : number ;
email : string ;
department : string ;
salary : number ;
fileName : string ;
fileType : FileType ;
violations : number ;
checks : number ;
lastCheck : number ; // timestamp в миллисекундах
} ;
// Кастомная функция фильтрации
const fuzzyFilter : FilterFn < Person > = ( row , columnId , value , addMeta ) = > {
const itemRank = rankItem ( row . getValue ( columnId ) , value ) ;
addMeta ( { itemRank } ) ;
return itemRank . passed ;
} ;
// Определяем тип для фильтров
declare module '@tanstack/react-table' {
interface FilterFns {
fuzzy : FilterFn < unknown > ;
// Иконки для типов файлов
const FileTypeIcon = ( { type } : { type : FileType } ) = > {
switch ( type ) {
case 'image' :
return < span className = "text-[#f08c00]" >
< IconImageFile / >
< / span > ;
case 'video' :
return < span className = "text-[#2f9e44]" >
< IconVideoFile / >
< / span > ;
case 'audio' :
return < span className = "text-[#1971c2]" >
< IconAudioFile / >
< / span > ;
default :
return < span > 📄 < / span > ;
}
}
} ;
export default function DataTable() {
// Данные
const [ data ] = useState < Person [ ] > ( [
{ id : 1 , name : 'Иван Петров' , age : 28 , email : 'ivan@example.com' , department : 'IT' , salary : 80000 } ,
{ id : 2 , name : 'Анна Сидорова' , age : 32 , email : 'anna@example.com' , department : 'HR' , salary : 65000 } ,
{ id : 3 , name : 'Сергей Иванов' , age : 45 , email : 'sergey@example.com' , department : 'Финансы' , salary : 95000 } ,
{ id : 4 , name : 'Мария Кузнецова' , age : 26 , email : 'maria@example.com' , department : 'Маркетинг' , salary : 60000 } ,
{ id : 5 , name : 'Алексей Смирнов' , age : 38 , email : 'alex@example.com' , department : 'IT' , salary : 85000 } ,
{ id : 6 , name : 'Ольга Васнецова' , age : 29 , email : 'olga@example.com' , department : 'HR' , salary : 62000 } ,
{ id : 7 , name : 'Дмитрий Орлов' , age : 41 , email : 'dmitry@example.com' , department : 'Финансы' , salary : 92000 } ,
{ id : 8 , name : 'Екатерина Новикова' , age : 35 , email : 'ekaterina@example.com' , department : 'Маркетинг' , salary : 70000 } ,
// Форматирование даты из timestamp
const formatDate = ( timestamp : number ) = > {
const date = new Date ( timestamp ) ;
const day = date . getDate ( ) . toString ( ) . padStart ( 2 , '0' ) ;
const month = ( date . getMonth ( ) + 1 ) . toString ( ) . padStart ( 2 , '0' ) ;
const year = date . getFullYear ( ) ;
return ` ${ day } . ${ month } . ${ year } ` ;
} ;
// Компонент таблицы
export default function TanstakFilesTable() {
// Данные с timestamp вместо Date объектов
const [ data ] = useState < FileItem [ ] > ( [
{ id : 1 , fileName : 'image1.jpg' , fileType : 'image' , violations : 5 , checks : 12 , lastCheck : 1705267200000 } , // 15.01.2024
{ id : 2 , fileName : 'presentation.mp4' , fileType : 'video' , violations : 2 , checks : 8 , lastCheck : 1705180800000 } , // 14.01.2024
{ id : 3 , fileName : 'song.mp3' , fileType : 'audio' , violations : 0 , checks : 5 , lastCheck : 1705094400000 } , // 13.01.2024
{ id : 4 , fileName : 'photo1.jpg' , fileType : 'image' , violations : 3 , checks : 10 , lastCheck : 1705008000000 } , // 12.01.2024
{ id : 5 , fileName : 'movie.mp4' , fileType : 'video' , violations : 1 , checks : 7 , lastCheck : 1704921600000 } , // 11.01.2024
{ id : 6 , fileName : 'podcast.mp3' , fileType : 'audio' , violations : 4 , checks : 9 , lastCheck : 1704835200000 } , // 10.01.2024
{ id : 7 , fileName : 'screenshot.png' , fileType : 'image' , violations : 0 , checks : 3 , lastCheck : 1704748800000 } , // 09.01.2024
{ id : 8 , fileName : 'tutorial.mp4' , fileType : 'video' , violations : 2 , checks : 6 , lastCheck : 1704662400000 } , // 08.01.2024
{ id : 9 , fileName : 'music.mp3' , fileType : 'audio' , violations : 1 , checks : 4 , lastCheck : 1704576000000 } , // 07.01.2024
{ id : 10 , fileName : 'image2.jpg' , fileType : 'image' , violations : 5 , checks : 11 , lastCheck : 1704489600000 } , // 06.01.2024
{ id : 11 , fileName : 'film.mov' , fileType : 'video' , violations : 0 , checks : 2 , lastCheck : 1704403200000 } , // 05.01.2024
{ id : 12 , fileName : 'sound.wav' , fileType : 'audio' , violations : 3 , checks : 8 , lastCheck : 1704316800000 } , // 04.01.2024
{ id : 13 , fileName : 'picture.png' , fileType : 'image' , violations : 2 , checks : 7 , lastCheck : 1704230400000 } , // 03.01.2024
{ id : 14 , fileName : 'video2.mp4' , fileType : 'video' , violations : 1 , checks : 5 , lastCheck : 1704144000000 } , // 02.01.2024
{ id : 15 , fileName : 'audio2.mp3' , fileType : 'audio' , violations : 0 , checks : 3 , lastCheck : 1704057600000 } , // 01.01.2024
] ) ;
// Состояния
const [ sorting , setSorting ] = useState < SortingState > ( [ ] ) ;
const [ columnFilters , setColumnFilters ] = useState < ColumnFiltersState > ( [ ] ) ;
const [ globalFilter , setGlobalFilter ] = useState ( '' ) ;
const [ rowSelection , setRowSelection ] = useState ( { } ) ;
const [ dateFilter , setDateFilter ] = useState < string > ( 'all ' ) ;
const [ typeFilter , setTypeFilter ] = useState < string > ( 'all' ) ;
const t = useTranslations ( "Global" ) ;
// Определение колонок
const columns = useMemo < ColumnDef < Person > [ ] > (
const columns = useMemo < ColumnDef < FileItem > [ ] > (
( ) = > [
{
id : 'select ' ,
header : ( { table } ) = > (
< input
type = "checkbox"
checked = { table . getIsAllPageRowsSelected ( ) }
onChange = { table . getToggleAllPageRowsSelectedHandler ( ) }
/ >
accessorKey : 'fileName ' ,
header : ( { column } ) = > (
< div className = "flex items-center justify-start" >
< span >
{ t ( 'file' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "ml-2 p-1 hover:bg-gray-200 rounded"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< ArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< ArrowDown / >
< / span >
: < span >
< Filter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > (
< input
type = "checkbox"
checked = { row . getIsSelected ( ) }
onChange = { row . getToggleSelectedHandler ( ) }
/ >
< div className = "flex items-center space-x-2" >
< FileTypeIcon type = { row . original . fileType } / >
< div >
< div className = "font-medium" > { row . original . fileName } < / div >
< / div >
< / div >
) ,
enableSorting : false ,
enableColumnFilter : false ,
} ,
{
accessorKey : 'id ' ,
header : 'ID' ,
cell : ( info ) = > info . getValue ( ) ,
accessorKey : 'violations ' ,
header : ( { column } ) = > (
< div className = "flex items-center justify-center" >
< span >
{ t ( 'violations' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "ml-2 p-1 hover:bg-gray-200 rounded"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< ArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< ArrowDown / >
< / span >
: < span >
< Filter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > (
< div className = { ` text-center font-semibold ${ row . original . violations > 0 ? 'text-red-600' : 'text-green-600' } ` } >
{ row . original . violations }
< / div >
) ,
} ,
{
accessorKey : 'name ' ,
header : 'Имя' ,
cell : ( info ) = > info . getValue ( ) ,
filterFn : fuzzyFilter ,
accessorKey : 'checks ' ,
header : ( { column } ) = > (
< div className = "flex items-center justify-center" >
< span >
{ t ( 'checks' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "ml-2 p-1 hover:bg-gray-200 rounded"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< ArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< ArrowDown / >
< / span >
: < span >
< Filter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > (
< div className = "text-center" >
{ row . original . checks }
< / div >
) ,
} ,
{
accessorKey : 'age ' ,
header : 'Возраст' ,
cell : ( info ) = > info . getValue ( ) ,
accessorKey : 'lastCheck ' ,
header : ( { column } ) = > (
< div className = "flex items-center justify-center" >
< span >
{ t ( 'last-check' ) }
< / span >
< button
onClick = { ( ) = > column . toggleSorting ( column . getIsSorted ( ) === 'asc' ) }
className = "ml-2 p-1 hover:bg-gray-200 rounded"
>
{
column . getIsSorted ( ) === 'asc' ?
< span >
< ArrowUp / >
< / span >
: column . getIsSorted ( ) === 'desc' ?
< span >
< ArrowDown / >
< / span >
: < span >
< Filter / >
< / span >
}
< / button >
< / div >
) ,
cell : ( { row } ) = > (
< div className = "text-center" >
{ formatDate ( row . original . lastCheck ) }
< / div >
) ,
enableColumnFilter : false ,
} ,
{
accessorKey : 'email ' ,
header : 'Email' ,
cell : ( info ) = > info . getValue ( ) ,
} ,
{
accessorKey : 'department' ,
header : 'Отдел' ,
cell : ( info ) = > info . getValue ( ) ,
} ,
{
accessorKey : 'salary' ,
header : 'Зарплата' ,
cell : ( info ) = > ` $ ${ Number ( info . getValue ( ) ) . toLocaleString ( ) } ` ,
id : 'actions ' ,
header : ( ) = > {
return (
< div className = "flex items-center justify-center" >
{ t ( 'actions' ) }
< / div >
)
} ,
cell : ( { row } ) = > (
< div className = "flex space-x-2 justify-center" >
< button
onClick = { ( ) = > handleView ( row . original ) }
className = "px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 text-sm"
>
< IconEye / >
< / button >
< button
onClick = { ( ) = > handleDownload ( row . original ) }
className = "px-3 py-1 bg-green-500 text-white rounded hover:bg-green-600 text-sm"
>
< IconDownload / >
< / button >
< button
onClick = { ( ) = > handleProtect ( row . original ) }
className = "px-3 py-1 bg-violet-500 text-white rounded hover:bg-violet-600 text-sm"
>
< IconShield / >
< / button >
< / div >
) ,
enableSorting : false ,
enableColumnFilter : false ,
} ,
] ,
[ ]
) ;
// Обработчики действий
const handleView = ( file : FileItem ) = > {
console . log ( ` Просмотр файла: ${ file . fileName } ` ) ;
} ;
const handleDownload = ( file : FileItem ) = > {
console . log ( ` Скачать: ${ file . fileName } ` ) ;
} ;
const handleProtect = ( file : FileItem ) = > {
console . log ( ` Щиток: ${ file . fileName } ` ) ;
} ;
// Фильтрация по типу файла и дате
const filteredData = useMemo ( ( ) = > {
let result = data ;
// Фильтр по типу файла
if ( typeFilter !== 'all' ) {
result = result . filter ( item = > item . fileType === typeFilter ) ;
}
// Фильтр по дате
if ( dateFilter !== 'all' ) {
const now = Date . now ( ) ;
const oneDay = 24 * 60 * 60 * 1000 ;
const sevenDays = 7 * oneDay ;
const thirtyDays = 30 * oneDay ;
switch ( dateFilter ) {
case 'today' :
const todayStart = new Date ( ) . setHours ( 0 , 0 , 0 , 0 ) ;
result = result . filter ( item = > item . lastCheck >= todayStart ) ;
break ;
case 'week' :
const weekAgo = now - sevenDays ;
result = result . filter ( item = > item . lastCheck >= weekAgo ) ;
break ;
case 'month' :
const monthAgo = now - thirtyDays ;
result = result . filter ( item = > item . lastCheck >= monthAgo ) ;
break ;
case 'older' :
const monthAgo2 = now - thirtyDays ;
result = result . filter ( item = > item . lastCheck < monthAgo2 ) ;
break ;
}
}
return result ;
} , [ data , typeFilter , dateFilter ] ) ;
// Создание таблицы
const table = useReactTable ( {
data ,
data : filteredData ,
columns ,
filterFns : {
fuzzy : fuzzyFilter ,
} ,
state : {
sorting ,
columnFilters ,
globalFilter ,
rowSelection ,
} ,
onSortingChange : setSorting ,
onColumnFiltersChange : setColumnFilters ,
onGlobalFilterChange : setGlobalFilter ,
onRowSelectionChange : setRowSelection ,
getCoreRowModel : getCoreRowModel ( ) ,
getSortedRowModel : getSortedRowModel ( ) ,
getPaginationRowModel : getPaginationRowModel ( ) ,
getFilteredRowModel : getFilteredRowModel ( ) ,
globalFilterFn : fuzzyFilter , // Используем саму функцию, а не строку
initialState : {
pagination : {
pageSize : 10 ,
} ,
} ,
} ) ;
return (
< div className = "p-6 max-w-6xl mx-auto" >
< h1 className = "text-2xl font-bold mb-6" > Т а б л и ц а с о т р у д н и к о в < / h1 >
< div className = "p-6 mx-auto" >
{ /* Фильтры */ }
< div className = "flex flex-col md:flex-row justify-between items-start md:items-center gap-4 p-4" >
< div className = "flex flex-col md:flex-row gap-4 w-full md:w-auto" >
< div className = "flex flex-col w-[150px]" >
< div className = "text-sm font-medium mb-1" > { t ( 'date-filter' ) } : < / div >
< DropDownList
value = { dateFilter }
callBack = { setDateFilter }
>
< li value = "all" >
{ t ( 'all-dates' ) }
< / li >
< li value = "today" >
{ t ( 'today' ) }
< / li >
< li value = "week" >
{ t ( 'for-a-week' ) }
< / li >
< li value = "month" >
{ t ( 'for-a-month' ) }
< / li >
< li value = "older" >
{ t ( 'older-than-a-month' ) }
< / li >
< / DropDownList >
< / div >
{ /* Глобальный поиск */ }
< div className = "mb-4 " >
< input
type = "text"
placeholder = "Поиск по всем полям..."
value = { globalFilter }
onChange = { ( e ) = > setGlobalFilter ( e . target . value ) }
className = "px-4 py-2 border rounded-md w-full max-w-md"
/ >
< / div >
< div className = "flex flex-col w-[150px]" >
< div className = "text-sm font-medium mb-1 " > { t ( 'type-filter' ) } : < / div >
< DropDownList
value = { typeFilter }
callBack = { setTypeFilter }
>
< li value = "all" >
{ t ( 'all-types' ) }
< / li >
< li value = "image" >
{ t ( 'images' ) }
< / li >
< li value = "video" >
{ t ( 'videos' ) }
< / li >
< li value = "audio" >
{ t ( 'audios' ) }
< / li >
< / DropDownList >
< / div >
< / div >
{ /* Фильтры по колонкам */ }
< div className = "flex gap-4 mb-4 flex-wrap" >
{ table . getAllColumns ( )
. filter ( column = > column . getCanFilter ( ) && column . id !== 'select' )
. map ( column = > (
< div key = { column . id } className = "flex flex-col" >
< label className = "text-sm font-medium mb-1" >
{ typeof column . columnDef . header === 'string'
? column.columnDef.header
: column.id }
< / label >
{ column . id === 'department' ? (
< select
value = { ( column . getFilterValue ( ) as string ) || '' }
onChange = { e = > column . setFilterValue ( e . target . value ) }
className = "px-3 py-1 border rounded"
>
< option value = "" > В с е о т д е л ы < / option >
< option value = "IT" > IT < / option >
< option value = "HR" > HR < / option >
< option value = "Финансы" > Ф и н а н с ы < / option >
< option value = "Маркетинг" > М а р к е т и н г < / option >
< / select >
) : column . id === 'age' ? (
< input
type = "number"
placeholder = "Возраст от..."
value = { ( column . getFilterValue ( ) as number ) || '' }
onChange = { e = > column . setFilterValue ( e . target . value ? parseInt ( e . target . value ) : undefined ) }
className = "px-3 py-1 border rounded w-32"
/ >
) : (
< input
type = "text"
placeholder = { ` Фильтр ${ column . id } ` }
value = { ( column . getFilterValue ( ) as string ) || '' }
onChange = { e = > column . setFilterValue ( e . target . value ) }
className = "px-3 py-1 border rounded"
/ >
) }
< / div >
) ) }
< div className = "flex flex-col w-full md:w-auto" >
< div className = "text-sm font-medium mb-1" > { t ( 'items-per-page' ) } : < / div >
< DropDownList
value = { table . getState ( ) . pagination . pageSize }
//@ts-ignore сделал так потому что для table.setPageSize нужна цифра
callBack = { table . setPageSize }
>
{ [ 5 , 10 , 20 , 50 , 100 ] . map ( pageSize = > (
< li key = { pageSize } value = { pageSize } >
{ t ( 'show' ) } { pageSize }
< / li >
) ) }
< / DropDownList >
< / div >
< / div >
{ /* Таблица */ }
< div className = "overflow-x-auto border rounded-lg" >
< div className = "overflow-x-auto rounded-lg shadow " >
< table className = "min-w-full divide-y divide-gray-200" >
< thead className = "bg-gray-50" >
{ table . getHeaderGroups ( ) . map ( headerGroup = > (
@@ -206,96 +411,115 @@ export default function DataTable() {
{ headerGroup . headers . map ( header = > (
< th
key = { header . id }
className = "px-6 py-3 text-left text-xs font-medium text-gray-5 00 uppercase tracking-wider cursor-pointer "
onClick = { header . column . getToggleSortingHandler ( ) }
className = "px-6 py-3 text-left text-xs font-medium text-gray-7 00 uppercase tracking-wider"
>
< div className = "flex items-center" >
{ header . isPlaceholder
? null
: typeof header . column . columnDef . header === 'string'
? header.column.columnDef.header
: header.column.id }
{ {
asc : ' 🔼' ,
desc : ' 🔽' ,
} [ header . column . getIsSorted ( ) as string ] ? ? null }
< / div >
{ header . isPlaceholder
? null
: typeof header . column . columnDef . header === 'function'
? header . column . columnDef . header ( header . getContext ( ) )
: header . column . columnDef . header as string }
< / th >
) ) }
< / tr >
) ) }
< / thead >
< tbody className = "bg-white divide-y divide-gray-200" >
{ table . getRowModel ( ) . rows . map ( row = > (
< tr key = { row . id } className = "hover:bg-gray-50" >
{ row . getVisibleCells ( ) . map ( cell = > (
< td key = { cell . id } className = "px-6 py-4 whitespace-nowrap" >
{ typeof cell . column . columnDef . cell === 'function'
? cell . column . columnDef . cell ( cell . getContext ( ) )
: cell . getValue ( ) as string }
< / td >
) ) }
{ table . getRowModel ( ) . rows . length > 0 ? (
table . getRowModel ( ) . rows . map ( row = > (
< tr key = { row . id } className = "hover:bg-gray-50 transition-colors" >
{ row . getVisibleCells ( ) . map ( cell = > (
< td key = { cell . id } className = "px-6 py-4 whitespace-nowrap" >
{ typeof cell . column . columnDef . cell === 'function'
? cell . column . columnDef . cell ( cell . getContext ( ) )
: cell . getValue ( ) as string }
< / td >
) ) }
< / tr >
) )
) : (
< tr >
< td colSpan = { columns . length } className = "px-6 py-8 text-center text-gray-500" >
{ t ( 'no-data-for-selected-filters' ) }
< / td >
< / tr >
) ) }
) }
< / tbody >
< / table >
< / div >
{ /* Пагинация */ }
< div className = "flex items-center justify-between mt-4" >
< div className = "flex flex-col md:flex-row items-center justify-between mt-6 gap- 4" >
< div className = "flex items-center gap-2" >
< span className = "text-sm text-gray-700" >
{ t ( 'page' ) } { ' ' }
< strong >
{ table . getState ( ) . pagination . pageIndex + 1 } { t ( 'out-of' ) } { table . getPageCount ( ) }
< / strong >
< / span >
< span className = "text-sm text-gray-500" >
| { t ( 'shown' ) } { table . getRowModel ( ) . rows . length } { t ( 'out-of' ) } { filteredData . length } { t ( 'files' ) }
< / span >
< / div >
< div className = "flex items-center gap-2" >
< button
className = "px-3 py-1 border rounded disabled:opacity-50 "
onClick = { ( ) = > table . setPageIndex ( 0 ) }
className = "px-2 py-1 border rounded-md hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed "
onClick = { ( ) = > table . firstPage ( ) }
disabled = { ! table . getCanPreviousPage ( ) }
>
⟪
< DoubleArrowLeft / >
< / button >
< button
className = "px-3 py-1 border rounded disabled:opacity-50 "
className = "px-2 py-1 border rounded-md hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed "
onClick = { ( ) = > table . previousPage ( ) }
disabled = { ! table . getCanPreviousPage ( ) }
>
⟨
< ArrowLeft / >
< / button >
< div className = "flex items-center gap-1" >
{ Array . from ( { length : Math.min ( 5 , table . getPageCount ( ) ) } , ( _ , i ) = > {
const pageIndex = Math . max (
0 ,
Math . min (
table . getPageCount ( ) - 5 ,
table . getState ( ) . pagination . pageIndex - 2
)
) + i ;
if ( pageIndex < table . getPageCount ( ) ) {
return (
< button
key = { pageIndex }
className = { ` border border-black px-3 py-1 rounded-md ${ table . getState ( ) . pagination . pageIndex === pageIndex
? 'bg-blue-500 text-white'
: 'hover:bg-gray-100'
} ` }
onClick = { ( ) = > table . setPageIndex ( pageIndex ) }
>
{ pageIndex + 1 }
< / button >
) ;
}
return null ;
} ) }
< / div >
< button
className = "px-3 py-1 border rounded disabled:opacity-50 "
className = "px-2 py-1 border rounded-md hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed "
onClick = { ( ) = > table . nextPage ( ) }
disabled = { ! table . getCanNextPage ( ) }
>
⟩
< ArrowRight / >
< / button >
< button
className = "px-3 py-1 border rounded disabled:opacity-50 "
onClick = { ( ) = > table . setPageIndex ( table . getPageCount ( ) - 1 ) }
className = "px-2 py-1 border rounded-md hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed "
onClick = { ( ) = > table . lastPage ( ) }
disabled = { ! table . getCanNextPage ( ) }
>
⟫
< DoubleArrowRight / >
< / button >
< / div >
< div className = "flex items-center gap-4" >
< span >
С т р а н и ц а { ' ' }
< strong >
{ table . getState ( ) . pagination . pageIndex + 1 } и з { table . getPageCount ( ) }
< / strong >
< / span >
< select
value = { table . getState ( ) . pagination . pageSize }
onChange = { e = > table . setPageSize ( Number ( e . target . value ) ) }
className = "px-2 py-1 border rounded"
>
{ [ 5 , 10 , 20 , 30 , 40 , 50 ] . map ( pageSize = > (
< option key = { pageSize } value = { pageSize } >
П о к а з а т ь { pageSize }
< / option >
) ) }
< / select >
< span >
В с е г о с т р о к : { data . length } | О т ф и л ь т р о в а н о : { table . getFilteredRowModel ( ) . rows . length }
< / span >
< / div >
< / div >
< / div >
) ;