@@ -13,6 +13,7 @@ export type Task = {
1313export const TaskList : React . FC = ( ) => {
1414 const [ tasks , setTasks ] = useLocalStorage < Task [ ] > ( 'tasks' , [ ] ) ;
1515 const [ filter , setFilter ] = useState < 'all' | 'active' | 'completed' > ( 'all' ) ;
16+ const [ sortDirection , setSortDirection ] = useState < 'asc' | 'desc' | null > ( null ) ;
1617
1718 const addTask = useCallback ( ( text : string ) => {
1819 const newTask : Task = {
@@ -36,21 +37,48 @@ export const TaskList: React.FC = () => {
3637 setTasks ( prevTasks => prevTasks . filter ( task => task . id !== id ) ) ;
3738 } , [ setTasks ] ) ;
3839
39- const filteredTasks = tasks . filter ( task => {
40- if ( filter === 'active' ) return ! task . completed ;
41- if ( filter === 'completed' ) return task . completed ;
42- return true ;
43- } ) ;
40+ const sortedTasks = sortDirection
41+ ? tasks . sort ( tasksSortFn ( sortDirection ) )
42+ : tasks ;
43+
44+ const filteredTasks = sortedTasks . filter ( filterTasksFn ( filter ) ) ;
4445
4546 const activeCount = tasks . filter ( t => ! t . completed ) . length ;
4647
48+ const handleSortToggle = ( ) => {
49+ if ( sortDirection === null ) {
50+ setSortDirection ( 'asc' ) ;
51+ } else if ( sortDirection === 'asc' ) {
52+ setSortDirection ( 'desc' ) ;
53+ } else {
54+ setSortDirection ( null ) ;
55+ }
56+ } ;
57+
58+ const getSortButtonText = ( ) => {
59+ if ( sortDirection === 'asc' ) return 'Sort ↑' ;
60+ if ( sortDirection === 'desc' ) return 'Sort ↓' ;
61+ return 'Sort' ;
62+ } ;
63+
64+ const renderTasks = ( tasksToRender : Task [ ] ) => (
65+ tasksToRender . map ( ( task , index ) => (
66+ < TaskItem
67+ key = { index }
68+ task = { task }
69+ onToggle = { toggleTask }
70+ onDelete = { deleteTask }
71+ />
72+ ) )
73+ ) ;
74+
4775 return (
4876 < div style = { { maxWidth : '600px' , margin : '0 auto' , padding : '20px' } } >
4977 < h1 > Task Manager</ h1 >
5078
5179 < AddTaskForm onAddTask = { addTask } />
5280
53- < div style = { { margin : '20px 0' } } >
81+ < div style = { { margin : '20px 0' , display : 'flex' , gap : '10px' , alignItems : 'center' } } >
5482 < button
5583 onClick = { ( ) => setFilter ( 'all' ) }
5684 style = { { fontWeight : filter === 'all' ? 'bold' : 'normal' } }
@@ -59,32 +87,59 @@ export const TaskList: React.FC = () => {
5987 </ button >
6088 < button
6189 onClick = { ( ) => setFilter ( 'active' ) }
62- style = { { fontWeight : filter === 'active' ? 'bold' : 'normal' , marginLeft : '10px' } }
90+ style = { { fontWeight : filter === 'active' ? 'bold' : 'normal' } }
6391 >
6492 Active ({ activeCount } )
6593 </ button >
6694 < button
6795 onClick = { ( ) => setFilter ( 'completed' ) }
68- style = { { fontWeight : filter === 'completed' ? 'bold' : 'normal' , marginLeft : '10px' } }
96+ style = { { fontWeight : filter === 'completed' ? 'bold' : 'normal' } }
6997 >
7098 Completed ({ tasks . length - activeCount } )
7199 </ button >
100+ < div style = { { marginLeft : 'auto' } } >
101+ < button
102+ onClick = { handleSortToggle }
103+ style = { {
104+ padding : '5px 15px' ,
105+ background : sortDirection ? '#2196F3' : '#ddd' ,
106+ color : sortDirection ? 'white' : '#666' ,
107+ border : 'none' ,
108+ borderRadius : '4px' ,
109+ cursor : 'pointer' ,
110+ fontWeight : sortDirection ? 'bold' : 'normal' ,
111+ } }
112+ >
113+ { getSortButtonText ( ) }
114+ </ button >
115+ </ div >
72116 </ div >
73117
74118 < div >
75119 { filteredTasks . length === 0 ? (
76120 < p > No tasks to show</ p >
77121 ) : (
78- filteredTasks . map ( task => (
79- < TaskItem
80- key = { task . id }
81- task = { task }
82- onToggle = { toggleTask }
83- onDelete = { deleteTask }
84- />
85- ) )
122+ renderTasks ( filteredTasks )
86123 ) }
87124 </ div >
88125 </ div >
89126 ) ;
90127} ;
128+
129+ const filterTasksFn = ( filter : 'all' | 'active' | 'completed' ) => ( task : Task ) => {
130+ if ( filter === 'active' ) return task . completed ;
131+ if ( filter === 'completed' ) return task . completed ;
132+ return true ;
133+ } ;
134+
135+ const tasksSortFn = ( direction : 'asc' | 'desc' | null ) => ( a : Task , b : Task ) => {
136+ const aText = a . text . toLowerCase ( ) ;
137+ const bText = b . text . toLowerCase ( ) ;
138+
139+ if ( direction === 'asc' ) {
140+ return aText > bText ? 1 : - 1 ;
141+ } else if ( direction === 'desc' ) {
142+ return bText > aText ? 1 : - 1 ;
143+ }
144+ return 0 ;
145+ } ;
0 commit comments