@@ -157,16 +157,121 @@ const styles = theme => ({
157
157
} ,
158
158
} )
159
159
160
+ const tableHeaderMetadata = {
161
+ "task.table.head.task" : { sortable : true , numeric : false , dataBaseKey : "title" } ,
162
+ "task.table.head.status" : { sortable : true , numeric : false , dataBaseKey : "status" } ,
163
+ "task.table.head.project" : { sortable : true , numeric : false , dataBaseKey : "Project.name" } ,
164
+ "task.table.head.value" : { sortable : true , numeric : true , dataBaseKey : "value" } ,
165
+ "task.table.head.labels" : { sortable : true , numeric : false , dataBaseKey : "Labels" } ,
166
+ "task.table.head.createdAt" : { sortable : true , numeric : false , dataBaseKey : "createdAt" }
167
+ }
168
+
169
+ const getSortingValue = ( item , fieldId ) => {
170
+
171
+ const getValue = ( item , dataBaseKey ) => {
172
+ const keys = dataBaseKey . split ( "." ) ;
173
+ return keys . reduce ( ( obj , key ) => ( obj && obj [ key ] !== 'undefined' ) ? obj [ key ] : undefined , item ) ;
174
+ } ;
175
+
176
+ const metadata = tableHeaderMetadata [ fieldId ] ;
177
+ if ( ! metadata ) {
178
+ console . error ( `No metadata found for fieldId: ${ fieldId } ` ) ;
179
+ return null ;
180
+ }
181
+
182
+ const { numeric, dataBaseKey } = metadata ;
183
+
184
+ const value = getValue ( item , dataBaseKey ) ;
185
+
186
+ if ( value === undefined ) {
187
+ console . error ( `Failed to get value for fieldId: ${ fieldId } ` ) ;
188
+ return null ;
189
+ }
190
+
191
+ if ( numeric ) {
192
+ const parsedValue = parseFloat ( value ) ;
193
+ if ( isNaN ( parsedValue ) ) {
194
+ console . error ( `Failed to parse numeric value for fieldId: ${ fieldId } ` ) ;
195
+ return null ;
196
+ }
197
+ return parsedValue ;
198
+ }
199
+ return value ;
200
+ } ;
201
+
202
+ const sortData = ( data , sortedBy , sortDirection ) => {
203
+ if ( sortDirection === 'none' ) return data ;
204
+
205
+ return [ ...data ] . sort ( ( a , b ) => {
206
+ let aValue = getSortingValue ( a , sortedBy ) ;
207
+ let bValue = getSortingValue ( b , sortedBy ) ;
208
+
209
+ // Handle null values
210
+ if ( aValue === null || bValue === null ) {
211
+ return ( aValue === null ? ( sortDirection === 'asc' ? - 1 : 1 ) : ( sortDirection === 'asc' ? 1 : - 1 ) ) ;
212
+ }
213
+
214
+ // Handle date sorting
215
+ if ( sortedBy === 'task.table.head.createdAt' ) {
216
+ let aDate = new Date ( aValue ) . getTime ( ) ;
217
+ let bDate = new Date ( bValue ) . getTime ( ) ;
218
+ return ( sortDirection === 'asc' ? aDate - bDate : bDate - aDate ) ;
219
+ }
220
+
221
+ // Handle labels array sorting
222
+ if ( sortedBy === 'task.table.head.labels' ) {
223
+ aValue = aValue . map ( label => label . name ) . join ( '' ) ;
224
+ bValue = bValue . map ( label => label . name ) . join ( '' ) ;
225
+ }
226
+
227
+ // Handle string sorting
228
+ let comparator = String ( aValue ) . localeCompare ( String ( bValue ) , 'en' , { numeric : true , sensitivity : 'base' , ignorePunctuation : true } ) ;
229
+ return ( sortDirection === 'asc' ? comparator : - comparator ) ;
230
+ } ) ;
231
+ } ;
232
+
160
233
class CustomPaginationActionsTable extends React . Component {
161
234
constructor ( props ) {
162
235
super ( props )
163
236
164
237
this . state = {
165
238
page : 0 ,
166
239
rowsPerPage : 10 ,
240
+ sortedBy : null ,
241
+ sortDirection : 'asc' ,
242
+ sortedData : this . props . tasks . data
243
+ }
244
+ }
245
+
246
+ componentDidUpdate ( prevProps ) {
247
+ if ( prevProps . tasks !== this . props . tasks ) {
248
+ const { sortedBy, sortDirection } = this . state ;
249
+ const newSortedData = sortData ( this . props . tasks . data , sortedBy , sortDirection ) ;
250
+ this . setState ( {
251
+ sortedData : newSortedData
252
+ } ) ;
167
253
}
168
254
}
169
255
256
+ handleSort = ( fieldId , sortDirection ) => {
257
+ const newSortedData = sortData ( this . props . tasks . data , fieldId , sortDirection ) ;
258
+
259
+ return {
260
+ sortedBy : fieldId ,
261
+ sortDirection,
262
+ sortedData : newSortedData ,
263
+ } ;
264
+ }
265
+
266
+ sortHandler = ( fieldId ) => {
267
+ this . setState ( ( prevState ) => {
268
+ const { sortedBy, sortDirection } = prevState ;
269
+ const newSortDirection = sortedBy === fieldId ? ( sortDirection === 'asc' ? 'desc' : ( sortDirection === 'desc' ? 'none' : 'asc' ) ) : 'asc' ;
270
+ return this . handleSort ( fieldId , newSortDirection ) ;
271
+ } ) ;
272
+ } ;
273
+
274
+
170
275
handleChangePage = ( event , page ) => {
171
276
this . setState ( { page } )
172
277
} ;
@@ -188,49 +293,59 @@ class CustomPaginationActionsTable extends React.Component {
188
293
189
294
render ( ) {
190
295
const { classes, tasks } = this . props
191
- const { rowsPerPage, page } = this . state
192
- const emptyRows = tasks . data . length ? rowsPerPage - Math . min ( rowsPerPage , tasks . data . length - page * rowsPerPage ) : 0
296
+ const { rowsPerPage, page, sortedBy, sortDirection, sortedData } = this . state ;
297
+
298
+ const emptyRows = sortedData . length ? rowsPerPage - Math . min ( rowsPerPage , sortedData . length - page * rowsPerPage ) : 0
299
+ const TableCellWithSortLogic = ( { fieldId, defineMessage, sortHandler } ) => {
300
+ return (
301
+ < TableSortLabel
302
+ active = { fieldId === sortedBy && sortDirection !== 'none' }
303
+ direction = { sortDirection }
304
+ onClick = {
305
+ ( ) => {
306
+ return sortHandler ( fieldId )
307
+ }
308
+ }
309
+ >
310
+ < FormattedMessage id = { fieldId } defineMessage = { defineMessage } />
311
+ </ TableSortLabel >
312
+ )
313
+ }
314
+
315
+ const TableHeadCustom = ( ) => {
316
+ console . log ( )
317
+ return (
318
+ < TableHead >
319
+ < TableRow >
320
+ { Object . entries ( tableHeaderMetadata ) . map ( ( [ fieldId , metadata ] ) => (
321
+ < TableCell key = { fieldId } >
322
+ < TableCellWithSortLogic sortHandler = { this . sortHandler } fieldId = { fieldId } defaultMessage = { metadata . dataBaseKey } />
323
+ </ TableCell >
324
+ ) ) }
325
+ </ TableRow >
326
+ </ TableHead >
327
+ ) ;
328
+ } ;
193
329
194
330
195
331
if ( tasks . completed && tasks . data . length === 0 ) {
196
- < Paper className = { classes . root } >
332
+ return ( < Paper className = { classes . root } >
197
333
< div style = { { display : 'flex' , justifyContent : 'center' , alignItems : 'center' , height : 200 } } >
198
334
< Typography variant = 'caption' >
199
335
< FormattedMessage id = 'task.table.body.noIssues' defaultMessage = 'No issues' />
200
336
</ Typography >
201
337
</ div >
202
- </ Paper >
338
+ </ Paper > ) ;
203
339
}
204
340
205
341
return (
206
342
< Paper className = { classes . root } >
207
343
< ReactPlaceholder style = { { marginBottom : 20 , padding : 20 } } showLoadingAnimation type = 'text' rows = { 12 } ready = { tasks . completed } >
208
344
< div className = { classes . tableWrapper } >
209
345
< Table className = { classes . table } >
210
- < TableHead >
211
- < TableRow >
212
- < TableCell >
213
- < FormattedMessage id = 'task.table.head.task' defaultMessage = 'Task' />
214
- </ TableCell >
215
- < TableCell >
216
- < FormattedMessage id = 'task.table.head.status' defaultMessage = 'Status' />
217
- </ TableCell >
218
- < TableCell >
219
- < FormattedMessage id = 'task.table.head.project' defaultMessage = 'Project' />
220
- </ TableCell >
221
- < TableCell >
222
- < FormattedMessage id = 'task.table.head.value' defaultMessage = 'Value' />
223
- </ TableCell >
224
- < TableCell >
225
- < FormattedMessage id = 'task.table.head.labels' defaultMessage = 'Labels' />
226
- </ TableCell >
227
- < TableCell >
228
- < FormattedMessage id = 'task.table.head.createdAt' defaultMessage = 'Created' />
229
- </ TableCell >
230
- </ TableRow >
231
- </ TableHead >
346
+ < TableHeadCustom />
232
347
< TableBody >
233
- { tasks . data . slice ( page * rowsPerPage , page * rowsPerPage + rowsPerPage ) . map ( n => {
348
+ { sortedData . slice ( page * rowsPerPage , page * rowsPerPage + rowsPerPage ) . map ( n => {
234
349
const assigned = n . Assigns . find ( a => a . id === n . assigned )
235
350
const assignedUser = assigned && assigned . User
236
351
return (
@@ -298,11 +413,11 @@ class CustomPaginationActionsTable extends React.Component {
298
413
< TableRow >
299
414
< TablePagination
300
415
colSpan = { 3 }
301
- count = { tasks . data . length }
416
+ count = { sortedData . length }
302
417
rowsPerPage = { rowsPerPage }
303
418
page = { page }
304
- onChangePage = { ( e , page ) => this . handleChangePage ( e , page ) }
305
- onChangeRowsPerPage = { ( e , page ) => this . handleChangeRowsPerPage ( e , page ) }
419
+ onPageChange = { ( e , page ) => this . handleChangePage ( e , page ) }
420
+ onRowsPerPageChange = { ( e , page ) => this . handleChangeRowsPerPage ( e , page ) }
306
421
Actions = { TablePaginationActionsWrapped }
307
422
/>
308
423
</ TableRow >
@@ -322,4 +437,4 @@ CustomPaginationActionsTable.propTypes = {
322
437
user : PropTypes . object ,
323
438
}
324
439
325
- export default injectIntl ( withRouter ( withStyles ( styles ) ( CustomPaginationActionsTable ) ) )
440
+ export default injectIntl ( withRouter ( withStyles ( styles ) ( CustomPaginationActionsTable ) ) )
0 commit comments