11import React , {
2- useState , useMemo , useEffect , useRef ,
2+ useState , useMemo , useEffect , useRef , useCallback ,
33} from 'react' ;
44import { Link } from 'react-router-dom' ;
55import {
@@ -76,18 +76,25 @@ const Dashboard = () => {
7676 const showFiltersKey = 'lp_dashboard_showFilters' ;
7777 const selectedContentTypeKey = 'lp_dashboard_contentType' ;
7878 const selectedStatusesKey = 'lp_dashboard_selectedStatuses' ;
79+ const selectedDateStatusesKey = 'lp_dashboard_selectedDateStatuses' ;
7980
8081 const [ showFilters , setShowFilters ] = useState ( ( ) => localStorage . getItem ( showFiltersKey ) === 'true' ) ;
8182 const [ selectedContentType , setSelectedContentType ] = useState ( ( ) => localStorage . getItem ( selectedContentTypeKey ) || 'All' ) ;
8283 const [ selectedStatuses , setSelectedStatuses ] = useState (
8384 ( ) => JSON . parse ( localStorage . getItem ( selectedStatusesKey ) ) || [ ] ,
8485 ) ;
86+ const [ selectedDateStatuses , setSelectedDateStatuses ] = useState (
87+ ( ) => JSON . parse ( localStorage . getItem ( selectedDateStatusesKey ) ) || [ ] ,
88+ ) ;
8589
8690 useEffect ( ( ) => { localStorage . setItem ( showFiltersKey , showFilters . toString ( ) ) ; } , [ showFilters ] ) ;
8791 useEffect ( ( ) => {
8892 localStorage . setItem ( selectedContentTypeKey , selectedContentType . toString ( ) ) ;
8993 } , [ selectedContentType ] ) ;
9094 useEffect ( ( ) => { localStorage . setItem ( selectedStatusesKey , JSON . stringify ( selectedStatuses ) ) ; } , [ selectedStatuses ] ) ;
95+ useEffect ( ( ) => {
96+ localStorage . setItem ( selectedDateStatusesKey , JSON . stringify ( selectedDateStatuses ) ) ;
97+ } , [ selectedDateStatuses ] ) ;
9198
9299 const handleStatusChange = ( status , isChecked ) => {
93100 setSelectedStatuses ( prev => {
@@ -98,60 +105,78 @@ const Dashboard = () => {
98105 } ) ;
99106 } ;
100107
108+ const handleDateStatusChange = ( dateStatus , isChecked ) => {
109+ setSelectedDateStatuses ( prev => {
110+ if ( isChecked ) {
111+ return [ ...prev , dateStatus ] ;
112+ }
113+ return prev . filter ( s => s !== dateStatus ) ;
114+ } ) ;
115+ } ;
116+
101117 const handleClearFilters = ( ) => {
102118 setSelectedContentType ( 'All' ) ;
103119 setSelectedStatuses ( [ ] ) ;
120+ setSelectedDateStatuses ( [ ] ) ;
104121 } ;
105122
106123 const activeFiltersCount = useMemo (
107- ( ) => ( selectedContentType !== 'All' ) + selectedStatuses . length ,
108- [ selectedContentType , selectedStatuses ] ,
124+ ( ) => ( selectedContentType !== 'All' ) + selectedStatuses . length + selectedDateStatuses . length ,
125+ [ selectedContentType , selectedStatuses , selectedDateStatuses ] ,
109126 ) ;
110127
128+ const getItemDates = ( item ) => {
129+ if ( item . type === 'course' ) {
130+ return {
131+ startDate : item . startDate ? new Date ( item . startDate ) : null ,
132+ endDate : item . endDate ? new Date ( item . endDate ) : null ,
133+ } ;
134+ }
135+ if ( item . type === 'learning_path' ) {
136+ return {
137+ startDate : item . minDate ? new Date ( item . minDate ) : null ,
138+ endDate : item . maxDate ? new Date ( item . maxDate ) : null ,
139+ } ;
140+ }
141+ return { startDate : null , endDate : null } ;
142+ } ;
143+
144+ const getDateStatus = useCallback ( ( item ) => {
145+ const currentDate = new Date ( ) ;
146+ const { startDate, endDate } = getItemDates ( item ) ;
147+
148+ if ( startDate && startDate > currentDate ) {
149+ return 'Upcoming' ;
150+ }
151+ if ( endDate && endDate < currentDate ) {
152+ return 'Ended' ;
153+ }
154+ return 'Open' ;
155+ } , [ ] ) ;
156+
111157 const filteredItems = useMemo ( ( ) => items . filter ( item => {
112158 const typeMatch = selectedContentType === 'All'
113- || ( selectedContentType === 'course' && item . type === 'course' )
114- || ( selectedContentType === 'learning_path' && item . type === 'learning_path' ) ;
159+ || ( selectedContentType === 'course' && item . type === 'course' )
160+ || ( selectedContentType === 'learning_path' && item . type === 'learning_path' ) ;
115161 const statusMatch = selectedStatuses . length === 0 || selectedStatuses . includes ( item . status ) ;
162+ const dateStatusMatch = selectedDateStatuses . length === 0 || selectedDateStatuses . includes ( getDateStatus ( item ) ) ;
116163 const searchMatch = searchQuery === ''
117164 || ( item . displayName && item . displayName . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) )
118165 || ( item . name && item . name . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ) ;
119- return typeMatch && statusMatch && searchMatch ;
120- } ) , [ items , selectedContentType , selectedStatuses , searchQuery ] ) ;
166+ return typeMatch && statusMatch && dateStatusMatch && searchMatch ;
167+ } ) , [ items , selectedContentType , selectedStatuses , selectedDateStatuses , searchQuery , getDateStatus ] ) ;
121168
122169 const sortedItems = useMemo ( ( ) => {
123- const currentDate = new Date ( ) ;
124-
125- const getStartDateCategory = ( item ) => {
126- let startDate = null ;
127- let endDate = null ;
128-
129- if ( item . type === 'course' ) {
130- startDate = item . startDate ? new Date ( item . startDate ) : null ;
131- endDate = item . endDate ? new Date ( item . endDate ) : null ;
132- } else if ( item . type === 'learning_path' ) {
133- startDate = item . minDate ? new Date ( item . minDate ) : null ;
134- endDate = item . maxDate ? new Date ( item . maxDate ) : null ;
135- }
136-
137- if ( startDate && startDate > currentDate ) {
138- return 1 ; // Not started.
139- }
140- if ( endDate && endDate < currentDate ) {
141- return 3 ; // Ended.
142- }
143- return 2 ; // Available.
144- } ;
145-
146170 const statusOrder = { 'not started' : 1 , 'in progress' : 2 , completed : 3 } ;
171+ const dateStatusOrder = { Upcoming : 1 , Open : 2 , Ended : 3 } ;
147172
148173 return [ ...filteredItems ] . sort ( ( a , b ) => {
149174 // 1. Sort by start date category.
150- const startCategoryA = getStartDateCategory ( a ) ;
151- const startCategoryB = getStartDateCategory ( b ) ;
175+ const dateStatusA = dateStatusOrder [ getDateStatus ( a ) ] || 999 ;
176+ const dateStatusB = dateStatusOrder [ getDateStatus ( b ) ] || 999 ;
152177
153- if ( startCategoryA !== startCategoryB ) {
154- return startCategoryA - startCategoryB ;
178+ if ( dateStatusA !== dateStatusB ) {
179+ return dateStatusA - dateStatusB ;
155180 }
156181
157182 // 2. Sort by progress status.
@@ -168,7 +193,7 @@ const Dashboard = () => {
168193
169194 return nameA . localeCompare ( nameB ) ;
170195 } ) ;
171- } , [ filteredItems ] ) ;
196+ } , [ filteredItems , getDateStatus ] ) ;
172197
173198 const PAGE_SIZE = getConfig ( ) . DASHBOARD_PAGE_SIZE || 10 ;
174199 const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
@@ -189,7 +214,7 @@ const Dashboard = () => {
189214 // Reset pagination when using filters or search.
190215 useEffect ( ( ) => {
191216 setCurrentPage ( 1 ) ;
192- } , [ searchQuery , selectedContentType , selectedStatuses ] ) ;
217+ } , [ searchQuery , selectedContentType , selectedStatuses , selectedDateStatuses ] ) ;
193218
194219 return (
195220 < >
@@ -221,6 +246,8 @@ const Dashboard = () => {
221246 onSelectContentType = { setSelectedContentType }
222247 selectedStatuses = { selectedStatuses }
223248 onChangeStatus = { handleStatusChange }
249+ selectedDateStatuses = { selectedDateStatuses }
250+ onChangeDateStatus = { handleDateStatusChange }
224251 onClose = { ( ) => setShowFilters ( false ) }
225252 isSmall = { isSmall }
226253 onClearAll = { handleClearFilters }
0 commit comments