1
1
import React , { useState } from 'react' ;
2
2
import { treatSpaceOrEnterAsClick } from '~/helpers/events' ;
3
- import { getDisplayStatus } from '~/helpers/errata' ;
3
+ import { getDisplayStatus , Errata } from '~/helpers/errata' ;
4
4
import './table.scss' ;
5
5
6
- type ColumnSpec = {
7
- label : string ;
8
- id : string ;
9
- sortFn ?: string ;
10
- cssClass : string ;
11
- } ;
12
-
13
- type RawErrataItem = {
6
+ export type RawErrataItem = Errata & {
14
7
id : string ;
15
8
created : string ;
16
9
resource : string ;
@@ -35,14 +28,7 @@ type ProcessedErrataItem = {
35
28
modified : string ;
36
29
} ;
37
30
38
- type SortController = {
39
- sortFn : string ;
40
- sortKey : string ;
41
- sortDir : number ;
42
- setSortFn : ( fn : string ) => void ;
43
- setSortKey : ( key : string ) => void ;
44
- setSortDir : ( dir : number ) => void ;
45
- } ;
31
+ type SortController = ReturnType < typeof useSortController > ;
46
32
47
33
type DesktopHeaderColumnProps = {
48
34
colSpec : ColumnSpec ;
@@ -85,12 +71,9 @@ type TableProps = {
85
71
filter : string ;
86
72
} ;
87
73
88
- type SortFn = (
89
- a : string | number | null | ProcessedErrataItem ,
90
- b : string | number | null | ProcessedErrataItem
91
- ) => number ;
74
+ type ColumnSpec = typeof columnSpecs [ number ] ;
92
75
93
- const columnSpecs : ColumnSpec [ ] = [
76
+ const columnSpecs = [
94
77
{
95
78
label : 'Date Submitted' ,
96
79
id : 'date' ,
@@ -131,7 +114,7 @@ const columnSpecs: ColumnSpec[] = [
131
114
sortFn : 'sortDecision' ,
132
115
cssClass : 'mid'
133
116
}
134
- ] ;
117
+ ] as const ;
135
118
136
119
const statusSortOrder : { [ key : string ] : number } = {
137
120
'Co' : 1 ,
@@ -141,7 +124,7 @@ const statusSortOrder: {[key: string]: number} = {
141
124
'In' : 5
142
125
} ;
143
126
144
- const sortFunctions : { [ key : string ] : SortFn } = {
127
+ const sortFunctions = {
145
128
sortDate : ( a : string , b : string ) : number => new Date ( a ) . getTime ( ) - new Date ( b ) . getTime ( ) ,
146
129
sort : ( a : string | null , b : string | null ) : number => {
147
130
const as = a === null ? '' : a ;
@@ -166,21 +149,22 @@ const sortFunctions: {[key: string]: SortFn} = {
166
149
167
150
function DesktopHeaderColumn ( { colSpec, sortController} : DesktopHeaderColumnProps ) : React . ReactElement {
168
151
const { sortKey, sortDir, setSortFn, setSortDir, setSortKey} = sortController ;
152
+ const sortable = 'sortFn' in colSpec ;
169
153
const onClick = ( ) : void => {
170
154
if ( sortKey === colSpec . id ) {
171
155
setSortDir ( - sortDir ) ;
172
156
} else {
173
- if ( colSpec . sortFn ) {
157
+ if ( sortable ) {
174
158
setSortFn ( colSpec . sortFn ) ;
175
159
}
176
160
setSortKey ( colSpec . id ) ;
177
161
setSortDir ( 1 ) ;
178
162
}
179
163
} ;
180
- const sortAttributes = colSpec . sortFn ? {
164
+ const sortAttributes = sortable ? {
181
165
role : 'button' , tabIndex : 0 , onClick, onKeyDown : treatSpaceOrEnterAsClick
182
166
} : { } ;
183
- const sortIndicator = colSpec . sortFn ?
167
+ const sortIndicator = sortable ?
184
168
< span className = { `will-sort sortdir${ colSpec . sortFn === 'sort' ? 1 : - 1 } ` } /> :
185
169
null ;
186
170
@@ -204,7 +188,7 @@ function DesktopHeaderRow({sortController}: DesktopHeaderRowProps): React.ReactE
204
188
return (
205
189
< tr >
206
190
{
207
- columnSpecs . map ( ( colSpec : ColumnSpec ) =>
191
+ columnSpecs . map ( ( colSpec ) =>
208
192
< DesktopHeaderColumn key = { colSpec . id } colSpec = { colSpec } sortController = { sortController } />
209
193
)
210
194
}
@@ -224,7 +208,7 @@ function DesktopDataColumn({colSpec, entry}: DesktopDataColumnProps): React.Reac
224
208
< React . Fragment >
225
209
{ entry [ colSpec . id as keyof ProcessedErrataItem ] } { ' ' }
226
210
{
227
- colSpec . id === 'displayStatus' &&
211
+ colSpec . id === 'displayStatus' &&
228
212
entry [ colSpec . id as keyof ProcessedErrataItem ] === 'No Correction' &&
229
213
< a href = { `/errata/${ entry . id } ` } > Details</ a >
230
214
}
@@ -238,16 +222,16 @@ function DesktopDataColumn({colSpec, entry}: DesktopDataColumnProps): React.Reac
238
222
function DesktopDataRow ( { entry} : DesktopDataRowProps ) : React . ReactElement {
239
223
return (
240
224
< tr >
241
- { columnSpecs . map ( ( colSpec : ColumnSpec ) =>
225
+ { columnSpecs . map ( ( colSpec ) =>
242
226
< DesktopDataColumn key = { colSpec . id } colSpec = { colSpec } entry = { entry } />
243
227
) }
244
228
</ tr >
245
229
) ;
246
230
}
247
231
248
- function useSortController ( ) : SortController {
249
- const [ sortFn , setSortFn ] = useState < string > ( 'sortDate' ) ;
250
- const [ sortKey , setSortKey ] = useState < string > ( 'date' ) ;
232
+ function useSortController ( ) {
233
+ const [ sortFn , setSortFn ] = useState < keyof typeof sortFunctions > ( 'sortDate' ) ;
234
+ const [ sortKey , setSortKey ] = useState < keyof ProcessedErrataItem > ( 'date' ) ;
251
235
const [ sortDir , setSortDir ] = useState < number > ( - 1 ) ;
252
236
253
237
return { sortFn, sortKey, sortDir, setSortFn, setSortKey, setSortDir} ;
@@ -257,9 +241,11 @@ function DesktopTable({data}: DesktopTableProps): React.ReactElement {
257
241
const sortController = useSortController ( ) ;
258
242
const { sortFn, sortKey, sortDir} = sortController ;
259
243
260
- const sortedData = [ ...data ] ;
261
- sortedData . sort ( ( a : ProcessedErrataItem , b : ProcessedErrataItem ) =>
262
- sortFunctions [ sortFn ] ( a [ sortKey as keyof ProcessedErrataItem ] , b [ sortKey as keyof ProcessedErrataItem ] )
244
+ const sortedData = [ ...data ] as Array < string & ProcessedErrataItem > ;
245
+
246
+ sortedData . sort ( ( a , b ) =>
247
+ // @ts -expect-error sortKey and sortFn are guaranteed compatible
248
+ sortFunctions [ sortFn ] ( a [ sortKey ] , b [ sortKey ] )
263
249
) ;
264
250
if ( sortDir < 0 ) {
265
251
sortedData . reverse ( ) ;
@@ -301,7 +287,7 @@ function MobileTable({entry}: MobileTableProps): React.ReactElement {
301
287
< table className = "body-block summary-table-mobile" >
302
288
< tbody >
303
289
{
304
- columnSpecs . map ( ( colSpec : ColumnSpec ) =>
290
+ columnSpecs . map ( ( colSpec ) =>
305
291
< MobileRow
306
292
key = { colSpec . label }
307
293
entry = { entry }
@@ -371,4 +357,4 @@ export default function Table({data, filter}: TableProps): React.ReactElement {
371
357
< DesktopTable data = { filteredDetails } />
372
358
</ div >
373
359
) ;
374
- }
360
+ }
0 commit comments