1
1
import { SetStateAction , useEffect , useRef , useState } from 'react' ;
2
2
import { Table , TableBody , TableCell , TableHead , TableHeader , TableRow } from "@/components/ui/table" ;
3
3
import { getCoreRowModel , useReactTable , flexRender , getFilteredRowModel , getPaginationRowModel , getExpandedRowModel , getSortedRowModel } from '@tanstack/react-table' ;
4
- import type { ColumnDef , Row , PaginationState , RowSelectionState , ColumnFiltersState , ExpandedState } from '@tanstack/react-table' ;
4
+ import type { ColumnDef , Row , PaginationState , RowSelectionState , ColumnFiltersState , ExpandedState , ColumnDefTemplate , HeaderContext , SortingState } from '@tanstack/react-table' ;
5
5
import { cn } from '@/lib/utils' ;
6
6
import { Select , SelectContent , SelectGroup , SelectItem , SelectLabel } from './select' ;
7
7
import { Button } from './button' ;
8
- import { ChevronLeftIcon , ChevronRightIcon , DoubleArrowLeftIcon , DoubleArrowRightIcon } from '@radix-ui/react-icons' ;
8
+ import { ArrowDownIcon , ArrowUpIcon , ChevronLeftIcon , ChevronRightIcon , DoubleArrowLeftIcon , DoubleArrowRightIcon } from '@radix-ui/react-icons' ;
9
9
import * as SelectPrimitive from "@radix-ui/react-select"
10
10
import type { Table as ReactTable } from '@tanstack/react-table' ;
11
11
import { useTranslation } from 'react-i18next' ;
12
12
import { useResizeObserver } from '@/hooks/useResizeObserver' ;
13
13
14
14
15
+ export function getHeader < T > ( name : string , translate : boolean = true , addSorting : boolean = true ) : ColumnDefTemplate < HeaderContext < T , unknown > > | undefined {
16
+ if ( ! addSorting ) {
17
+ return ( ) => {
18
+ const { t } = useTranslation ( ) ;
19
+ return < span className = 'select-none' > { translate ? t ( name ) : name } </ span > ;
20
+ }
21
+ }
22
+
23
+ return ( { column } ) => {
24
+ const { t } = useTranslation ( ) ;
25
+ return (
26
+ < div className = 'select-none flex' >
27
+ < span
28
+ className = "cursor-pointer hover:text-black dark:hover:text-white flex flex-row items-center"
29
+ onClick = { ( ) => column . toggleSorting ( ) } >
30
+ { translate ? t ( name ) : name }
31
+ { column . getIsSorted ( ) === "desc" ? (
32
+ < ArrowDownIcon className = "ml-2" />
33
+ ) : column . getIsSorted ( ) === "asc" ? (
34
+ < ArrowUpIcon className = "ml-2" />
35
+ ) : (
36
+ < > </ >
37
+ ) }
38
+ </ span >
39
+ </ div >
40
+ )
41
+ }
42
+ }
43
+
44
+ function getStoredSortingState ( key ?: string ) {
45
+ if ( key ) {
46
+ let sortingString = localStorage . getItem ( key ) ;
47
+ if ( sortingString ) {
48
+ return JSON . parse ( sortingString ) ;
49
+ }
50
+ }
51
+ }
52
+
15
53
interface ReactTableProps < T extends object > {
16
54
data : T [ ] ;
17
55
columns : ColumnDef < T > [ ] ;
@@ -29,6 +67,7 @@ interface ReactTableProps<T extends object> {
29
67
filters ?: { id : string , value : string } [ ] ;
30
68
maxHeight ?: string | number ;
31
69
expandable ?: boolean ;
70
+ storeSortingState ?: string ;
32
71
}
33
72
34
73
function SimpleTable < T extends object > ( {
@@ -46,7 +85,8 @@ function SimpleTable<T extends object>({
46
85
allowMultiSelect,
47
86
filters,
48
87
maxHeight,
49
- expandable
88
+ expandable,
89
+ storeSortingState
50
90
} : ReactTableProps < T > ) {
51
91
const [ pagination , setPagination ] = useState < PaginationState > ( {
52
92
pageIndex : pageIndex ?? 0 ,
@@ -55,6 +95,7 @@ function SimpleTable<T extends object>({
55
95
const [ rowSelection , setRowSelection ] = useState < RowSelectionState > ( initialRowSelection || { } ) ;
56
96
const [ columnFilters , setColumnFilters ] = useState < ColumnFiltersState > ( filters || [ ] )
57
97
const [ expanded , setExpanded ] = useState < ExpandedState > ( { } ) ;
98
+ const [ sorting , setSorting ] = useState < SortingState > ( getStoredSortingState ( storeSortingState ) || [ ] ) ;
58
99
59
100
const table = useReactTable ( {
60
101
data,
@@ -69,7 +110,8 @@ function SimpleTable<T extends object>({
69
110
pagination,
70
111
rowSelection,
71
112
columnFilters,
72
- expanded
113
+ expanded,
114
+ sorting
73
115
} ,
74
116
getFilteredRowModel : getFilteredRowModel ( ) ,
75
117
onColumnFiltersChange : setColumnFilters ,
@@ -78,6 +120,7 @@ function SimpleTable<T extends object>({
78
120
if ( allowSelect || allowSelectCheckbox || allowMultiSelect ) setRowSelection ( arg ) ;
79
121
} ,
80
122
onExpandedChange : setExpanded ,
123
+ onSortingChange : setSorting ,
81
124
getSubRows : ( row : any ) => row ?. subRows ,
82
125
} ) ;
83
126
@@ -104,6 +147,12 @@ function SimpleTable<T extends object>({
104
147
}
105
148
} , [ filters ] )
106
149
150
+ useEffect ( ( ) => {
151
+ if ( storeSortingState ) {
152
+ localStorage . setItem ( storeSortingState , JSON . stringify ( sorting ) ) ;
153
+ }
154
+ } , [ sorting ] ) ;
155
+
107
156
// For some reason the ScrollArea scrollbar is only shown when it's set to a specific height.
108
157
// So, we wrap it in a parent div, monitor its size, and set the height of the table accordingly.
109
158
const parentRef = useRef < HTMLTableElement > ( null ) ;
0 commit comments