Skip to content

Commit

Permalink
Merge pull request #1452 from topcoder-platform/multiround
Browse files Browse the repository at this point in the history
Multiround
  • Loading branch information
jmgasper authored Dec 20, 2022
2 parents 68a32ee + c29f228 commit af2ee4f
Show file tree
Hide file tree
Showing 18 changed files with 524 additions and 43 deletions.
10 changes: 6 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ parameters:

defaults: &defaults
docker:
- image: circleci/python:2.7-stretch-browsers
- image: cimg/python:3.11.0-browsers

test_defaults: &test_defaults
docker:
Expand All @@ -19,8 +19,10 @@ install_dependency: &install_dependency
name: Installation of build and deployment dependencies.
command: |
sudo apt install jq
sudo pip install awscli --upgrade
sudo pip install docker-compose
sudo apt update
sudo apt install python3-pip
sudo pip3 install awscli --upgrade
sudo pip3 install docker-compose
install_test_dependency: &install_test_dependency
name: Installation of build and deployment dependencies.
Expand Down Expand Up @@ -150,7 +152,7 @@ workflows:
context : org-global
filters: &filters-dev
branches:
only: ['develop', 'Oct_2022_Release']
only: ['develop', 'multiround']

# Production builds are exectuted only on tagged commits to the
# master branch.
Expand Down
4 changes: 3 additions & 1 deletion config/constants/development.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module.exports = {
DES_TRACK_ID: '5fa04185-041f-49a6-bfd1-fe82533cd6c8',
DS_TRACK_ID: 'c0f5d461-8219-4c14-878a-c3a3f356466d',
QA_TRACK_ID: '36e6a8d0-7e1e-4608-a673-64279d99c115',
CP_TRACK_ID: '9d6e0de8-df14-4c76-ba0a-a9a8cb03a4ea',
CHALLENGE_TYPE_ID: '927abff4-7af9-4145-8ba1-577c16e64e2e',
MARATHON_TYPE_ID: '929bc408-9cf2-4b3e-ba71-adfbf693046c',
SEGMENT_API_KEY: 'QBtLgV8vCiuRX1lDikbMjcoe9aCHkF6n',
Expand All @@ -44,5 +45,6 @@ module.exports = {
// if idle for this many minutes, show user a prompt saying they'll be logged out
IDLE_TIMEOUT_MINUTES: 10,
// duration to show the prompt saying user will be logged out, before actually logging out the user
IDLE_TIMEOUT_GRACE_MINUTES: 5
IDLE_TIMEOUT_GRACE_MINUTES: 5,
MULTI_ROUND_CHALLENGE_TEMPLATE_ID: 'd4201ca4-8437-4d63-9957-3f7708184b07'
}
4 changes: 3 additions & 1 deletion config/constants/production.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module.exports = {
DES_TRACK_ID: '5fa04185-041f-49a6-bfd1-fe82533cd6c8',
DS_TRACK_ID: 'c0f5d461-8219-4c14-878a-c3a3f356466d',
QA_TRACK_ID: '36e6a8d0-7e1e-4608-a673-64279d99c115',
CP_TRACK_ID: '9d6e0de8-df14-4c76-ba0a-a9a8cb03a4ea',
CHALLENGE_TYPE_ID: '927abff4-7af9-4145-8ba1-577c16e64e2e',
MARATHON_TYPE_ID: '929bc408-9cf2-4b3e-ba71-adfbf693046c',
SEGMENT_API_KEY: 'QSQAW5BWmZfLoKFNRgNKaqHvLDLJoGqF',
Expand All @@ -42,5 +43,6 @@ module.exports = {
FILE_PICKER_REGION: 'us-east-1',
FILE_PICKER_CNAME: 'fs.topcoder.com',
IDLE_TIMEOUT_MINUTES: 10,
IDLE_TIMEOUT_GRACE_MINUTES: 5
IDLE_TIMEOUT_GRACE_MINUTES: 5,
MULTI_ROUND_CHALLENGE_TEMPLATE_ID: 'd4201ca4-8437-4d63-9957-3f7708184b07'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
@import "../../../styles/includes";

.row {
box-sizing: border-box;
display: flex;
flex-direction: row;
margin: 30px 30px 0 30px;
align-content: space-between;
justify-content: flex-start;

.field {
@include upto-sm {
display: block;
padding-bottom: 10px;
}

label {
@include roboto-bold();

font-size: 16px;
line-height: 19px;
font-weight: 500;
color: $tc-gray-80;
}

&.col1 {
max-width: 185px;
min-width: 185px;
margin-right: 14px;
white-space: nowrap;
display: flex;
align-items: center;
flex-grow: 1;

span {
color: $tc-red;
}
}

&.col2.error {
color: $tc-red;
margin-top: -25px;
}
&.col2 {
align-self: flex-end;
width: 80%;
margin-bottom: auto;
margin-top: auto;
display: flex;
flex-direction: row;
max-width: 600px;
min-width: 600px;
}
}
}
48 changes: 48 additions & 0 deletions src/components/ChallengeEditor/ChallengeType-Field/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import _ from 'lodash'
import React from 'react'
import PropTypes from 'prop-types'
import Select from '../../Select'
import cn from 'classnames'
import styles from './ChallengeType-Field.module.scss'

const ChallengeTypeField = ({ types, onUpdateSelect, challenge, disabled }) => {
return (
<>
<div className={styles.row}>
<div className={cn(styles.field, styles.col1)}>
<label htmlFor='type'>Challenge Type <span>*</span> :</label>
</div>
<div className={cn(styles.field, styles.col2, { [styles.disabled]: disabled })}>
<Select
name='challenge_type'
options={_.map(types, type => ({ label: type, value: type }))}
placeholder='Challenge Type'
isClearable={false}
onChange={(e) => onUpdateSelect(e.value, false, 'challengeType')}
isDisabled={disabled}
/>
</div>
</div>
{ challenge.submitTriggered && !challenge.challengeType && <div className={styles.row}>
<div className={cn(styles.field, styles.col1)} />
<div className={cn(styles.field, styles.col2, styles.error)}>
Challenge Type is required field
</div>
</div> }
</>
)
}

ChallengeTypeField.defaultProps = {
types: [],
disabled: false
}

ChallengeTypeField.propTypes = {
types: PropTypes.arrayOf(PropTypes.shape()).isRequired,
onUpdateSelect: PropTypes.func.isRequired,
challenge: PropTypes.shape().isRequired,
disabled: PropTypes.bool
}

export default ChallengeTypeField
10 changes: 9 additions & 1 deletion src/components/ChallengeEditor/ChallengeView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import {
REVIEW_TYPES,
CONNECT_APP_URL,
PHASE_PRODUCT_CHALLENGE_ID_FIELD,
MULTI_ROUND_CHALLENGE_TEMPLATE_ID,
DS_TRACK_ID
} from '../../../config/constants'
import PhaseInput from '../../PhaseInput'
import CheckpointPrizesField from '../CheckpointPrizes-Field'

const ChallengeView = ({
projectDetail,
Expand Down Expand Up @@ -96,6 +98,7 @@ const ChallengeView = ({
const showTimeline = false // disables the timeline for time being https://github.com/topcoder-platform/challenge-engine-ui/issues/706
const isTask = _.get(challenge, 'task.isTask', false)
const phases = _.get(challenge, 'phases', [])
const showCheckpointPrizes = _.get(challenge, 'timelineTemplateId') === MULTI_ROUND_CHALLENGE_TEMPLATE_ID
const isDataScience = challenge.trackId === DS_TRACK_ID
const useDashboardData = _.find(challenge.metadata, { name: 'show_data_dashboard' })
const useDashboard = useDashboardData ? useDashboardData.value : true
Expand Down Expand Up @@ -125,7 +128,7 @@ const ChallengeView = ({
</div>
}
<div className={styles.col}>
<span className={styles.fieldTitle}>Track:</span>
<span className={styles.fieldTitle}>Domain:</span>
<Track disabled type={challengeTrack} isActive key={challenge.trackId} onUpdateOthers={() => { }} />
</div>
<div className={styles.col}>
Expand Down Expand Up @@ -239,6 +242,11 @@ const ChallengeView = ({
readOnly
/>}
<ChallengePrizesField challenge={challenge} readOnly />
{
showCheckpointPrizes && (
<CheckpointPrizesField challenge={challenge} readOnly />
)
}
<CopilotFeeField challenge={challenge} readOnly />
<ChallengeTotalField challenge={challenge} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
width: 271px;
}
input:last-of-type {
width: 187px;
width: 70px;
margin-right: 10px;
}
}
Expand All @@ -61,3 +61,45 @@
color: $tc-red;
cursor: pointer;
}

.dollarIcon {
color: $tc-black;
cursor: pointer;
}

.checkpointPrizeContainer {
margin: 0 0 0 60px;
}

.checkpointLabel {
font-weight: 500 !important;
padding-left: 0 !important;
}

.checkpointPrizeContainer > div {
display: inline-block;
margin-right: 10px;
}

.checkpointPrizeInputContainer {
box-sizing: border-box;
display: flex;
height: 40px;
}

.checkpointPrizeAmountContainer {
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
background-color: $tc-prize-bg;
border: 1px solid $tc-gray-40;
max-width: 50px;
min-width: 50px;
width: 50px;
border-right-width: 0;
}

.checkpointSelect {
max-width: 85px;
}
87 changes: 69 additions & 18 deletions src/components/ChallengeEditor/CheckpointPrizes-Field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,88 @@ import React from 'react'
import PropTypes from 'prop-types'
import styles from './CheckpointPrizes-Field.module.scss'
import cn from 'classnames'
import { range } from 'lodash'
import _ from 'lodash'
import { validateValue } from '../../../util/input-check'
import { VALIDATION_VALUE_TYPE, PRIZE_SETS_TYPE, CHALLENGE_PRIZE_TYPE } from '../../../config/constants'
import {
VALIDATION_VALUE_TYPE,
PRIZE_SETS_TYPE,
CHALLENGE_PRIZE_TYPE,
MAX_CHECKPOINT_PRIZE_COUNT,
DEFAULT_CHECKPOINT_PRIZE,
DEFAULT_CHECKPOINT_PRIZE_COUNT
} from '../../../config/constants'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faDollarSign } from '@fortawesome/free-solid-svg-icons'
import Select from '../../Select'

const CheckpointPrizesField = ({ challenge, onUpdateOthers }) => {
const CheckpointPrizesField = ({ challenge, onUpdateOthers, readOnly }) => {
const type = PRIZE_SETS_TYPE.CHECKPOINT_PRIZES
const checkpointPrize = challenge.prizeSets.find(p => p.type === type) || { type: CHALLENGE_PRIZE_TYPE.USD, prizes: [] }
const number = checkpointPrize.prizes.length
const amount = checkpointPrize.prizes.length ? checkpointPrize.prizes[0].value : 0
const prizeSets = _.get(challenge, 'prizeSets') || []
const checkpointPrize = prizeSets.find(p => p.type === type) || { type: PRIZE_SETS_TYPE.CHECKPOINT_PRIZES, prizes: [], 'description': 'Checkpoint Prizes' }
const number = _.get(checkpointPrize, 'prizes.length') || DEFAULT_CHECKPOINT_PRIZE_COUNT
const amount = _.get(checkpointPrize, 'prizes.length') ? checkpointPrize.prizes[0].value : DEFAULT_CHECKPOINT_PRIZE

// update the check point prize with default values if it's not already defined
if (_.get(checkpointPrize, 'prizes.length') === 0) {
onChange(number, amount)
}

function onChange (number, amount) {
checkpointPrize.prizes = range(validateValue(number, VALIDATION_VALUE_TYPE.INTEGER))
.map(i => ({ type: CHALLENGE_PRIZE_TYPE.USD, value: validateValue(amount, VALIDATION_VALUE_TYPE.INTEGER, '$') }))
onUpdateOthers({ field: 'prizeSets', value: [...challenge.prizeSets.filter(p => p.type !== type), +number && checkpointPrize].filter(p => p) })
checkpointPrize.prizes = _.range(validateValue(number, VALIDATION_VALUE_TYPE.INTEGER))
.map(i => ({ type: CHALLENGE_PRIZE_TYPE.USD, value: +validateValue(amount, VALIDATION_VALUE_TYPE.INTEGER) }))
onUpdateOthers({ field: 'prizeSets', value: [...prizeSets.filter(p => p.type !== type), +number && checkpointPrize].filter(p => p) })
}

return (
<div className={styles.row}>
<div className={cn(styles.field, styles.col1)}>
<label htmlFor='checkpointPrizes'>Checkpoint Prizes :</label>
<>
<div className={cn(styles.row)}>
<div className={cn(styles.field, styles.col1)}>
<label htmlFor={`checkpointPrizes`} className={styles.checkpointLabel}>Checkpoint Prizes :</label>
</div>
{
readOnly ? (
<div className={cn(styles.field, styles.col2)}>
${amount} for each submission up to {number} submissions
</div>
) : (
<div className={cn(styles.field, styles.col2)}>
<div>
<div className={styles.checkpointPrizeInputContainer}>
<div className={styles.checkpointPrizeAmountContainer}>
<FontAwesomeIcon className={styles.dollarIcon} icon={faDollarSign} />
</div>
<input id='checkpointPrize' name='checkpointPrize' type='text' placeholder='' value={amount} maxLength='7' required onChange={(e) => onChange(number, e.target.value)} />
</div>
</div>
<div>
for each submission up to&nbsp;&nbsp;
</div>
<div className={styles.checkpointSelect}>
<Select
name='submissions'
options={_.range(1, MAX_CHECKPOINT_PRIZE_COUNT + 1).map((v) => ({ label: v, value: v }))}
value={{ label: number, value: number }}
isClearable={false}
onChange={e => onChange(e.value, amount)}
isDisabled={false}
/>
</div>
</div>
)
}
</div>
<div className={cn(styles.field, styles.col2)}>
<input id='checkNumber' name='checkNumber' type='text' placeholder='Number of checkpoint prizes' value={number} maxLength='200' onChange={e => onChange(e.target.value, amount)} />
<input id='checkAmount' name='checkAmount' type='text' placeholder='Amount per prizes' value={amount} maxLength='200' onChange={e => onChange(number, e.target.value)} />
</div>
</div>
</>
)
}

CheckpointPrizesField.defaultProps = {
readOnly: false
}

CheckpointPrizesField.propTypes = {
challenge: PropTypes.shape().isRequired,
onUpdateOthers: PropTypes.func.isRequired
onUpdateOthers: PropTypes.func,
readOnly: PropTypes.bool
}

export default CheckpointPrizesField
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
overflow: auto;

&.isPrivate {
max-height: 205px;
max-height: 400px;
}

:global {
Expand Down
Loading

0 comments on commit af2ee4f

Please sign in to comment.