Skip to content

Commit 9cfe023

Browse files
author
Vikas Agarwal
committed
feat: git#944-Move "Close Task" to View Screen
— Added intelligent close task button which enables only when task is active and has assigned member.
1 parent b8ba616 commit 9cfe023

File tree

4 files changed

+115
-11
lines changed

4 files changed

+115
-11
lines changed

src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,15 @@
244244

245245
.actionButtonsRight {
246246
right: 20px;
247-
248247

249248
.button:not(:last-child),
250249
a:not(:last-child) {
251250
margin-right: 20px;
252251
}
252+
253+
button {
254+
white-space: nowrap;
255+
}
253256
}
254257

255258
.button {

src/components/ChallengeEditor/ChallengeView/index.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const ChallengeView = ({
3434
challengeId,
3535
assignedMemberDetails,
3636
enableEdit,
37-
onLaunchChallenge }) => {
37+
onLaunchChallenge,
38+
onCloseTask }) => {
3839
const selectedType = _.find(metadata.challengeTypes, { id: challenge.typeId })
3940
const challengeTrack = _.find(metadata.challengeTracks, { id: challenge.trackId })
4041

@@ -87,6 +88,20 @@ const ChallengeView = ({
8788
</div>
8889
)
8990
}
91+
{
92+
isTask && challenge.status === 'Active' && (
93+
<div className={styles.button}>
94+
{ assignedMemberDetails ? (
95+
<PrimaryButton text={'Close Task'} type={'danger'} onClick={onCloseTask} />
96+
) : (
97+
<Tooltip content={MESSAGE.NO_TASK_ASSIGNEE}>
98+
{/* Don't disable button for real inside tooltip, otherwise mouseEnter/Leave events work not good */}
99+
<PrimaryButton text={'Close Task'} type={'disabled'} />
100+
</Tooltip>
101+
)}
102+
</div>
103+
)
104+
}
90105
{ enableEdit && <PrimaryButton text={'Edit'} type={'info'} submit link={`./edit`} /> }
91106
<PrimaryButton text={'Back'} type={'info'} submit link={`..`} />
92107
</div>
@@ -236,7 +251,8 @@ ChallengeView.propTypes = {
236251
challengeResources: PropTypes.arrayOf(PropTypes.object),
237252
assignedMemberDetails: PropTypes.shape(),
238253
enableEdit: PropTypes.bool,
239-
onLaunchChallenge: PropTypes.func
254+
onLaunchChallenge: PropTypes.func,
255+
onCloseTask: PropTypes.func
240256
}
241257

242258
export default withRouter(ChallengeView)

src/config/constants.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,5 +183,8 @@ export const CHALLENGE_TYPES_WITH_MULTIPLE_PRIZES = ['Challenge']
183183
* To have the same wording across the app.
184184
*/
185185
export const MESSAGE = {
186-
NO_LEGACY_CHALLENGE: 'Legacy challenge is not yet created'
186+
NO_LEGACY_CHALLENGE: 'Legacy challenge is not yet created',
187+
NO_TASK_ASSIGNEE: 'Task is not assigned yet',
188+
TASK_CLOSE_SUCCESS: 'Task closed successfully',
189+
CHALLENGE_LAUNCH_SUCCESS: 'Challenge activated successfully'
187190
}

src/containers/ChallengeEditor/index.js

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
} from '../../actions/challenges'
3030

3131
import { connect } from 'react-redux'
32-
import { SUBMITTER_ROLE_UUID } from '../../config/constants'
32+
import { SUBMITTER_ROLE_UUID, MESSAGE } from '../../config/constants'
3333
import { patchChallenge } from '../../services/challenges'
3434
import ConfirmationModal from '../../components/Modal/ConfirmationModal'
3535
import AlertModal from '../../components/Modal/AlertModal'
@@ -42,13 +42,23 @@ class ChallengeEditor extends Component {
4242
constructor (props) {
4343
super(props)
4444
const mountedWithCreatePage = props.match.path.endsWith('/new')
45-
this.state = { mountedWithCreatePage, isLaunching: false, showSuccessModal: false, showLaunchModal: false }
45+
this.state = {
46+
challengeDetails: props.challengeDetails,
47+
mountedWithCreatePage,
48+
isLaunching: false,
49+
showSuccessModal: false,
50+
showLaunchModal: false
51+
}
4652

4753
this.onLaunchChallenge = this.onLaunchChallenge.bind(this)
4854
this.activateChallenge = this.activateChallenge.bind(this)
4955
this.closeLaunchModal = this.closeLaunchModal.bind(this)
56+
this.closeCloseTaskModal = this.closeCloseTaskModal.bind(this)
5057
this.closeSuccessModal = this.closeSuccessModal.bind(this)
58+
this.onCloseTask = this.onCloseTask.bind(this)
59+
this.closeTask = this.closeTask.bind(this)
5160
}
61+
5262
componentDidMount () {
5363
const {
5464
match,
@@ -95,6 +105,8 @@ class ChallengeEditor extends Component {
95105
const challengeId = _.get(newMatch.params, 'challengeId', null)
96106
if (_.get(match.params, 'projectId', null) !== projectId || _.get(match.params, 'challengeId', null) !== challengeId) {
97107
this.fetchChallengeDetails(newMatch, loadChallengeDetails, loadResources)
108+
} else {
109+
this.setState({ challengeDetails: nextProps.challengeDetails })
98110
}
99111
}
100112

@@ -124,10 +136,18 @@ class ChallengeEditor extends Component {
124136
this.setState({ showLaunchModal: true })
125137
}
126138

139+
onCloseTask () {
140+
this.setState({ showCloseTaskModal: true })
141+
}
142+
127143
closeLaunchModal () {
128144
this.setState({ showLaunchModal: false })
129145
}
130146

147+
closeCloseTaskModal () {
148+
this.setState({ showCloseTaskModal: false })
149+
}
150+
131151
closeSuccessModal () {
132152
this.setState({ showSuccessModal: false })
133153
}
@@ -137,20 +157,63 @@ class ChallengeEditor extends Component {
137157
const { challengeDetails } = this.props
138158
try {
139159
this.setState({ isLaunching: true })
140-
await patchChallenge(challengeDetails.id, { status: 'Active' })
141-
this.setState({ isLaunching: false, showLaunchModal: false, showSuccessModal: true })
160+
const response = await patchChallenge(challengeDetails.id, { status: 'Active' })
161+
this.setState({
162+
isLaunching: false,
163+
showLaunchModal: false,
164+
showSuccessModal: true,
165+
suceessMessage: MESSAGE.CHALLENGE_LAUNCH_SUCCESS,
166+
challengeDetails: { ...challengeDetails, status: response.status }
167+
})
142168
} catch (e) {
143169
const error = _.get(e, 'response.data.message', 'Unable to activate the challenge')
144170
this.setState({ isLaunching: false, showLaunchModal: false, launchError: error })
145171
}
146172
}
147173

174+
/**
175+
* Close task when user confirm it
176+
*/
177+
async closeTask () {
178+
const { challengeResources } = this.props
179+
const { challengeDetails } = this.state
180+
const submitters = challengeResources && challengeResources.filter(cr => cr.roleId === SUBMITTER_ROLE_UUID)
181+
var assignedMemberDetails = null
182+
if (submitters && submitters.length === 1) {
183+
assignedMemberDetails = {
184+
userId: submitters[0].memberId,
185+
handle: submitters[0].memberHandle
186+
}
187+
}
188+
189+
// set assigned user as the only one winner
190+
const winners = [{
191+
userId: assignedMemberDetails.userId,
192+
handle: assignedMemberDetails.handle,
193+
placement: 1
194+
}]
195+
try {
196+
this.setState({ isLaunching: true })
197+
const response = await patchChallenge(challengeDetails.id, { winners, status: 'Completed' })
198+
this.setState({
199+
isLaunching: false,
200+
showCloseTaskModal: false,
201+
showSuccessModal: true,
202+
suceessMessage: MESSAGE.TASK_CLOSE_SUCCESS,
203+
challengeDetails: { ...challengeDetails, status: response.status }
204+
})
205+
} catch (e) {
206+
const error = _.get(e, 'response.data.message', 'Unable to close the task')
207+
this.setState({ isLaunching: false, showCloseTaskModal: false, launchError: error })
208+
}
209+
}
210+
148211
render () {
149212
const {
150213
match,
151214
isLoading,
152215
isProjectLoading,
153-
challengeDetails,
216+
// challengeDetails,
154217
challengeResources,
155218
metadata,
156219
createAttachment,
@@ -165,7 +228,15 @@ class ChallengeEditor extends Component {
165228
replaceResourceInRole
166229
// members
167230
} = this.props
168-
const { mountedWithCreatePage, isLaunching, showLaunchModal, showSuccessModal } = this.state
231+
const {
232+
mountedWithCreatePage,
233+
isLaunching,
234+
showLaunchModal,
235+
showCloseTaskModal,
236+
showSuccessModal,
237+
suceessMessage,
238+
challengeDetails
239+
} = this.state
169240
if (isProjectLoading || isLoading) return <Loader />
170241
const challengeId = _.get(match.params, 'challengeId', null)
171242
if (challengeId && (!challengeDetails || !challengeDetails.id)) {
@@ -191,15 +262,25 @@ class ChallengeEditor extends Component {
191262
onCancel={this.closeLaunchModal}
192263
onConfirm={this.activateChallenge}
193264
/>
265+
const closeTaskModal = <ConfirmationModal
266+
title='Confirm Close Task'
267+
message={`Do you want to close task "${challengeDetails.name}"?`}
268+
theme={theme}
269+
isProcessing={isLaunching}
270+
errorMessage={this.state.launchError}
271+
onCancel={this.closeCloseTaskModal}
272+
onConfirm={this.closeTask}
273+
/>
194274
const successModal = <AlertModal
195275
title='Success'
196-
message='Challenge is activated successfully'
276+
message={suceessMessage}
197277
theme={theme}
198278
closeText='Ok'
199279
onClose={this.closeSuccessModal}
200280
/>
201281
return <div>
202282
{ showLaunchModal && activateModal }
283+
{ showCloseTaskModal && closeTaskModal }
203284
{ showSuccessModal && successModal }
204285
<Route
205286
exact
@@ -269,6 +350,7 @@ class ChallengeEditor extends Component {
269350
assignedMemberDetails={assignedMemberDetails}
270351
enableEdit={enableEdit}
271352
onLaunchChallenge={this.onLaunchChallenge}
353+
onCloseTask={this.onCloseTask}
272354
/>
273355
))
274356
} />

0 commit comments

Comments
 (0)