From 5e519b49b06ca45585d44adf1e62fa2cad72a8ac Mon Sep 17 00:00:00 2001 From: lunarkid <4476442+dedywahyudi@users.noreply.github.com> Date: Sun, 14 Aug 2022 11:12:29 +0700 Subject: [PATCH 1/6] fix: new challenge timeline --- .circleci/config.yml | 2 +- src/assets/images/icon-arrow-down.svg | 12 +- src/assets/images/icon-arrow-up.svg | 12 +- .../Header/DeadlinesPanel/Card/index.jsx | 68 +++++---- .../Header/DeadlinesPanel/Card/style.scss | 133 +++++++++++++----- .../Header/DeadlinesPanel/index.jsx | 70 ++++++--- .../Header/DeadlinesPanel/style.scss | 18 ++- .../challenge-detail/Header/index.jsx | 78 +--------- .../challenge-detail/Header/style.scss | 71 ++-------- .../containers/challenge-detail/index.jsx | 2 +- 10 files changed, 234 insertions(+), 232 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f374780470..d1f864bf7b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -370,7 +370,7 @@ workflows: filters: branches: only: - - social-share-updates + - reskin-challenge-details # This is stage env for production QA releases - "build-prod-staging": context : org-global diff --git a/src/assets/images/icon-arrow-down.svg b/src/assets/images/icon-arrow-down.svg index 0562fc97c7..8e34056812 100644 --- a/src/assets/images/icon-arrow-down.svg +++ b/src/assets/images/icon-arrow-down.svg @@ -1,9 +1,3 @@ - - \ No newline at end of file + + + diff --git a/src/assets/images/icon-arrow-up.svg b/src/assets/images/icon-arrow-up.svg index ad29ee85ae..b4fa8c8b92 100644 --- a/src/assets/images/icon-arrow-up.svg +++ b/src/assets/images/icon-arrow-up.svg @@ -1,9 +1,3 @@ - - \ No newline at end of file + + + diff --git a/src/shared/components/challenge-detail/Header/DeadlinesPanel/Card/index.jsx b/src/shared/components/challenge-detail/Header/DeadlinesPanel/Card/index.jsx index d58cfb4a75..dc2a8a3337 100644 --- a/src/shared/components/challenge-detail/Header/DeadlinesPanel/Card/index.jsx +++ b/src/shared/components/challenge-detail/Header/DeadlinesPanel/Card/index.jsx @@ -16,38 +16,58 @@ import './style.scss'; const FORMAT_YEAR = 'MMM DD, YYYY'; const TIME = 'HH:mm'; -export default function Card({ past, time, title }) { - const time2 = moment(time); - const past2 = past === null ? time2.isBefore(moment()) : past; +export default function Card({ + title, start, end, showRange, +}) { + const startMoment = moment(start); + const endMoment = moment(end); + const past = endMoment.isBefore(moment()); return ( -
+

{title}

-
-

- { past2 ? : } - - {time2.format(FORMAT_YEAR)} - -

-

- { past2 ? : } - - {time2.format(TIME)} - -

-
+

+ {showRange ? ( +

+ Starts +

+ { past ? : } + + {startMoment.format(FORMAT_YEAR)} + +

+

+ { past ? : } + + {startMoment.format(TIME)} + +

+
+ ) : null} +
+ {showRange ? Ends : null} +

+ { past ? : } + + {endMoment.format(FORMAT_YEAR)} + +

+

+ { past ? : } + + {endMoment.format(TIME)} + +

+
+

); } -Card.defaultProps = { - past: null, -}; - Card.propTypes = { - past: PT.bool, title: PT.string.isRequired, - time: PT.string.isRequired, + start: PT.string.isRequired, + end: PT.string.isRequired, + showRange: PT.bool.isRequired, }; diff --git a/src/shared/components/challenge-detail/Header/DeadlinesPanel/Card/style.scss b/src/shared/components/challenge-detail/Header/DeadlinesPanel/Card/style.scss index d2ed40c6c5..575418ac4e 100644 --- a/src/shared/components/challenge-detail/Header/DeadlinesPanel/Card/style.scss +++ b/src/shared/components/challenge-detail/Header/DeadlinesPanel/Card/style.scss @@ -2,42 +2,76 @@ .open { color: $tc-white; + + svg { + path { + fill: $tc-white; + } + } } .past { color: #aaa; + + svg { + path { + fill: #aaa; + } + } } .open, .past { @include roboto-regular; - margin-bottom: 10px; - padding: 0 20px; - border-left: 1px solid $tc-gray-40; + flex: 0 0 auto; + position: relative; + padding: 0 24px; + min-width: 200px; + margin-bottom: 24px; + + &:not(:last-child)::after { + content: ''; + position: absolute; + right: 0; + top: 0; + width: 2px; + height: 100%; + border-radius: 1px; + background-color: #767676; + } @include xs-to-md { - border-left: none; - border-bottom: 1px solid $tc-gray-40; - padding-top: 16px; - padding-bottom: 16px; + padding: 16px 0; + margin-bottom: 0; - &:last-child { - border-bottom: none; + &:not(:last-child)::after { + height: 2px; + width: 100%; + top: unset; + bottom: 0; } } - &:first-child { - border-left: none; + svg { + height: 13.13px; + width: 13.13px; } } .date { - font-size: 20px; - letter-spacing: -0.5px; - line-height: 25px; - font-weight: 500; - margin-top: 7px; + @include roboto-medium; + + display: flex; + align-items: center; + font-size: 16px; + line-height: 24px; + margin-bottom: 4px; + + @include xs-to-md { + font-size: 14px; + line-height: 20px; + } span { margin-left: 8px; @@ -45,38 +79,61 @@ } .time { - font-size: 20px; - letter-spacing: -0.5px; - line-height: 25px; - font-weight: 500; - margin-top: 4px; + @include roboto-medium; + + display: flex; + align-items: center; + font-size: 16px; + line-height: 24px; + + @include xs-to-md { + font-size: 14px; + line-height: 20px; + } span { margin-left: 8px; } } -.open .date { - color: $tc-white; +.title { + @include roboto-bold; - svg { - path: { - fill: $tc-white; - } + font-size: 12px; + letter-spacing: 1px; + line-height: 16px; + margin-bottom: 16px; + text-transform: uppercase; + + @include xs-to-md { + font-size: 10px; + line-height: 12px; + margin-bottom: 20px; } } -.past .date { color: #aaa; } -.title { - font-size: 12px; - font-weight: 700; - letter-spacing: 0; - color: #fff; - line-height: 15px; - margin-bottom: 5px; - text-transform: uppercase; +.sections { + display: flex; + flex-direction: column; + gap: 16px; + + @include xs-to-md { + flex-direction: row; + gap: 24px; + } } -.past .title { - color: $tc-gray-40; +.section { + @include xs-to-md { + flex: 1; + } +} + +.section-title { + @include roboto-medium; + + display: inline-block; + font-size: 11px; + line-height: 10px; + margin-bottom: 4px; } diff --git a/src/shared/components/challenge-detail/Header/DeadlinesPanel/index.jsx b/src/shared/components/challenge-detail/Header/DeadlinesPanel/index.jsx index 710a5bf509..081d4f88b3 100644 --- a/src/shared/components/challenge-detail/Header/DeadlinesPanel/index.jsx +++ b/src/shared/components/challenge-detail/Header/DeadlinesPanel/index.jsx @@ -11,29 +11,65 @@ import Card from './Card'; import './style.scss'; export default function DeadlinesPanel({ deadlines }) { - /* Calculates challenge start time. */ - let start = deadlines[0] || {}; - start = phaseStartDate(start); - const started = moment(start).isBefore(); + let hasSubmissionPhase = false; + + const getCardProps = (deadline, index) => { + let { name } = deadline; + let showRange = true; + name = name.replace(/\bCheckpoint\b/, 'Checkpoints'); + if (/.+submission/i.test(name)) { + hasSubmissionPhase = true; + name = name.replace(/submission/i, 'Due'); + showRange = false; + } else { + switch (name) { + case 'Submission': + name = hasSubmissionPhase ? 'Finals Due' : 'Submission Due'; + showRange = false; + break; + case 'Review': + name = hasSubmissionPhase ? 'Finals Review' : name; + break; + case 'Appeals': + name = hasSubmissionPhase ? 'Appeals Due' : name; + showRange = false; + break; + default: + } + } + if (index === deadlines.length - 1) { + name = 'Winners Announced'; + showRange = false; + } + + const start = phaseStartDate(deadline); + const end = phaseEndDate(deadline); + + return { + name, start, end, showRange, + }; + }; return ( -
+

Timezone: {moment.tz.guess()}

- - { deadlines.map((d, index) => ( - - ))} + { deadlines.map((d, index) => { + const { + name, start, end, showRange, + } = getCardProps(d, index); + return ( + + ); + })}
); } diff --git a/src/shared/components/challenge-detail/Header/DeadlinesPanel/style.scss b/src/shared/components/challenge-detail/Header/DeadlinesPanel/style.scss index 8f814362a1..982af5ffb6 100644 --- a/src/shared/components/challenge-detail/Header/DeadlinesPanel/style.scss +++ b/src/shared/components/challenge-detail/Header/DeadlinesPanel/style.scss @@ -5,14 +5,16 @@ display: flex; flex-wrap: wrap; justify-content: space-between; - padding: 30px 0 15px 0; + padding: 24px 0 34px 0; position: relative; + margin-bottom: -24px; @include xs-to-md { flex-direction: column; padding-top: 0; padding-right: 16px; padding-left: 16px; + margin-bottom: 0; } &.left { @@ -21,10 +23,16 @@ } .timezone { - @include tc-label-sm; + @include roboto-regular; - color: $tc-gray-40; + color: #d4d4d4; + font-size: 12px; + line-height: 18px; position: absolute; - right: 12px; - bottom: 6px; + right: 24px; + bottom: 8px; + + @include xs-to-md { + right: 16px; + } } diff --git a/src/shared/components/challenge-detail/Header/index.jsx b/src/shared/components/challenge-detail/Header/index.jsx index 08a055d3a4..1fdab4452a 100644 --- a/src/shared/components/challenge-detail/Header/index.jsx +++ b/src/shared/components/challenge-detail/Header/index.jsx @@ -12,6 +12,7 @@ import { isMM } from 'utils/challenge'; import PT from 'prop-types'; import React from 'react'; +import { useMediaQuery } from 'react-responsive'; import { PrimaryButton } from 'topcoder-react-ui-kit'; import { Link } from 'topcoder-react-utils'; import { COMPETITION_TRACKS } from 'utils/tc'; @@ -29,10 +30,6 @@ import TabSelector from './TabSelector'; import style from './style.scss'; -/* Holds day and hour range in ms. */ -const HOUR_MS = 60 * 60 * 1000; -const DAY_MS = 24 * HOUR_MS; - export default function ChallengeHeader(props) { const { isLoggedIn, @@ -50,7 +47,7 @@ export default function ChallengeHeader(props) { unregistering, challengeTypesMap, selectedView, - showDeadlineDetail, + showDeadlineDetail: showDeadlineDetailProp, hasFirstPlacement, hasThriveArticles, hasRecommendedChallenges, @@ -78,6 +75,9 @@ export default function ChallengeHeader(props) { track, } = challenge; + const desktop = useMediaQuery({ minWidth: 1024 }); + const showDeadlineDetail = desktop || showDeadlineDetailProp; + const tags = challenge.tags || []; const allPhases = challenge.phases || []; @@ -128,26 +128,6 @@ export default function ChallengeHeader(props) { */ const hasSubmissions = !_.isEmpty(mySubmissions); - const openPhases = sortedAllPhases.filter(p => p.isOpen); - let nextPhase = openPhases[0]; - if (hasRegistered && openPhases[0] && openPhases[0].name === 'Registration') { - nextPhase = openPhases[1] || {}; - } - const nextDeadline = nextPhase && nextPhase.name; - - const deadlineEnd = moment(nextPhase && phaseEndDate(nextPhase)); - const currentTime = moment(); - - let timeLeft = deadlineEnd.isAfter(currentTime) - ? deadlineEnd.diff(currentTime) : 0; - - let format; - if (timeLeft > DAY_MS) format = 'D[d] H[h]'; - else if (timeLeft > HOUR_MS) format = 'H[h] m[min]'; - else format = 'm[min] s[s]'; - - timeLeft = moment.duration(timeLeft).format(format); - let relevantPhases = []; if (showDeadlineDetail) { @@ -210,41 +190,6 @@ export default function ChallengeHeader(props) { const checkpointCount = checkpoints && checkpoints.numberOfPassedScreeningSubmissions; - let nextDeadlineMsg; - switch ((status || '').toLowerCase()) { - case 'active': - nextDeadlineMsg = ( -
- Next Deadline: - {' '} - { - - {nextDeadline || '-'} - - } -
- ); - break; - case 'completed': - nextDeadlineMsg = ( -
- The challenge is finished. -
- ); - break; - default: - nextDeadlineMsg = ( -
- Status: - ‌ - - {_.upperFirst(_.lowerCase(status))} - -
- ); - break; - } - // Legacy MMs have a roundId field, but new MMs do not. // This is used to disable registration/submission for legacy MMs. const isLegacyMM = isMM(challenge) && Boolean(challenge.roundId); @@ -425,18 +370,7 @@ export default function ChallengeHeader(props) {
- {nextDeadlineMsg} - { - (status || '').toLowerCase() === 'active' - && ( -
- Current Deadline Ends:{' '} - - {timeLeft} - -
- ) - } + Competition Timeline