From 9cfe023383f426635d56796d5efa88119cc7155d Mon Sep 17 00:00:00 2001 From: Vikas Agarwal Date: Wed, 9 Dec 2020 18:46:52 +0530 Subject: [PATCH] =?UTF-8?q?feat:=20git#944-Move=20"Close=20Task"=20to=20Vi?= =?UTF-8?q?ew=20Screen=20=E2=80=94=20Added=20intelligent=20close=20task=20?= =?UTF-8?q?button=20which=20enables=20only=20when=20task=20is=20active=20a?= =?UTF-8?q?nd=20has=20assigned=20member.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeView/ChallengeView.module.scss | 5 +- .../ChallengeEditor/ChallengeView/index.js | 20 +++- src/config/constants.js | 5 +- src/containers/ChallengeEditor/index.js | 96 +++++++++++++++++-- 4 files changed, 115 insertions(+), 11 deletions(-) diff --git a/src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss b/src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss index 64699bd9..df8cc001 100644 --- a/src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss +++ b/src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss @@ -244,12 +244,15 @@ .actionButtonsRight { right: 20px; - .button:not(:last-child), a:not(:last-child) { margin-right: 20px; } + + button { + white-space: nowrap; + } } .button { diff --git a/src/components/ChallengeEditor/ChallengeView/index.js b/src/components/ChallengeEditor/ChallengeView/index.js index a7ef66f0..802ff8ae 100644 --- a/src/components/ChallengeEditor/ChallengeView/index.js +++ b/src/components/ChallengeEditor/ChallengeView/index.js @@ -34,7 +34,8 @@ const ChallengeView = ({ challengeId, assignedMemberDetails, enableEdit, - onLaunchChallenge }) => { + onLaunchChallenge, + onCloseTask }) => { const selectedType = _.find(metadata.challengeTypes, { id: challenge.typeId }) const challengeTrack = _.find(metadata.challengeTracks, { id: challenge.trackId }) @@ -87,6 +88,20 @@ const ChallengeView = ({ ) } + { + isTask && challenge.status === 'Active' && ( +
+ { assignedMemberDetails ? ( + + ) : ( + + {/* Don't disable button for real inside tooltip, otherwise mouseEnter/Leave events work not good */} + + + )} +
+ ) + } { enableEdit && } @@ -236,7 +251,8 @@ ChallengeView.propTypes = { challengeResources: PropTypes.arrayOf(PropTypes.object), assignedMemberDetails: PropTypes.shape(), enableEdit: PropTypes.bool, - onLaunchChallenge: PropTypes.func + onLaunchChallenge: PropTypes.func, + onCloseTask: PropTypes.func } export default withRouter(ChallengeView) diff --git a/src/config/constants.js b/src/config/constants.js index c297d61c..581b9eb0 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -183,5 +183,8 @@ export const CHALLENGE_TYPES_WITH_MULTIPLE_PRIZES = ['Challenge'] * To have the same wording across the app. */ export const MESSAGE = { - NO_LEGACY_CHALLENGE: 'Legacy challenge is not yet created' + NO_LEGACY_CHALLENGE: 'Legacy challenge is not yet created', + NO_TASK_ASSIGNEE: 'Task is not assigned yet', + TASK_CLOSE_SUCCESS: 'Task closed successfully', + CHALLENGE_LAUNCH_SUCCESS: 'Challenge activated successfully' } diff --git a/src/containers/ChallengeEditor/index.js b/src/containers/ChallengeEditor/index.js index aa64b53c..c4033093 100644 --- a/src/containers/ChallengeEditor/index.js +++ b/src/containers/ChallengeEditor/index.js @@ -29,7 +29,7 @@ import { } from '../../actions/challenges' import { connect } from 'react-redux' -import { SUBMITTER_ROLE_UUID } from '../../config/constants' +import { SUBMITTER_ROLE_UUID, MESSAGE } from '../../config/constants' import { patchChallenge } from '../../services/challenges' import ConfirmationModal from '../../components/Modal/ConfirmationModal' import AlertModal from '../../components/Modal/AlertModal' @@ -42,13 +42,23 @@ class ChallengeEditor extends Component { constructor (props) { super(props) const mountedWithCreatePage = props.match.path.endsWith('/new') - this.state = { mountedWithCreatePage, isLaunching: false, showSuccessModal: false, showLaunchModal: false } + this.state = { + challengeDetails: props.challengeDetails, + mountedWithCreatePage, + isLaunching: false, + showSuccessModal: false, + showLaunchModal: false + } this.onLaunchChallenge = this.onLaunchChallenge.bind(this) this.activateChallenge = this.activateChallenge.bind(this) this.closeLaunchModal = this.closeLaunchModal.bind(this) + this.closeCloseTaskModal = this.closeCloseTaskModal.bind(this) this.closeSuccessModal = this.closeSuccessModal.bind(this) + this.onCloseTask = this.onCloseTask.bind(this) + this.closeTask = this.closeTask.bind(this) } + componentDidMount () { const { match, @@ -95,6 +105,8 @@ class ChallengeEditor extends Component { const challengeId = _.get(newMatch.params, 'challengeId', null) if (_.get(match.params, 'projectId', null) !== projectId || _.get(match.params, 'challengeId', null) !== challengeId) { this.fetchChallengeDetails(newMatch, loadChallengeDetails, loadResources) + } else { + this.setState({ challengeDetails: nextProps.challengeDetails }) } } @@ -124,10 +136,18 @@ class ChallengeEditor extends Component { this.setState({ showLaunchModal: true }) } + onCloseTask () { + this.setState({ showCloseTaskModal: true }) + } + closeLaunchModal () { this.setState({ showLaunchModal: false }) } + closeCloseTaskModal () { + this.setState({ showCloseTaskModal: false }) + } + closeSuccessModal () { this.setState({ showSuccessModal: false }) } @@ -137,20 +157,63 @@ class ChallengeEditor extends Component { const { challengeDetails } = this.props try { this.setState({ isLaunching: true }) - await patchChallenge(challengeDetails.id, { status: 'Active' }) - this.setState({ isLaunching: false, showLaunchModal: false, showSuccessModal: true }) + const response = await patchChallenge(challengeDetails.id, { status: 'Active' }) + this.setState({ + isLaunching: false, + showLaunchModal: false, + showSuccessModal: true, + suceessMessage: MESSAGE.CHALLENGE_LAUNCH_SUCCESS, + challengeDetails: { ...challengeDetails, status: response.status } + }) } catch (e) { const error = _.get(e, 'response.data.message', 'Unable to activate the challenge') this.setState({ isLaunching: false, showLaunchModal: false, launchError: error }) } } + /** + * Close task when user confirm it + */ + async closeTask () { + const { challengeResources } = this.props + const { challengeDetails } = this.state + const submitters = challengeResources && challengeResources.filter(cr => cr.roleId === SUBMITTER_ROLE_UUID) + var assignedMemberDetails = null + if (submitters && submitters.length === 1) { + assignedMemberDetails = { + userId: submitters[0].memberId, + handle: submitters[0].memberHandle + } + } + + // set assigned user as the only one winner + const winners = [{ + userId: assignedMemberDetails.userId, + handle: assignedMemberDetails.handle, + placement: 1 + }] + try { + this.setState({ isLaunching: true }) + const response = await patchChallenge(challengeDetails.id, { winners, status: 'Completed' }) + this.setState({ + isLaunching: false, + showCloseTaskModal: false, + showSuccessModal: true, + suceessMessage: MESSAGE.TASK_CLOSE_SUCCESS, + challengeDetails: { ...challengeDetails, status: response.status } + }) + } catch (e) { + const error = _.get(e, 'response.data.message', 'Unable to close the task') + this.setState({ isLaunching: false, showCloseTaskModal: false, launchError: error }) + } + } + render () { const { match, isLoading, isProjectLoading, - challengeDetails, + // challengeDetails, challengeResources, metadata, createAttachment, @@ -165,7 +228,15 @@ class ChallengeEditor extends Component { replaceResourceInRole // members } = this.props - const { mountedWithCreatePage, isLaunching, showLaunchModal, showSuccessModal } = this.state + const { + mountedWithCreatePage, + isLaunching, + showLaunchModal, + showCloseTaskModal, + showSuccessModal, + suceessMessage, + challengeDetails + } = this.state if (isProjectLoading || isLoading) return const challengeId = _.get(match.params, 'challengeId', null) if (challengeId && (!challengeDetails || !challengeDetails.id)) { @@ -191,15 +262,25 @@ class ChallengeEditor extends Component { onCancel={this.closeLaunchModal} onConfirm={this.activateChallenge} /> + const closeTaskModal = const successModal = return
{ showLaunchModal && activateModal } + { showCloseTaskModal && closeTaskModal } { showSuccessModal && successModal } )) } />