@@ -17,6 +17,9 @@ import { PrimaryButton } from 'topcoder-react-ui-kit';
17
17
import { Link } from 'topcoder-react-utils' ;
18
18
import { COMPETITION_TRACKS } from 'utils/tc' ;
19
19
import { phaseEndDate } from 'utils/challenge-listing/helper' ;
20
+ import {
21
+ getTimeLeft ,
22
+ } from 'utils/challenge-detail/helper' ;
20
23
21
24
import LeftArrow from 'assets/images/arrow-prev.svg' ;
22
25
@@ -30,6 +33,10 @@ import TabSelector from './TabSelector';
30
33
31
34
import style from './style.scss' ;
32
35
36
+ /* Holds day and hour range in ms. */
37
+ const HOUR_MS = 60 * 60 * 1000 ;
38
+ const DAY_MS = 24 * HOUR_MS ;
39
+
33
40
export default function ChallengeHeader ( props ) {
34
41
const {
35
42
isLoggedIn,
@@ -108,6 +115,10 @@ export default function ChallengeHeader(props) {
108
115
registrationEnded = ! regPhase . isOpen ;
109
116
}
110
117
118
+ const currentPhases = challenge . phases
119
+ . filter ( p => p . name !== 'Registration' && p . isOpen )
120
+ . sort ( ( a , b ) => moment ( a . scheduledEndDate ) . diff ( b . scheduledEndDate ) ) [ 0 ] ;
121
+
111
122
const trackLower = track ? track . replace ( ' ' , '-' ) . toLowerCase ( ) : 'design' ;
112
123
113
124
const eventNames = ( events || [ ] ) . map ( ( event => ( event . eventName || '' ) . toUpperCase ( ) ) ) ;
@@ -128,6 +139,31 @@ export default function ChallengeHeader(props) {
128
139
*/
129
140
const hasSubmissions = ! _ . isEmpty ( mySubmissions ) ;
130
141
142
+ const openPhases = sortedAllPhases . filter ( p => p . isOpen ) ;
143
+ let nextPhase = openPhases [ 0 ] ;
144
+ if ( hasRegistered && openPhases [ 0 ] && openPhases [ 0 ] . name === 'Registration' ) {
145
+ nextPhase = openPhases [ 1 ] || { } ;
146
+ }
147
+
148
+ const deadlineEnd = moment ( nextPhase && phaseEndDate ( nextPhase ) ) ;
149
+ const currentTime = moment ( ) ;
150
+
151
+ const timeDiff = getTimeLeft ( currentPhases , 'to go' ) ;
152
+
153
+ if ( ! timeDiff . late ) {
154
+ timeDiff . text = timeDiff . text . replace ( 'to go' , '' ) ;
155
+ }
156
+
157
+ let timeLeft = deadlineEnd . isAfter ( currentTime )
158
+ ? deadlineEnd . diff ( currentTime ) : 0 ;
159
+
160
+ let format ;
161
+ if ( timeLeft > DAY_MS ) format = 'D[d] H[h]' ;
162
+ else if ( timeLeft > HOUR_MS ) format = 'H[h] m[min]' ;
163
+ else format = 'm[min] s[s]' ;
164
+
165
+ timeLeft = moment . duration ( timeLeft ) . format ( format ) ;
166
+
131
167
let relevantPhases = [ ] ;
132
168
133
169
if ( showDeadlineDetail ) {
@@ -177,31 +213,52 @@ export default function ChallengeHeader(props) {
177
213
|| phaseEndDate ( p ) . getTime ( ) < endPhaseDate ) ) ;
178
214
relevantPhases . push ( {
179
215
id : - 1 ,
180
- name : 'Winners' ,
216
+ name : 'Winners Announced ' ,
181
217
isOpen : false ,
182
218
actualEndDate : endPhaseDate ,
183
219
scheduledEndDate : endPhaseDate ,
184
220
} ) ;
185
221
} else if ( relevantPhases . length > 1 ) {
186
- const lastPhase = relevantPhases [ relevantPhases . length - 1 ] ;
187
- const lastPhaseTime = phaseEndDate ( lastPhase ) . getTime ( ) ;
188
-
222
+ // const lastPhase = relevantPhases[relevantPhases.length - 1];
223
+ // const lastPhaseTime = phaseEndDate(lastPhase).getTime();
189
224
const appealsEndDate = phaseEndDate ( sortedAllPhases [ sortedAllPhases . length - 1 ] ) ;
190
- const appealsEnd = appealsEndDate . getTime ( ) ;
191
- if ( lastPhaseTime < appealsEnd ) {
192
- relevantPhases . push ( {
193
- id : - 1 ,
194
- name : 'Winners' ,
195
- isOpen : false ,
196
- actualEndDate : appealsEndDate ,
197
- scheduledEndDate : appealsEndDate ,
198
- } ) ;
199
- }
225
+ // const appealsEnd = appealsEndDate.getTime();
226
+ relevantPhases . push ( {
227
+ id : - 1 ,
228
+ name : 'Winners Announced' ,
229
+ isOpen : false ,
230
+ actualEndDate : appealsEndDate ,
231
+ scheduledEndDate : appealsEndDate ,
232
+ } ) ;
200
233
}
201
234
}
202
235
203
236
const checkpointCount = checkpoints && checkpoints . numberOfPassedScreeningSubmissions ;
204
237
238
+ let nextDeadlineMsg ;
239
+ switch ( ( status || '' ) . toLowerCase ( ) ) {
240
+ case 'completed' :
241
+ nextDeadlineMsg = (
242
+ < div styleName = "completed" >
243
+ The challenge is finished.
244
+ </ div >
245
+ ) ;
246
+ break ;
247
+ case 'active' :
248
+ break ;
249
+ default :
250
+ nextDeadlineMsg = (
251
+ < div >
252
+ Status:
253
+ ‌
254
+ < span styleName = "deadline-highlighted" >
255
+ { _ . upperFirst ( _ . lowerCase ( status ) ) }
256
+ </ span >
257
+ </ div >
258
+ ) ;
259
+ break ;
260
+ }
261
+
205
262
// Legacy MMs have a roundId field, but new MMs do not.
206
263
// This is used to disable registration/submission for legacy MMs.
207
264
const isLegacyMM = isMM ( challenge ) && Boolean ( challenge . roundId ) ;
@@ -382,7 +439,18 @@ export default function ChallengeHeader(props) {
382
439
< div styleName = "deadlines-view" >
383
440
< div styleName = { `deadlines-overview ${ showDeadlineDetail ? 'opened' : '' } ` } >
384
441
< div styleName = "deadlines-overview-text" >
385
- Competition Timeline
442
+ { nextDeadlineMsg }
443
+ {
444
+ ( status || '' ) . toLowerCase ( ) === 'active'
445
+ && (
446
+ < div styleName = "current-phase" >
447
+ { currentPhases && `${ currentPhases . name } Ends: ` }
448
+ < span styleName = "deadline-highlighted" >
449
+ { timeDiff . text }
450
+ </ span >
451
+ </ div >
452
+ )
453
+ }
386
454
</ div >
387
455
< a
388
456
onClick = { onToggleDeadlines }
@@ -462,7 +530,6 @@ ChallengeHeader.propTypes = {
462
530
timelineTemplateId : PT . string ,
463
531
reliabilityBonus : PT . any ,
464
532
userDetails : PT . any ,
465
- currentPhases : PT . any ,
466
533
numOfRegistrants : PT . any ,
467
534
numOfCheckpointSubmissions : PT . any ,
468
535
numOfSubmissions : PT . any ,
0 commit comments