diff --git a/src/actions/challenges.js b/src/actions/challenges.js index ed65f8f6..e41678fe 100644 --- a/src/actions/challenges.js +++ b/src/actions/challenges.js @@ -58,7 +58,7 @@ import { removeChallengeFromPhaseProduct, saveChallengeAsPhaseProduct } from '.. /** * Loads active challenges of project by page */ -export function loadChallengesByPage (page, projectId, status, filterChallengeName = null, selfService = false) { +export function loadChallengesByPage (page, projectId, status, filterChallengeName = null, selfService = false, userHandle = null) { return (dispatch, getState) => { dispatch({ type: LOAD_CHALLENGES_PENDING, @@ -87,6 +87,9 @@ export function loadChallengesByPage (page, projectId, status, filterChallengeNa } if (selfService) { filters.selfService = true + if (userHandle) { + filters.selfServiceCopilot = userHandle + } } return fetchChallenges(filters, { diff --git a/src/actions/sidebar.js b/src/actions/sidebar.js index fe73bced..2a463df4 100644 --- a/src/actions/sidebar.js +++ b/src/actions/sidebar.js @@ -53,7 +53,7 @@ export function loadProjects (filterProjectName = '', myProjects = true) { } /** - * Unlads projects of the authenticated user + * Unloads projects of the authenticated user */ export function unloadProjects () { return (dispatch) => { diff --git a/src/components/ChallengeEditor/ChallengeView/index.js b/src/components/ChallengeEditor/ChallengeView/index.js index fa9adddb..761bbe29 100644 --- a/src/components/ChallengeEditor/ChallengeView/index.js +++ b/src/components/ChallengeEditor/ChallengeView/index.js @@ -37,7 +37,8 @@ const ChallengeView = ({ enableEdit, onLaunchChallenge, onCloseTask, - projectPhases + projectPhases, + assignYourselfCopilit }) => { const selectedType = _.find(metadata.challengeTypes, { id: challenge.typeId }) const challengeTrack = _.find(metadata.challengeTracks, { id: challenge.trackId }) @@ -103,18 +104,18 @@ const ChallengeView = ({ {selectedMilestone && -
- Milestone: {selectedMilestone ? ( - - {selectedMilestone.name} - - ) : ''} -
+
+ Milestone: {selectedMilestone ? ( + + {selectedMilestone.name} + + ) : ''} +
}
Track: - {}} /> + { }} />
Type: {selectedType ? selectedType.name : ''} @@ -130,10 +131,11 @@ const ChallengeView = ({
{isTask && - } + } + copilot, + selfService: challenge.legacy.selfService + }} copilots={metadata.members} assignYourselfCopilit={assignYourselfCopilit} readOnly />
{ const [selectedTab, setSelectedTab] = useState(0) @@ -80,6 +81,10 @@ const ChallengeViewTabs = ({ const isTask = _.get(challenge, 'task.isTask', false) + const isSelfService = challenge.legacy.selfService + const isDraft = challenge.status.toUpperCase() === CHALLENGE_STATUS.DRAFT + const launchText = `${isSelfService && isDraft ? 'Approve and ' : ''}Launch` + return (
@@ -94,7 +99,7 @@ const ChallengeViewTabs = ({ styles.actionButtonsLeft )} > - { isTask ? () + {isTask ? () : () }
@@ -107,12 +112,13 @@ const ChallengeViewTabs = ({ styles.actionButtonsRight )} > - {(challenge.status === 'Draft' || challenge.status === 'New') &&
} + {(challenge.status === 'Draft' || challenge.status === 'New') && !isSelfService && + (
)} {challenge.status === 'Draft' && (
{challenge.legacyId || isTask ? ( @@ -138,9 +144,17 @@ const ChallengeViewTabs = ({ )}
)} - {enableEdit && ( + {enableEdit && !isSelfService && ( )} + {isSelfService && isDraft && + ( + + )}
@@ -208,6 +222,7 @@ const ChallengeViewTabs = ({ onLaunchChallenge={onLaunchChallenge} onCloseTask={onCloseTask} projectPhases={projectPhases} + assignYourselfCopilit={assignYourselfCopilit} /> )} {selectedTab === 1 && ( @@ -244,7 +259,8 @@ ChallengeViewTabs.propTypes = { onLaunchChallenge: PropTypes.func, cancelChallenge: PropTypes.func.isRequired, onCloseTask: PropTypes.func, - projectPhases: PropTypes.arrayOf(PropTypes.object) + projectPhases: PropTypes.arrayOf(PropTypes.object), + assignYourselfCopilit: PropTypes.func.isRequired } export default ChallengeViewTabs diff --git a/src/components/ChallengeEditor/Copilot-Field/index.js b/src/components/ChallengeEditor/Copilot-Field/index.js index 25b24540..9e89c7dd 100644 --- a/src/components/ChallengeEditor/Copilot-Field/index.js +++ b/src/components/ChallengeEditor/Copilot-Field/index.js @@ -1,23 +1,30 @@ import React from 'react' import PropTypes from 'prop-types' +import { PrimaryButton } from '../../Buttons' import styles from './Copilot-Field.module.scss' import cn from 'classnames' import _ from 'lodash' import CopilotCard from '../../CopilotCard' -const CopilotField = ({ copilots, challenge, onUpdateOthers, readOnly }) => { +const CopilotField = ({ copilots, challenge, onUpdateOthers, readOnly, assignYourselfCopilit }) => { let errMessage = 'Please set a copilot' const selectedCopilot = _.find(copilots, { handle: challenge.copilot }) const copilotFee = _.find(challenge.prizeSets, p => p.type === 'copilot', []) - console.log(copilotFee) + const selfService = challenge.selfService + if (readOnly) { return (
- +
- {selectedCopilot && (
- + {(selectedCopilot || selfService) && (
+ {(selectedCopilot && )} + {(selfService && )}
)}
) @@ -26,7 +33,7 @@ const CopilotField = ({ copilots, challenge, onUpdateOthers, readOnly }) => { <>
- +
{ @@ -49,7 +56,7 @@ const CopilotField = ({ copilots, challenge, onUpdateOthers, readOnly }) => { CopilotField.defaultProps = { copilots: [], - onUpdateOthers: () => {}, + onUpdateOthers: () => { }, readOnly: false } @@ -57,7 +64,8 @@ CopilotField.propTypes = { copilots: PropTypes.arrayOf(PropTypes.shape()).isRequired, challenge: PropTypes.shape().isRequired, onUpdateOthers: PropTypes.func, - readOnly: PropTypes.bool + readOnly: PropTypes.bool, + assignYourselfCopilit: PropTypes.func.isRequired } export default CopilotField diff --git a/src/components/ChallengeEditor/index.js b/src/components/ChallengeEditor/index.js index ae5d8cbd..5d2958b8 100644 --- a/src/components/ChallengeEditor/index.js +++ b/src/components/ChallengeEditor/index.js @@ -181,7 +181,7 @@ class ChallengeEditor extends Component { } } - async resetChallengeData (setState = () => {}) { + async resetChallengeData (setState = () => { }) { const { isNew, challengeDetails, metadata, attachments, challengeId, assignedMemberDetails } = this.props if ( challengeDetails && @@ -214,11 +214,13 @@ class ChallengeEditor extends Component { setState({ challenge: challengeDetail, assignedMemberDetails, - draftChallenge: { data: { - ..._.cloneDeep(challengeDetails), - copilot: challengeData.copilot, - reviewer: challengeData.reviewer - } }, + draftChallenge: { + data: { + ..._.cloneDeep(challengeDetails), + copilot: challengeData.copilot, + reviewer: challengeData.reviewer + } + }, isLoading: false, isOpenAdvanceSettings, currentTemplate @@ -506,7 +508,7 @@ class ChallengeEditor extends Component { if (fileTypesMetadataIndex > -1) { fileTypesMetadata = { ...newChallenge.metadata[fileTypesMetadataIndex] } newChallenge.metadata[fileTypesMetadataIndex] = fileTypesMetadata - // if not yet, create an empty record in metadata + // if not yet, create an empty record in metadata } else { fileTypesMetadata = { name: 'fileTypes', value: '[]' } newChallenge.metadata.push(fileTypesMetadata) @@ -1038,7 +1040,8 @@ class ChallengeEditor extends Component { newChallenge.phases = _.cloneDeep(draftChallenge.data.phases) this.setState({ draftChallenge, - challenge: newChallenge }) + challenge: newChallenge + }) } else { this.setState({ draftChallenge }) } @@ -1065,7 +1068,7 @@ class ChallengeEditor extends Component { return challengeId } - async updateAllChallengeInfo (status, cb = () => {}) { + async updateAllChallengeInfo (status, cb = () => { }) { const { updateChallengeDetails, assignedMemberDetails: oldAssignedMember, projectDetail } = this.props if (this.state.isSaving) return this.setState({ isSaving: true }, async () => { @@ -1095,11 +1098,13 @@ class ChallengeEditor extends Component { const draftChallenge = { data: action.challengeDetails } draftChallenge.data.copilot = copilot draftChallenge.data.reviewer = reviewer - this.setState({ isLaunch: true, + this.setState({ + isLaunch: true, isConfirm: newChallenge.id, draftChallenge, challenge: newChallenge, - isSaving: false }, cb) + isSaving: false + }, cb) } catch (e) { const error = this.formatResponseError(e) || `Unable to update the challenge to status ${status}` this.setState({ isSaving: false, error }, cb) @@ -1353,7 +1358,7 @@ class ChallengeEditor extends Component { /> ) - // if some information for closing task is missing, ask to complete it + // if some information for closing task is missing, ask to complete it } else { const formattedErrors = validationErrors.length === 1 ? validationErrors[0] : ( validationErrors.slice(0, -1).join(', ') + ' and ' + validationErrors[validationErrors.length - 1] @@ -1410,7 +1415,7 @@ class ChallengeEditor extends Component {
*/}
- { !this.state.hasValidationErrors ? ( + {!this.state.hasValidationErrors ? ( ) : ( @@ -1468,11 +1473,11 @@ class ChallengeEditor extends Component { {projectDetail.version === 'v4' && } - { useTask && () } + {useTask && ()}
{showDesignChallengeWarningModel && designChallengeModal} - { errorContainer } - { actionButtons } + {errorContainer} + {actionButtons} ) : (
e.preventDefault()}> @@ -1489,7 +1494,7 @@ class ChallengeEditor extends Component {
Track: - {}} /> + { }} />
Type: {selectedType ? selectedType.name : ''} @@ -1531,7 +1536,7 @@ class ChallengeEditor extends Component {
- { isOpenAdvanceSettings && ( + {isOpenAdvanceSettings && ( {/* remove terms field and use default term */} @@ -1580,7 +1585,7 @@ class ChallengeEditor extends Component { /> ) } - { showTimeline && ( + {showTimeline && ( {/* hide until challenge API change is pushed to PROD https://github.com/topcoder-platform/challenge-api/issues/348 */} - { false && - { errorContainer } - { actionButtons } + {errorContainer} + {actionButtons} ) @@ -1644,11 +1649,11 @@ class ChallengeEditor extends Component {
* Required
- { activateModal } - { draftModal } - { closeTaskModal } + {activateModal} + {draftModal} + {closeTaskModal}
- { challengeForm } + {challengeForm}
diff --git a/src/components/ChallengesComponent/ChallengeCard/index.js b/src/components/ChallengesComponent/ChallengeCard/index.js index 9d14b0b2..4049ddc1 100644 --- a/src/components/ChallengesComponent/ChallengeCard/index.js +++ b/src/components/ChallengesComponent/ChallengeCard/index.js @@ -163,15 +163,16 @@ const hoverComponents = (challenge, onUpdateLaunch, deleteModalLaunch) => { ) } -const renderStatus = (status) => { +const renderStatus = (status, getStatusText) => { switch (status) { case CHALLENGE_STATUS.ACTIVE: case CHALLENGE_STATUS.NEW: case CHALLENGE_STATUS.DRAFT: case CHALLENGE_STATUS.COMPLETED: - return () + const statusText = getStatusText ? getStatusText(status) : status + return () default: - return ({status}) + return ({statusText}) } } @@ -276,7 +277,7 @@ class ChallengeCard extends React.Component { render () { const { isLaunch, isConfirm, isSaving, isDeleteLaunch, isCheckChalengePermission, hasEditChallengePermission } = this.state - const { challenge, shouldShowCurrentPhase, reloadChallengeList, isBillingAccountExpired, disableHover } = this.props + const { challenge, shouldShowCurrentPhase, reloadChallengeList, isBillingAccountExpired, disableHover, getStatusText } = this.props const { phaseMessage, endTime } = getPhaseInfo(challenge) const deleteMessage = isCheckChalengePermission ? 'Checking permissions...' @@ -335,7 +336,7 @@ class ChallengeCard extends React.Component { {renderLastUpdated(challenge)} - {renderStatus(challenge.status.toUpperCase())} + {renderStatus(challenge.status.toUpperCase(), getStatusText)} {shouldShowCurrentPhase && ( {phaseMessage} @@ -371,7 +372,8 @@ ChallengeCard.propTypes = { partiallyUpdateChallengeDetails: PropTypes.func.isRequired, deleteChallenge: PropTypes.func.isRequired, isBillingAccountExpired: PropTypes.bool, - disableHover: PropTypes.bool + disableHover: PropTypes.bool, + getStatusText: PropTypes.func } export default withRouter(ChallengeCard) diff --git a/src/components/ChallengesComponent/ChallengeList/index.js b/src/components/ChallengesComponent/ChallengeList/index.js index d8e111ac..50603986 100644 --- a/src/components/ChallengesComponent/ChallengeList/index.js +++ b/src/components/ChallengesComponent/ChallengeList/index.js @@ -51,7 +51,7 @@ class ChallengeList extends Component { const { status, filterChallengeName, loadChallengesByPage, activeProjectId, selfService } = this.props this.setState({ searchText }, () => { if (status !== projectStatus || searchText !== filterChallengeName) { - loadChallengesByPage(1, activeProjectId, projectStatus, searchText, selfService) + loadChallengesByPage(1, activeProjectId, projectStatus, searchText, selfService, this.getHandle()) } }) } @@ -64,7 +64,7 @@ class ChallengeList extends Component { const { searchText } = this.state const { page, loadChallengesByPage, activeProjectId, status, selfService } = this.props if (page !== pageNumber) { - loadChallengesByPage(pageNumber, activeProjectId, status, searchText, selfService) + loadChallengesByPage(pageNumber, activeProjectId, status, searchText, selfService, this.getHandle()) } } @@ -74,7 +74,7 @@ class ChallengeList extends Component { reloadChallengeList () { const { searchText } = this.state const { page, loadChallengesByPage, activeProjectId, status, selfService } = this.props - loadChallengesByPage(page, activeProjectId, status, searchText, selfService) + loadChallengesByPage(page, activeProjectId, status, searchText, selfService, this.getHandle()) } /** @@ -92,6 +92,22 @@ class ChallengeList extends Component { this.setState({ errorMessage: null }) } + getStatusTextFunc (selfService) { + const draftText = selfService ? 'Waiting for approval' : 'Draft' + return (status) => { + switch (status) { + case CHALLENGE_STATUS.DRAFT: + return draftText + default: + return status + } + } + } + + getHandle () { + return this.props.auth && this.props.auth.user ? this.props.auth.user.handle : null + } + render () { const { searchText, errorMessage } = this.state const { @@ -187,9 +203,9 @@ class ChallengeList extends Component { } }}> - Active + {(selfService ? 'Assigned challenges' : 'Active')} {(!selfService && New)} - Draft + {this.getStatusTextFunc(selfService)(CHALLENGE_STATUS.DRAFT)} {(!selfService && Completed)} {(!selfService && Cancelled)} @@ -231,6 +247,7 @@ class ChallengeList extends Component { deleteChallenge={deleteChallenge} isBillingAccountExpired={isBillingAccountExpired} disableHover={selfService} + getStatusText={this.getStatusTextFunc(selfService)} /> ) @@ -276,7 +293,8 @@ ChallengeList.propTypes = { partiallyUpdateChallengeDetails: PropTypes.func.isRequired, deleteChallenge: PropTypes.func.isRequired, isBillingAccountExpired: PropTypes.bool, - selfService: PropTypes.bool + selfService: PropTypes.bool, + auth: PropTypes.object.isRequired } export default ChallengeList diff --git a/src/components/ChallengesComponent/ChallengeStatus/ChallengeStatus.module.scss b/src/components/ChallengesComponent/ChallengeStatus/ChallengeStatus.module.scss index 7fde3c54..12ac0156 100644 --- a/src/components/ChallengesComponent/ChallengeStatus/ChallengeStatus.module.scss +++ b/src/components/ChallengesComponent/ChallengeStatus/ChallengeStatus.module.scss @@ -1,12 +1,13 @@ @import "../../../styles/includes"; .container { - height: 22px; + min-height: 22px; width: 86px; border-radius: 3px; display: flex; justify-content: center; align-items: center; + text-align: center; span { @include roboto; diff --git a/src/components/ChallengesComponent/ChallengeStatus/index.js b/src/components/ChallengesComponent/ChallengeStatus/index.js index d11fd980..160c764e 100644 --- a/src/components/ChallengesComponent/ChallengeStatus/index.js +++ b/src/components/ChallengesComponent/ChallengeStatus/index.js @@ -17,16 +17,17 @@ const statuses = { [CHALLENGE_STATUS.COMPLETED]: styles.blue } -const ChallengeStatus = ({ status }) => { +const ChallengeStatus = ({ status, statusText }) => { return (
- {_.startCase(_.toLower(status))} + {_.startCase(_.toLower(statusText))}
) } ChallengeStatus.propTypes = { - status: PropTypes.string + status: PropTypes.string, + statusText: PropTypes.string } export default ChallengeStatus diff --git a/src/components/ChallengesComponent/index.js b/src/components/ChallengesComponent/index.js index 2758988c..82f34bb2 100644 --- a/src/components/ChallengesComponent/index.js +++ b/src/components/ChallengesComponent/index.js @@ -28,7 +28,8 @@ const ChallengesComponent = ({ partiallyUpdateChallengeDetails, deleteChallenge, isBillingAccountExpired, - selfService + selfService, + auth }) => { return ( @@ -78,6 +79,7 @@ const ChallengesComponent = ({ deleteChallenge={deleteChallenge} isBillingAccountExpired={isBillingAccountExpired} selfService={selfService} + auth={auth} /> )} @@ -104,7 +106,8 @@ ChallengesComponent.propTypes = { partiallyUpdateChallengeDetails: PropTypes.func.isRequired, deleteChallenge: PropTypes.func.isRequired, isBillingAccountExpired: PropTypes.bool, - selfService: PropTypes.bool + selfService: PropTypes.bool, + auth: PropTypes.object.isRequired } ChallengesComponent.defaultProps = { diff --git a/src/components/Sidebar/index.js b/src/components/Sidebar/index.js index 0cc4affb..eb3cec34 100644 --- a/src/components/Sidebar/index.js +++ b/src/components/Sidebar/index.js @@ -37,7 +37,7 @@ const Sidebar = ({ ) } -
+
Give Application Feedback
diff --git a/src/containers/ChallengeEditor/index.js b/src/containers/ChallengeEditor/index.js index 8345dd94..7e942ce9 100644 --- a/src/containers/ChallengeEditor/index.js +++ b/src/containers/ChallengeEditor/index.js @@ -306,6 +306,10 @@ class ChallengeEditor extends Component { } } + assignYourselfCopilit () { + console.debug('assign copilit') + } + render () { const { match, @@ -330,7 +334,8 @@ class ChallengeEditor extends Component { deleteChallenge, loggedInUser, projectPhases, - isProjectPhasesLoading + isProjectPhasesLoading, + assignYourselfCopilit // members } = this.props const { @@ -424,6 +429,7 @@ class ChallengeEditor extends Component { replaceResourceInRole={replaceResourceInRole} partiallyUpdateChallengeDetails={partiallyUpdateChallengeDetails} projectPhases={projectPhases} + assignYourselfCopilit={assignYourselfCopilit} /> )} /> @@ -487,6 +493,7 @@ class ChallengeEditor extends Component { enableEdit={enableEdit} onLaunchChallenge={this.onLaunchChallenge} onCloseTask={this.onCloseTask} + assignYourselfCopilit={this.assignYourselfCopilit} /> )} /> @@ -541,7 +548,8 @@ ChallengeEditor.propTypes = { replaceResourceInRole: PropTypes.func, loadProject: PropTypes.func, projectPhases: PropTypes.arrayOf(PropTypes.object), - isProjectPhasesLoading: PropTypes.bool + isProjectPhasesLoading: PropTypes.bool, + assignYourselfCopilit: PropTypes.func.isRequired // members: PropTypes.arrayOf(PropTypes.shape()) } diff --git a/src/containers/Challenges/index.js b/src/containers/Challenges/index.js index 103c0801..929403cb 100644 --- a/src/containers/Challenges/index.js +++ b/src/containers/Challenges/index.js @@ -85,7 +85,8 @@ class Challenges extends Component { partiallyUpdateChallengeDetails, deleteChallenge, isBillingAccountExpired, - selfService + selfService, + auth } = this.props const { searchProjectName, onlyMyProjects } = this.state const projectInfo = _.find(projects, { id: activeProjectId }) || {} @@ -149,6 +150,7 @@ class Challenges extends Component { deleteChallenge={deleteChallenge} isBillingAccountExpired={isBillingAccountExpired} selfService={selfService} + auth={auth} /> } @@ -178,16 +180,18 @@ Challenges.propTypes = { partiallyUpdateChallengeDetails: PropTypes.func.isRequired, deleteChallenge: PropTypes.func.isRequired, isBillingAccountExpired: PropTypes.bool, - selfService: PropTypes.bool + selfService: PropTypes.bool, + auth: PropTypes.object.isRequired } -const mapStateToProps = ({ challenges, sidebar, projects }) => ({ +const mapStateToProps = ({ challenges, sidebar, projects, auth }) => ({ ..._.omit(challenges, ['projectId']), challengeProjectId: challenges.projectId, activeProjectId: sidebar.activeProjectId, projects: sidebar.projects, projectDetail: projects.projectDetail, - isBillingAccountExpired: projects.isBillingAccountExpired + isBillingAccountExpired: projects.isBillingAccountExpired, + auth: auth }) const mapDispatchToProps = {