@@ -17,6 +17,9 @@ import { PrimaryButton } from 'topcoder-react-ui-kit';
1717import { Link } from 'topcoder-react-utils' ;
1818import { COMPETITION_TRACKS } from 'utils/tc' ;
1919import { phaseEndDate } from 'utils/challenge-listing/helper' ;
20+ import {
21+ getTimeLeft ,
22+ } from 'utils/challenge-detail/helper' ;
2023
2124import LeftArrow from 'assets/images/arrow-prev.svg' ;
2225
@@ -30,6 +33,10 @@ import TabSelector from './TabSelector';
3033
3134import style from './style.scss' ;
3235
36+ /* Holds day and hour range in ms. */
37+ const HOUR_MS = 60 * 60 * 1000 ;
38+ const DAY_MS = 24 * HOUR_MS ;
39+
3340export default function ChallengeHeader ( props ) {
3441 const {
3542 isLoggedIn,
@@ -108,6 +115,10 @@ export default function ChallengeHeader(props) {
108115 registrationEnded = ! regPhase . isOpen ;
109116 }
110117
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+
111122 const trackLower = track ? track . replace ( ' ' , '-' ) . toLowerCase ( ) : 'design' ;
112123
113124 const eventNames = ( events || [ ] ) . map ( ( event => ( event . eventName || '' ) . toUpperCase ( ) ) ) ;
@@ -128,6 +139,31 @@ export default function ChallengeHeader(props) {
128139 */
129140 const hasSubmissions = ! _ . isEmpty ( mySubmissions ) ;
130141
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+
131167 let relevantPhases = [ ] ;
132168
133169 if ( showDeadlineDetail ) {
@@ -177,31 +213,57 @@ export default function ChallengeHeader(props) {
177213 || phaseEndDate ( p ) . getTime ( ) < endPhaseDate ) ) ;
178214 relevantPhases . push ( {
179215 id : - 1 ,
180- name : 'Winners' ,
216+ name : 'Winners Announced ' ,
181217 isOpen : false ,
182218 actualEndDate : endPhaseDate ,
183219 scheduledEndDate : endPhaseDate ,
184220 } ) ;
185221 } 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();
189224 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+ } ) ;
200233 }
201234 }
202235
203236 const checkpointCount = checkpoints && checkpoints . numberOfPassedScreeningSubmissions ;
204237
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 'draft' :
248+ nextDeadlineMsg = (
249+ < div styleName = "draft" >
250+ In Draft
251+ </ div >
252+ ) ;
253+ break ;
254+ default :
255+ // nextDeadlineMsg = (
256+ // <div>
257+ // Status:
258+ // ‌
259+ // <span styleName="deadline-highlighted">
260+ // {_.upperFirst(_.lowerCase(status))}
261+ // </span>
262+ // </div>
263+ // );
264+ break ;
265+ }
266+
205267 // Legacy MMs have a roundId field, but new MMs do not.
206268 // This is used to disable registration/submission for legacy MMs.
207269 const isLegacyMM = isMM ( challenge ) && Boolean ( challenge . roundId ) ;
@@ -382,7 +444,18 @@ export default function ChallengeHeader(props) {
382444 < div styleName = "deadlines-view" >
383445 < div styleName = { `deadlines-overview ${ showDeadlineDetail ? 'opened' : '' } ` } >
384446 < div styleName = "deadlines-overview-text" >
385- Competition Timeline
447+ { nextDeadlineMsg }
448+ {
449+ ( status || '' ) . toLowerCase ( ) === 'active'
450+ && (
451+ < div styleName = "current-phase" >
452+ { currentPhases && `${ currentPhases . name } Ends: ` }
453+ < span styleName = "deadline-highlighted" >
454+ { timeDiff . text }
455+ </ span >
456+ </ div >
457+ )
458+ }
386459 </ div >
387460 < a
388461 onClick = { onToggleDeadlines }
@@ -462,7 +535,6 @@ ChallengeHeader.propTypes = {
462535 timelineTemplateId : PT . string ,
463536 reliabilityBonus : PT . any ,
464537 userDetails : PT . any ,
465- currentPhases : PT . any ,
466538 numOfRegistrants : PT . any ,
467539 numOfCheckpointSubmissions : PT . any ,
468540 numOfSubmissions : PT . any ,
0 commit comments