diff --git a/config/constants/development.js b/config/constants/development.js
index 89dba60d..4619d647 100644
--- a/config/constants/development.js
+++ b/config/constants/development.js
@@ -31,5 +31,6 @@ 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',
- SEGMENT_API_KEY: 'QBtLgV8vCiuRX1lDikbMjcoe9aCHkF6n'
+ SEGMENT_API_KEY: 'QBtLgV8vCiuRX1lDikbMjcoe9aCHkF6n',
+ CREATE_FORUM_TYPE_IDS: ['927abff4-7af9-4145-8ba1-577c16e64e2e', 'dc876fa4-ef2d-4eee-b701-b555fcc6544c']
}
diff --git a/config/constants/production.js b/config/constants/production.js
index f7f7e18b..835c1a23 100644
--- a/config/constants/production.js
+++ b/config/constants/production.js
@@ -31,5 +31,6 @@ 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',
- SEGMENT_API_KEY: 'QSQAW5BWmZfLoKFNRgNKaqHvLDLJoGqF'
+ SEGMENT_API_KEY: 'QSQAW5BWmZfLoKFNRgNKaqHvLDLJoGqF',
+ CREATE_FORUM_TYPE_IDS: ['927abff4-7af9-4145-8ba1-577c16e64e2e', 'dc876fa4-ef2d-4eee-b701-b555fcc6544c']
}
diff --git a/src/actions/challenges.js b/src/actions/challenges.js
index 13e8b58f..641b9542 100644
--- a/src/actions/challenges.js
+++ b/src/actions/challenges.js
@@ -28,9 +28,6 @@ import {
UPLOAD_ATTACHMENT_FAILURE,
UPLOAD_ATTACHMENT_PENDING,
UPLOAD_ATTACHMENT_SUCCESS,
- LOAD_CHALLENGE_RESOURCES_PENDING,
- LOAD_CHALLENGE_RESOURCES_SUCCESS,
- LOAD_CHALLENGE_RESOURCES_FAILURE,
CREATE_CHALLENGE_RESOURCE,
DELETE_CHALLENGE_RESOURCE,
REMOVE_ATTACHMENT,
@@ -40,7 +37,8 @@ import {
UPDATE_CHALLENGE_DETAILS_FAILURE,
CREATE_CHALLENGE_PENDING,
CREATE_CHALLENGE_SUCCESS,
- CREATE_CHALLENGE_FAILURE
+ CREATE_CHALLENGE_FAILURE,
+ LOAD_CHALLENGE_RESOURCES
} from '../config/constants'
import { loadProject } from './projects'
@@ -174,7 +172,7 @@ export function loadChallengeDetails (projectId, challengeId) {
payload: fetchChallenge(challengeId).then((challenge) => {
// TODO remove this unncessary check, or better utilize the the case when given project id
// does not match with challenge's project id
- if (challenge.projectId === projectId) {
+ if (challenge.projectId == projectId) { // eslint-disable-line
dispatch(loadProject(projectId))
}
return challenge
@@ -203,10 +201,12 @@ export function updateChallengeDetails (challengeId, challengeDetails) {
type: UPDATE_CHALLENGE_DETAILS_SUCCESS,
challengeDetails: challenge
})
- }).catch(() => {
+ }).catch((error) => {
dispatch({
- type: UPDATE_CHALLENGE_DETAILS_FAILURE
+ type: UPDATE_CHALLENGE_DETAILS_FAILURE,
+ error
})
+ return Promise.reject(error)
})
}
}
@@ -394,27 +394,11 @@ export function loadChallengeTerms () {
}
export function loadResources (challengeId) {
- return async (dispatch) => {
- dispatch({
- type: LOAD_CHALLENGE_RESOURCES_PENDING,
- challengeResources: {}
- })
-
+ return (dispatch, getState) => {
if (challengeId) {
- return fetchResources(challengeId).then((resources) => {
- dispatch({
- type: LOAD_CHALLENGE_RESOURCES_SUCCESS,
- challengeResources: resources
- })
- }).catch(() => {
- dispatch({
- type: LOAD_CHALLENGE_RESOURCES_FAILURE
- })
- })
- } else {
- dispatch({
- type: LOAD_CHALLENGE_RESOURCES_SUCCESS,
- challengeResources: null
+ return dispatch({
+ type: LOAD_CHALLENGE_RESOURCES,
+ payload: fetchResources(challengeId)
})
}
}
diff --git a/src/components/ChallengeEditor/ChallengeEditor.module.scss b/src/components/ChallengeEditor/ChallengeEditor.module.scss
index 23c723f8..b66f644a 100644
--- a/src/components/ChallengeEditor/ChallengeEditor.module.scss
+++ b/src/components/ChallengeEditor/ChallengeEditor.module.scss
@@ -397,3 +397,9 @@
align-items: center;
}
+.errorContainer {
+ .errorMessage {
+ color: $red;
+ }
+}
+
diff --git a/src/components/ChallengeEditor/ChallengePrizes-Field/index.js b/src/components/ChallengeEditor/ChallengePrizes-Field/index.js
index b6b804c5..12a850d7 100644
--- a/src/components/ChallengeEditor/ChallengePrizes-Field/index.js
+++ b/src/components/ChallengeEditor/ChallengePrizes-Field/index.js
@@ -26,7 +26,7 @@ class ChallengePrizesField extends Component {
addNewPrize () {
const challengePrize = this.getChallengePrize()
- challengePrize.prizes = [...challengePrize.prizes, { type: CHALLENGE_PRIZE_TYPE.MONEY, value: 1 }]
+ challengePrize.prizes = [...challengePrize.prizes, { type: CHALLENGE_PRIZE_TYPE.USD, value: 1 }]
this.onUpdateValue(challengePrize)
}
@@ -55,7 +55,7 @@ class ChallengePrizesField extends Component {
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.MONEY, 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 () {
diff --git a/src/components/ChallengeEditor/ChallengeView/index.js b/src/components/ChallengeEditor/ChallengeView/index.js
index 31b74caf..164787f6 100644
--- a/src/components/ChallengeEditor/ChallengeView/index.js
+++ b/src/components/ChallengeEditor/ChallengeView/index.js
@@ -21,7 +21,16 @@ import PhaseInput from '../../PhaseInput'
import LegacyLinks from '../../LegacyLinks'
import AssignedMemberField from '../AssignedMember-Field'
-const ChallengeView = ({ projectDetail, challenge, metadata, challengeResources, token, isLoading, challengeId, assignedMemberDetails }) => {
+const ChallengeView = ({
+ projectDetail,
+ challenge,
+ metadata,
+ challengeResources,
+ token,
+ isLoading,
+ challengeId,
+ assignedMemberDetails,
+ enableEdit }) => {
const selectedType = _.find(metadata.challengeTypes, { id: challenge.typeId })
const challengeTrack = _.find(metadata.challengeTracks, { id: challenge.trackId })
@@ -64,7 +73,7 @@ const ChallengeView = ({ projectDetail, challenge, metadata, challengeResources,
View Details
@@ -202,7 +211,8 @@ ChallengeView.propTypes = {
isLoading: PropTypes.bool.isRequired,
challengeId: PropTypes.string.isRequired,
challengeResources: PropTypes.arrayOf(PropTypes.object),
- assignedMemberDetails: PropTypes.shape()
+ assignedMemberDetails: PropTypes.shape(),
+ enableEdit: PropTypes.bool
}
export default withRouter(ChallengeView)
diff --git a/src/components/ChallengeEditor/CheckpointPrizes-Field/index.js b/src/components/ChallengeEditor/CheckpointPrizes-Field/index.js
index 9afd7790..5f1fe512 100644
--- a/src/components/ChallengeEditor/CheckpointPrizes-Field/index.js
+++ b/src/components/ChallengeEditor/CheckpointPrizes-Field/index.js
@@ -4,17 +4,17 @@ import styles from './CheckpointPrizes-Field.module.scss'
import cn from 'classnames'
import { range } from 'lodash'
import { validateValue } from '../../../util/input-check'
-import { VALIDATION_VALUE_TYPE, PRIZE_SETS_TYPE } from '../../../config/constants'
+import { VALIDATION_VALUE_TYPE, PRIZE_SETS_TYPE, CHALLENGE_PRIZE_TYPE } from '../../../config/constants'
const CheckpointPrizesField = ({ challenge, onUpdateOthers }) => {
const type = PRIZE_SETS_TYPE.CHECKPOINT_PRIZES
- const checkpointPrize = challenge.prizeSets.find(p => p.type === type) || { type, 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
function onChange (number, amount) {
checkpointPrize.prizes = range(validateValue(number, VALIDATION_VALUE_TYPE.INTEGER))
- .map(i => ({ type: 'Prize ' + i, value: validateValue(amount, 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) })
}
return (
diff --git a/src/components/ChallengeEditor/CopilotFee-Field/index.js b/src/components/ChallengeEditor/CopilotFee-Field/index.js
index d7d357de..fbee9df3 100644
--- a/src/components/ChallengeEditor/CopilotFee-Field/index.js
+++ b/src/components/ChallengeEditor/CopilotFee-Field/index.js
@@ -5,11 +5,11 @@ import PropTypes from 'prop-types'
import { validateValue } from '../../../util/input-check'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faDollarSign } from '@fortawesome/free-solid-svg-icons'
-import { VALIDATION_VALUE_TYPE, PRIZE_SETS_TYPE } from '../../../config/constants'
+import { VALIDATION_VALUE_TYPE, PRIZE_SETS_TYPE, CHALLENGE_PRIZE_TYPE } from '../../../config/constants'
const CopilotFeeField = ({ challenge, onUpdateOthers, readOnly }) => {
const type = PRIZE_SETS_TYPE.COPILOT_PAYMENT
- const copilotFee = (challenge.prizeSets && challenge.prizeSets.find(p => p.type === type)) || { type, prizes: [{ type, value: 0 }] }
+ const copilotFee = (challenge.prizeSets && challenge.prizeSets.find(p => p.type === type)) || { type, prizes: [{ type: CHALLENGE_PRIZE_TYPE.USD, value: 0 }] }
const value = copilotFee.prizes[0].value
function onChange (e) {
@@ -17,7 +17,7 @@ const CopilotFeeField = ({ challenge, onUpdateOthers, readOnly }) => {
if (parseInt(value) > 1000000) {
value = '1000000'
}
- copilotFee.prizes = [{ type, value }]
+ copilotFee.prizes = [{ type: CHALLENGE_PRIZE_TYPE.USD, value }]
onUpdateOthers({ field: 'prizeSets', value: [...challenge.prizeSets.filter(p => p.type !== type), copilotFee] })
}
diff --git a/src/components/ChallengeEditor/ReviewCost-Field/index.js b/src/components/ChallengeEditor/ReviewCost-Field/index.js
index 11f288fc..03099bf6 100644
--- a/src/components/ChallengeEditor/ReviewCost-Field/index.js
+++ b/src/components/ChallengeEditor/ReviewCost-Field/index.js
@@ -3,16 +3,16 @@ import PropTypes from 'prop-types'
import styles from './ReviewCost-Field.module.scss'
import cn from 'classnames'
import { validateValue } from '../../../util/input-check'
-import { VALIDATION_VALUE_TYPE, PRIZE_SETS_TYPE } from '../../../config/constants'
+import { VALIDATION_VALUE_TYPE, PRIZE_SETS_TYPE, CHALLENGE_PRIZE_TYPE } from '../../../config/constants'
const ReviewCostField = ({ challenge, onUpdateOthers }) => {
const type = PRIZE_SETS_TYPE.REVIEWER_PAYMENT
- const reviewCost = challenge.prizeSets.find(p => p.type === type) || { type, prizes: [{ type, value: 0 }] }
+ const reviewCost = challenge.prizeSets.find(p => p.type === type) || { type, prizes: [{ type: CHALLENGE_PRIZE_TYPE.USD, value: 0 }] }
const value = reviewCost.prizes[0].value
function onChange (e) {
const value = validateValue(e.target.value, VALIDATION_VALUE_TYPE.INTEGER, '$')
- reviewCost.prizes = [{ type, value }]
+ reviewCost.prizes = [{ type: CHALLENGE_PRIZE_TYPE.USD, value }]
onUpdateOthers({ field: 'prizeSets', value: [...challenge.prizeSets.filter(p => p.type !== type), reviewCost] })
}
diff --git a/src/components/ChallengeEditor/index.js b/src/components/ChallengeEditor/index.js
index 08118594..8f6d4433 100644
--- a/src/components/ChallengeEditor/index.js
+++ b/src/components/ChallengeEditor/index.js
@@ -15,7 +15,8 @@ import {
PRIZE_SETS_TYPE,
DEFAULT_TERM_UUID,
DEFAULT_NDA_UUID,
- SUBMITTER_ROLE_UUID
+ SUBMITTER_ROLE_UUID,
+ CREATE_FORUM_TYPE_IDS
} from '../../config/constants'
import { PrimaryButton, OutlineButton } from '../Buttons'
import TrackField from './Track-Field'
@@ -767,6 +768,10 @@ class ChallengeEditor extends Component {
phases: this.getTemplatePhases(defaultTemplate)
// prizeSets: this.getDefaultPrizeSets()
}
+ const discussions = this.getDiscussionsConfig(newChallenge)
+ if (discussions) {
+ newChallenge.discussions = discussions
+ }
try {
const action = await createChallenge(newChallenge)
const draftChallenge = {
@@ -779,6 +784,18 @@ class ChallengeEditor extends Component {
}
}
+ getDiscussionsConfig (challenge) {
+ if (_.includes(CREATE_FORUM_TYPE_IDS, challenge.typeId)) {
+ return ([
+ {
+ name: `${challenge.name} Discussion`,
+ type: 'challenge',
+ provider: 'vanilla'
+ }
+ ])
+ }
+ }
+
getTemplatePhases (template) {
const timelinePhaseIds = template.phases.map(timelinePhase => timelinePhase.phaseId || timelinePhase)
const validPhases = _.cloneDeep(this.props.metadata.challengePhases).filter(challengePhase => {
@@ -919,11 +936,7 @@ class ChallengeEditor extends Component {
}
async onlySave () {
- this.updateAllChallengeInfo(this.state.challenge.status, () => {
- this.resetModal()
- const { history } = this.props
- history.push('./view')
- })
+ this.updateAllChallengeInfo(this.state.challenge.status)
}
getResourceRoleByName (name) {
@@ -1008,7 +1021,7 @@ class ChallengeEditor extends Component {
return
Error loading challenge
}
const isTask = _.get(challenge, 'task.isTask', false)
- const { assignedMemberDetails } = this.state
+ const { assignedMemberDetails, error } = this.state
let isActive = false
let isDraft = false
let isCompleted = false
@@ -1044,7 +1057,6 @@ class ChallengeEditor extends Component {
let activateModal = null
let closeTaskModal = null
let draftModal = null
- let savedModal = null
let { type } = challenge
if (!type) {
@@ -1056,20 +1068,6 @@ class ChallengeEditor extends Component {
}
}
}
- if (!isNew && challenge.status === 'New' && isLaunch && isConfirm) {
- savedModal = (
-
- )
- }
if (!isNew && isLaunch && !isConfirm) {
activateModal = (
@@ -1162,6 +1160,8 @@ class ChallengeEditor extends Component {
)
}
+ const errorContainer =
+
const actionButtons =
{!isLoading && this.state.hasValidationErrors && Please fix the errors before saving
}
{
@@ -1182,7 +1182,7 @@ class ChallengeEditor extends Component {
{ isDraft && }
}
{!isLoading && isActive &&
@@ -1211,10 +1211,11 @@ class ChallengeEditor extends Component {
+ { errorContainer }
{ actionButtons }
) : (
-