1
- import { useState , useEffect } from "react" ;
1
+ import { useState , useEffect , useRef } from "react" ;
2
2
import { useTranslation } from "react-i18next" ;
3
3
import {
4
4
Upload ,
@@ -33,9 +33,10 @@ export const FileManagementPage = () => {
33
33
const [ showRenameModal , setShowRenameModal ] = useState ( false ) ;
34
34
const [ selectedFile , setSelectedFile ] = useState < FileData | null > ( null ) ;
35
35
const [ newFileName , setNewFileName ] = useState ( "" ) ;
36
- const [ sortBy , setSortBy ] = useState < "name" | "size" | "type" > ( "name " ) ;
37
- const [ sortDirection , setSortDirection ] = useState < "asc" | "desc" > ( "asc " ) ;
36
+ const [ sortBy , setSortBy ] = useState < "name" | "size" | "type" | "updatedAt" > ( "updatedAt " ) ;
37
+ const [ sortDirection , setSortDirection ] = useState < "asc" | "desc" > ( "desc " ) ;
38
38
const [ activeCategory , setActiveCategory ] = useState < FileCategory > ( 'all' ) ;
39
+ const [ isSortOptionsOpen , setIsSortOptionsOpen ] = useState ( false ) ;
39
40
const [ confirmDialog , setConfirmDialog ] = useState ( {
40
41
isOpen : false ,
41
42
title : '' ,
@@ -44,6 +45,10 @@ export const FileManagementPage = () => {
44
45
cancelText : '' ,
45
46
confirmColor : 'red' as 'red' | 'blue' | 'green' | 'gray'
46
47
} ) ;
48
+
49
+ // Add refs for sort dropdown and button
50
+ const sortOptionsRef = useRef < HTMLDivElement > ( null ) ;
51
+ const sortButtonRef = useRef < HTMLButtonElement > ( null ) ;
47
52
48
53
// Load files on mount
49
54
useEffect ( ( ) => {
@@ -164,6 +169,9 @@ export const FileManagementPage = () => {
164
169
comparison = a . size - b . size ;
165
170
} else if ( sortBy === "type" ) {
166
171
comparison = a . type . localeCompare ( b . type ) ;
172
+ } else if ( sortBy === "updatedAt" ) {
173
+ // Sort by date - newest first by default
174
+ comparison = new Date ( b . updatedAt ) . getTime ( ) - new Date ( a . updatedAt ) . getTime ( ) ;
167
175
}
168
176
return sortDirection === "asc" ? comparison : - comparison ;
169
177
} ) ;
@@ -192,7 +200,8 @@ export const FileManagementPage = () => {
192
200
const fileData = {
193
201
name : file . name ,
194
202
type : file . type ,
195
- size : file . size
203
+ size : file . size ,
204
+ updatedAt : new Date ( )
196
205
} ;
197
206
198
207
// Save to database
@@ -287,6 +296,11 @@ export const FileManagementPage = () => {
287
296
return parseFloat ( ( bytes / Math . pow ( k , i ) ) . toFixed ( 2 ) ) + " " + sizes [ i ] ;
288
297
} ;
289
298
299
+ // Format date for display
300
+ const formatDate = ( date : Date ) : string => {
301
+ return new Date ( date ) . toLocaleString ( ) ;
302
+ } ;
303
+
290
304
// Get file icon based on type
291
305
const getFileIcon = ( file : FileData ) => {
292
306
const category = getFileCategory ( file ) ;
@@ -328,8 +342,30 @@ export const FileManagementPage = () => {
328
342
}
329
343
} ;
330
344
331
- // Toggle sort direction
332
- const handleSortChange = ( sortKey : "name" | "size" | "type" ) => {
345
+ // Handle click outside to close sort options dropdown
346
+ useEffect ( ( ) => {
347
+ const handleClickOutside = ( event : MouseEvent ) => {
348
+ if (
349
+ sortOptionsRef . current &&
350
+ ! sortOptionsRef . current . contains ( event . target as Node ) &&
351
+ sortButtonRef . current &&
352
+ ! sortButtonRef . current . contains ( event . target as Node )
353
+ ) {
354
+ setIsSortOptionsOpen ( false ) ;
355
+ }
356
+ } ;
357
+
358
+ document . addEventListener ( 'mousedown' , handleClickOutside ) ;
359
+ return ( ) => {
360
+ document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
361
+ } ;
362
+ } , [ ] ) ;
363
+
364
+ const toggleSortOptions = ( ) => {
365
+ setIsSortOptionsOpen ( ! isSortOptionsOpen ) ;
366
+ } ;
367
+
368
+ const handleSortChange = ( sortKey : "name" | "size" | "type" | "updatedAt" ) => {
333
369
if ( sortBy === sortKey ) {
334
370
// Toggle direction if same key
335
371
setSortDirection ( sortDirection === "asc" ? "desc" : "asc" ) ;
@@ -338,6 +374,7 @@ export const FileManagementPage = () => {
338
374
setSortBy ( sortKey ) ;
339
375
setSortDirection ( "asc" ) ;
340
376
}
377
+ setIsSortOptionsOpen ( false ) ;
341
378
} ;
342
379
343
380
const handleDeleteClick = ( file : FileData ) => {
@@ -475,19 +512,26 @@ export const FileManagementPage = () => {
475
512
{ /* Sort dropdown */ }
476
513
< div className = "relative ml-4" >
477
514
< button
515
+ ref = { sortButtonRef }
478
516
className = "flex items-center px-3 py-2 rounded-md input-box"
479
- onClick = { ( ) => {
480
- const options = document . getElementById ( 'sortOptions' ) ;
481
- options ?. classList . toggle ( 'hidden' ) ;
482
- } }
517
+ onClick = { toggleSortOptions }
483
518
>
484
519
< span className = "mr-2" >
485
520
{ t ( "fileManagement.sortBy" ) }
486
521
</ span >
487
522
< ChevronDown size = { 16 } />
488
523
</ button >
489
- < div id = "sortOptions" className = "absolute right-0 z-10 hidden mt-1 bg-white border rounded-md shadow-lg image-generation-popup" >
524
+ < div
525
+ ref = { sortOptionsRef }
526
+ className = { `absolute right-0 z-10 mt-1 bg-white border rounded-md shadow-lg image-generation-popup ${ ! isSortOptionsOpen ? 'hidden' : '' } ` }
527
+ >
490
528
< div className = "py-1" >
529
+ < button
530
+ className = { `flex items-center w-full px-4 py-2 ${ sortBy === 'updatedAt' ? 'image-generation-provider-selected' : 'image-generation-provider-item' } ` }
531
+ onClick = { ( ) => handleSortChange ( 'updatedAt' ) }
532
+ >
533
+ { t ( "fileManagement.updatedAt" ) } { sortBy === 'updatedAt' && ( sortDirection === 'asc' ? '↑' : '↓' ) }
534
+ </ button >
491
535
< button
492
536
className = { `flex items-center w-full px-4 py-2 ${ sortBy === 'name' ? 'image-generation-provider-selected' : 'image-generation-provider-item' } ` }
493
537
onClick = { ( ) => handleSortChange ( 'name' ) }
@@ -524,6 +568,7 @@ export const FileManagementPage = () => {
524
568
< th className = "px-4 py-3 text-left" > { t ( "fileManagement.fileName" ) } </ th >
525
569
< th className = "px-4 py-3 text-left" > { t ( "fileManagement.fileType" ) } </ th >
526
570
< th className = "px-4 py-3 text-left" > { t ( "fileManagement.fileSize" ) } </ th >
571
+ < th className = "px-4 py-3 text-left" > { t ( "fileManagement.updatedAt" ) } </ th >
527
572
< th className = "px-4 py-3 text-center" > { t ( "fileManagement.actions" ) } </ th >
528
573
</ tr >
529
574
</ thead >
@@ -541,6 +586,7 @@ export const FileManagementPage = () => {
541
586
</ td >
542
587
< td className = "px-4 py-3" > { file . type . split ( "/" ) . pop ( ) || "Unknown" } </ td >
543
588
< td className = "px-4 py-3" > { formatFileSize ( file . size ) } </ td >
589
+ < td className = "px-4 py-3" > { formatDate ( file . updatedAt ) } </ td >
544
590
< td className = "px-4 py-3" >
545
591
< div className = "flex items-center justify-center space-x-2" >
546
592
< button
0 commit comments