11import { AnimatePresence , motion } from 'framer-motion' ;
2- import React from 'react' ;
2+ import React , { useMemo , useCallback } from 'react' ;
33import { useSelector , useDispatch } from 'react-redux' ;
4+
45import styles from '../styles/modules/app.module.scss' ;
56import TodoItem from './TodoItem' ;
6- import { clearCompletedTodos } from '../slices/todoSlice' ; // ✅ import action
7+ import { clearCompletedTodos } from '../slices/todoSlice' ;
78
89const container = {
910 hidden : { opacity : 1 } ,
@@ -15,35 +16,36 @@ const container = {
1516 } ,
1617 } ,
1718} ;
19+
1820const child = {
1921 hidden : { y : 20 , opacity : 0 } ,
20- visible : {
21- y : 0 ,
22- opacity : 1 ,
23- } ,
22+ visible : { y : 0 , opacity : 1 } ,
2423} ;
2524
2625function AppContent ( ) {
2726 const dispatch = useDispatch ( ) ;
27+
2828 const todoList = useSelector ( ( state ) => state . todo . todoList ) ;
2929 const filterStatus = useSelector ( ( state ) => state . todo . filterStatus ) ;
3030
31- const sortedTodoList = [ ...todoList ] ;
32- sortedTodoList . sort ( ( a , b ) => new Date ( b . time ) - new Date ( a . time ) ) ;
31+ // ✅ Optimized sorting + filtering
32+ const filteredTodoList = useMemo ( ( ) => {
33+ return [ ...todoList ]
34+ . sort ( ( a , b ) => new Date ( b . time ) - new Date ( a . time ) )
35+ . filter ( ( item ) =>
36+ filterStatus === 'all' ? true : item . status === filterStatus
37+ ) ;
38+ } , [ todoList , filterStatus ] ) ;
3339
34- const filteredTodoList = sortedTodoList . filter ( ( item ) => {
35- if ( filterStatus === 'all' ) {
36- return true ;
37- }
38- return item . status === filterStatus ;
39- } ) ;
40+ const hasCompleted = useMemo (
41+ ( ) => todoList . some ( ( todo ) => todo . status === 'complete' ) ,
42+ [ todoList ]
43+ ) ;
4044
41- // ✅ Handler for clearing completed todos
42- const handleClearCompleted = ( ) => {
45+ // ✅ Stable handler
46+ const handleClearCompleted = useCallback ( ( ) => {
4347 dispatch ( clearCompletedTodos ( ) ) ;
44- } ;
45-
46- const hasCompleted = todoList . some ( ( todo ) => todo . status === 'complete' ) ;
48+ } , [ dispatch ] ) ;
4749
4850 return (
4951 < motion . div
@@ -52,31 +54,20 @@ function AppContent() {
5254 initial = "hidden"
5355 animate = "visible"
5456 >
55- { /* ✅ Clear Completed button */ }
57+ { /* Clear Completed Button */ }
5658 { hasCompleted && (
57- < div style = { { textAlign : 'right' , marginBottom : '1rem' } } >
59+ < div className = { styles . clearWrapper } >
5860 < button
61+ className = { styles . clearButton }
5962 onClick = { handleClearCompleted }
60- style = { {
61- backgroundColor : '#ff5c5c' ,
62- border : 'none' ,
63- color : 'white' ,
64- padding : '0.5rem 1rem' ,
65- borderRadius : '8px' ,
66- cursor : 'pointer' ,
67- fontWeight : '500' ,
68- transition : 'background 0.2s' ,
69- } }
70- onMouseOver = { ( e ) => ( e . target . style . backgroundColor = '#ff3b3b' ) }
71- onMouseOut = { ( e ) => ( e . target . style . backgroundColor = '#ff5c5c' ) }
7263 >
7364 Clear Completed
7465 </ button >
7566 </ div >
7667 ) }
7768
7869 < AnimatePresence >
79- { filteredTodoList && filteredTodoList . length > 0 ? (
70+ { filteredTodoList . length > 0 ? (
8071 filteredTodoList . map ( ( todo ) => (
8172 < TodoItem key = { todo . id } todo = { todo } />
8273 ) )
@@ -90,4 +81,4 @@ function AppContent() {
9081 ) ;
9182}
9283
93- export default AppContent ;
84+ export default AppContent ;
0 commit comments