diff --git a/.circleci/config.yml b/.circleci/config.yml index 8a204949..6d96e22b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,6 +33,8 @@ builddeploy_steps: &builddeploy_steps command: | ./awsconfiguration.sh $DEPLOY_ENV ./buildenv.sh -e $DEPLOY_ENV -b ${LOGICAL_ENV}-${APPNAME}-buildvar + echo awsenvconf >.dockerignore + echo buildenvvar >>.dockerignore - run: name: "building image" command: | diff --git a/src/actions/challenges.js b/src/actions/challenges.js index 6314ecbe..1d610d29 100644 --- a/src/actions/challenges.js +++ b/src/actions/challenges.js @@ -245,9 +245,10 @@ export function createChallenge (challengeDetails) { type: CREATE_CHALLENGE_SUCCESS, challengeDetails: challenge }) - }).catch(() => { + }).catch((e) => { dispatch({ - type: CREATE_CHALLENGE_FAILURE + type: CREATE_CHALLENGE_FAILURE, + error: e }) }) } diff --git a/src/components/ChallengeEditor/AssignedMember-Field/AssignedMember-Field.module.scss b/src/components/ChallengeEditor/AssignedMember-Field/AssignedMember-Field.module.scss index 33eea080..f9892657 100644 --- a/src/components/ChallengeEditor/AssignedMember-Field/AssignedMember-Field.module.scss +++ b/src/components/ChallengeEditor/AssignedMember-Field/AssignedMember-Field.module.scss @@ -39,6 +39,7 @@ display: flex; flex-direction: row; flex-wrap: wrap; + min-width: 280px; } } diff --git a/src/components/ChallengeEditor/ChallengeEditor.module.scss b/src/components/ChallengeEditor/ChallengeEditor.module.scss index cac38dd5..51ba1127 100644 --- a/src/components/ChallengeEditor/ChallengeEditor.module.scss +++ b/src/components/ChallengeEditor/ChallengeEditor.module.scss @@ -28,6 +28,7 @@ span { color: $tc-red; } + } .textRequired { @@ -211,6 +212,18 @@ } } } + + .templateLink { + text-align: center; + font-size: 14px; + line-height: 29px; + font-weight: 400; + + a { + font-weight: 400; + font-size: 12px; + } + } } .group:last-of-type { margin-bottom: 0; @@ -232,10 +245,13 @@ } .error { - text-align: right; padding-right: 40px; padding-bottom: 20px; - color: $tc-red + color: $tc-red; + + .errorMessage { + font-size: 25px; + } } .actionButtons { @@ -332,6 +348,7 @@ line-height: 36px; margin-bottom: 30px; margin-top: 0; + } span { diff --git a/src/components/ChallengeEditor/ChallengePrizes-Field/index.js b/src/components/ChallengeEditor/ChallengePrizes-Field/index.js index 24fb5f83..5897a08b 100644 --- a/src/components/ChallengeEditor/ChallengePrizes-Field/index.js +++ b/src/components/ChallengeEditor/ChallengePrizes-Field/index.js @@ -8,7 +8,12 @@ import PrizeInput from '../../PrizeInput' import styles from './ChallengePrizes-Field.module.scss' import cn from 'classnames' import { PrimaryButton } from '../../Buttons' -import { CHALLENGE_PRIZE_TYPE, VALIDATION_VALUE_TYPE, PRIZE_SETS_TYPE, CHALLENGE_TYPES_WITH_MULTIPLE_PRIZES } from '../../../config/constants' +import { + CHALLENGE_PRIZE_TYPE, + VALIDATION_VALUE_TYPE, + PRIZE_SETS_TYPE, + CHALLENGE_TYPES_WITH_MULTIPLE_PRIZES +} from '../../../config/constants' import { validateValue } from '../../../util/input-check' class ChallengePrizesField extends Component { @@ -26,7 +31,10 @@ class ChallengePrizesField extends Component { addNewPrize () { const challengePrize = this.getChallengePrize() - challengePrize.prizes = [...challengePrize.prizes, { type: CHALLENGE_PRIZE_TYPE.USD, value: 1 }] + challengePrize.prizes = [ + ...challengePrize.prizes, + { type: CHALLENGE_PRIZE_TYPE.USD, value: 1 } + ] this.onUpdateValue(challengePrize) } @@ -38,7 +46,10 @@ class ChallengePrizesField extends Component { onUpdateInput (value, index) { const challengePrize = this.getChallengePrize() - challengePrize.prizes[index].value = validateValue(value, VALIDATION_VALUE_TYPE.INTEGER) + challengePrize.prizes[index].value = validateValue( + value, + VALIDATION_VALUE_TYPE.INTEGER + ) if (parseInt(challengePrize.prizes[index].value) > 1000000) { challengePrize.prizes[index].value = '1000000' } @@ -48,60 +59,102 @@ class ChallengePrizesField extends Component { onUpdateValue (challengePrize) { const type = PRIZE_SETS_TYPE.CHALLENGE_PRIZES const { onUpdateOthers, challenge } = this.props - const existingPrizes = challenge.prizeSets ? challenge.prizeSets.filter(p => p.type !== type) : [] + const existingPrizes = challenge.prizeSets + ? challenge.prizeSets.filter(p => p.type !== type) + : [] - onUpdateOthers({ field: 'prizeSets', value: [...existingPrizes, challengePrize] }) + onUpdateOthers({ + field: 'prizeSets', + value: [...existingPrizes, challengePrize] + }) } getChallengePrize () { const type = PRIZE_SETS_TYPE.CHALLENGE_PRIZES - return (this.props.challenge.prizeSets && this.props.challenge.prizeSets.length && this.props.challenge.prizeSets.find(p => p.type === type)) || { type, prizes: [{ type: CHALLENGE_PRIZE_TYPE.USD, value: 0 }] } + return ( + (this.props.challenge.prizeSets && + this.props.challenge.prizeSets.length && + this.props.challenge.prizeSets.find(p => p.type === type)) || { + type, + prizes: [{ type: CHALLENGE_PRIZE_TYPE.USD, value: 0 }] + } + ) } renderPrizes () { const { currentPrizeIndex } = this.state const { readOnly, challenge } = this.props - const allowMultiplePrizes = _.includes(CHALLENGE_TYPES_WITH_MULTIPLE_PRIZES, challenge.type) - return _.map(this.getChallengePrize().prizes, (prize, index, { length }) => ( -
-
-
- -
- {readOnly ? ( - ${prize.value} - ) : (
- - { - index > 0 && ( -
this.removePrize(index)}> - + const allowMultiplePrizes = _.includes( + CHALLENGE_TYPES_WITH_MULTIPLE_PRIZES, + challenge.type + ) + return _.map( + this.getChallengePrize().prizes, + (prize, index, { length }) => { + let errMessage = '' + if (prize.value === '') { + errMessage = 'Prize amount is required field' + } else if (+prize.value <= 0 || +prize.value > 1000000) { + errMessage = + 'Prize amount must be more than 0 and no more than 1000000' + } else if (index > 0) { + const prePrize = this.getChallengePrize().prizes[index - 1] + if (+prePrize.value < +prize.value) { + errMessage = + 'Prize for the higher place cannot be bigger than for lower place' + } + } + return ( +
+
+
+ +
+ {readOnly ? ( + ${prize.value} + ) : ( +
+ + {index > 0 && ( +
this.removePrize(index)} + > + +
+ )}
- ) - } -
)} -
- {!readOnly && challenge.submitTriggered && (prize.value === '' || (+prize.value <= 0 || +prize.value > 1000000)) && ( -
-
-
- {prize.value === '' - ? 'Prize amount is required field' - : 'Prize amount must be more than 0 and no more than 1000000'} + )}
+ {!readOnly && challenge.submitTriggered && errMessage && ( +
+
+
+ {errMessage} +
+
+ )}
- )} -
- )) + ) + } + ) } render () { const { readOnly, challenge } = this.props - const allowMultiplePrizes = _.includes(CHALLENGE_TYPES_WITH_MULTIPLE_PRIZES, challenge.type) + const allowMultiplePrizes = _.includes( + CHALLENGE_TYPES_WITH_MULTIPLE_PRIZES, + challenge.type + ) return (
@@ -109,10 +162,12 @@ class ChallengePrizesField extends Component {
- { this.renderPrizes() } - {!readOnly && allowMultiplePrizes && (
- -
)} + {this.renderPrizes()} + {!readOnly && allowMultiplePrizes && ( +
+ +
+ )}
) } diff --git a/src/components/ChallengeEditor/TextEditor-Field/index.js b/src/components/ChallengeEditor/TextEditor-Field/index.js index d5c53628..bd3f8b40 100644 --- a/src/components/ChallengeEditor/TextEditor-Field/index.js +++ b/src/components/ChallengeEditor/TextEditor-Field/index.js @@ -60,6 +60,9 @@ class TextEditorField extends Component {
)} {shouldShowPrivateDescription && showShowPrivateDescriptionField && (
Private specification + {!readOnly && (
+ Access specification templates here +
)} This text will only be visible to Topcoder members that have registered for this challenge diff --git a/src/components/ChallengeEditor/index.js b/src/components/ChallengeEditor/index.js index 9a3c91d5..21a8a5fb 100644 --- a/src/components/ChallengeEditor/index.js +++ b/src/components/ChallengeEditor/index.js @@ -677,7 +677,7 @@ class ChallengeEditor extends Component { return false } - return _.every(challengePrizes.prizes, (prize) => { + return _.every(challengePrizes.prizes, (prize, index) => { if (prize.value === '') { return false } @@ -685,6 +685,11 @@ class ChallengeEditor extends Component { if (prizeNumber <= 0 || prizeNumber > 1000000) { return false } + if (index > 0) { + if (+prize.value > +challengePrizes.prizes[index - 1].value) { + return false + } + } return true }) } @@ -1157,6 +1162,7 @@ class ChallengeEditor extends Component { token, removeAttachment, failedToLoad, + errorMessage, projectDetail, attachments } = this.props @@ -1184,6 +1190,7 @@ class ChallengeEditor extends Component {
+ {errorMessage &&
{`Error : ${errorMessage}`}
} Please try again later and if the issue persists contact us at  support@topcoder.com  to resolve the issue as soon as possible. @@ -1478,6 +1485,9 @@ class ChallengeEditor extends Component {
Public specification *
+
+ Access specification templates here +
{ + this.setState({ + isCheckChalengePermission: false, + hasEditChallengePermission: hasPermission + }) + }) + this.setState({ + isDeleteLaunch: true, + isCheckChalengePermission: true, + hasEditChallengePermission: false + }) } } @@ -249,25 +266,32 @@ class ChallengeCard extends React.Component { } render () { - const { isLaunch, isConfirm, isSaving, isDeleteLaunch } = this.state + const { isLaunch, isConfirm, isSaving, isDeleteLaunch, isCheckChalengePermission, hasEditChallengePermission } = this.state const { challenge, shouldShowCurrentPhase, reloadChallengeList } = this.props const { phaseMessage, endTime } = getPhaseInfo(challenge) + const deleteMessage = isCheckChalengePermission + ? 'Checking permissions...' + : `Do you want to delete "${challenge.name}"?` + return (
- { - isDeleteLaunch && !isConfirm && ( - - ) - } - { isLaunch && !isConfirm && ( + {isDeleteLaunch && !isConfirm && ( + + )} + {isLaunch && !isConfirm && ( ( +const ConfirmationModal = ({ title, message, errorMessage, theme, isProcessing, onCancel, onConfirm, disableConfirmButton }) => (
{title}
@@ -23,6 +23,7 @@ const ConfirmationModal = ({ title, message, errorMessage, theme, isProcessing,
@@ -39,6 +40,7 @@ ConfirmationModal.propTypes = { errorMessage: PropTypes.string, theme: PropTypes.shape(), isProcessing: PropTypes.bool, + disableConfirmButton: PropTypes.bool, onCancel: PropTypes.func, onConfirm: PropTypes.func } diff --git a/src/components/Modal/Modal.module.scss b/src/components/Modal/Modal.module.scss index c8a65d3d..cd50fb88 100644 --- a/src/components/Modal/Modal.module.scss +++ b/src/components/Modal/Modal.module.scss @@ -24,9 +24,11 @@ } .closebtn { + width: 30px; + height: 30px; position: absolute; right: 0px; - top: -7px; + top: 0px; font-size: 27px; opacity: 1; color: black; diff --git a/src/components/SelectUserAutocomplete/index.js b/src/components/SelectUserAutocomplete/index.js index 49ef0f45..3217718f 100644 --- a/src/components/SelectUserAutocomplete/index.js +++ b/src/components/SelectUserAutocomplete/index.js @@ -40,6 +40,7 @@ export default function SelectUserAutocomplete (props) {