Skip to content

Commit 85d8f44

Browse files
authored
Merge pull request topcoder-platform#1030 from mark-nakachon/fixes-#927
fixes - topcoder-platform#927
2 parents 6a1758e + b614c36 commit 85d8f44

File tree

12 files changed

+208
-22
lines changed

12 files changed

+208
-22
lines changed

src/actions/challenges.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
fetchChallengeTracks,
1616
updateChallenge,
1717
patchChallenge,
18+
deleteChallenge as deleteChallengeAPI,
1819
createChallenge as createChallengeAPI,
1920
createResource as createResourceAPI,
2021
deleteResource as deleteResourceAPI
@@ -38,6 +39,9 @@ import {
3839
CREATE_CHALLENGE_PENDING,
3940
CREATE_CHALLENGE_SUCCESS,
4041
CREATE_CHALLENGE_FAILURE,
42+
DELETE_CHALLENGE_PENDING,
43+
DELETE_CHALLENGE_SUCCESS,
44+
DELETE_CHALLENGE_FAILURE,
4145
LOAD_CHALLENGE_RESOURCES
4246
} from '../config/constants'
4347
import { loadProject } from './projects'
@@ -267,6 +271,26 @@ export function partiallyUpdateChallengeDetails (challengeId, partialChallengeDe
267271
}
268272
}
269273

274+
export function deleteChallenge (challengeId) {
275+
return async (dispatch) => {
276+
dispatch({
277+
type: DELETE_CHALLENGE_PENDING
278+
})
279+
280+
return deleteChallengeAPI(challengeId).then((challenge) => {
281+
return dispatch({
282+
type: DELETE_CHALLENGE_SUCCESS,
283+
challengeDetails: challenge
284+
})
285+
}).catch((error) => {
286+
dispatch({
287+
type: DELETE_CHALLENGE_FAILURE
288+
})
289+
throw error
290+
})
291+
}
292+
}
293+
270294
export function loadTimelineTemplates () {
271295
return async (dispatch) => {
272296
const timelineTemplates = await fetchTimelineTemplates()

src/components/ChallengeEditor/ChallengeEditor.module.scss

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@
241241
.actionButtons {
242242
position: absolute;
243243
top: 30px;
244-
a {
244+
a,button {
245245
height: 40px;
246246
}
247247
}
@@ -251,7 +251,13 @@
251251
}
252252

253253
.actionButtonsRight {
254+
display: flex;
255+
align-items: center;
254256
right: 20px;
257+
258+
button {
259+
margin-right: 20px;
260+
}
255261
}
256262

257263
.buttonContainer {

src/components/ChallengeEditor/index.js

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class ChallengeEditor extends Component {
6868
super(props)
6969
this.state = {
7070
isLaunch: false,
71+
isDeleteLaunch: false,
7172
isConfirm: false,
7273
isClose: false,
7374
isOpenAdvanceSettings: false,
@@ -121,6 +122,8 @@ class ChallengeEditor extends Component {
121122
this.getAvailableTimelineTemplates = this.getAvailableTimelineTemplates.bind(this)
122123
this.autoUpdateChallengeThrottled = _.throttle(this.validateAndAutoUpdateChallenge.bind(this), 3000) // 3s
123124
this.updateResource = this.updateResource.bind(this)
125+
this.onDeleteChallenge = this.onDeleteChallenge.bind(this)
126+
this.deleteModalLaunch = this.deleteModalLaunch.bind(this)
124127
}
125128

126129
componentDidMount () {
@@ -131,6 +134,27 @@ class ChallengeEditor extends Component {
131134
this.resetChallengeData(this.setState.bind(this))
132135
}
133136

137+
deleteModalLaunch () {
138+
if (!this.state.isDeleteLaunch) {
139+
this.setState({ isDeleteLaunch: true })
140+
}
141+
}
142+
143+
async onDeleteChallenge () {
144+
const { deleteChallenge, challengeDetails, history } = this.props
145+
try {
146+
this.setState({ isSaving: true })
147+
// Call action to delete the challenge
148+
await deleteChallenge(challengeDetails.id)
149+
this.setState({ isSaving: false })
150+
this.resetModal()
151+
history.push(`/projects/${challengeDetails.projectId}/challenges`)
152+
} catch (e) {
153+
const error = _.get(e, 'response.data.message', 'Unable to Delete the challenge')
154+
this.setState({ isSaving: false, error })
155+
}
156+
}
157+
134158
/**
135159
* Validates challenge and if its valid calling an autosave method
136160
*
@@ -206,7 +230,7 @@ class ChallengeEditor extends Component {
206230
}
207231

208232
resetModal () {
209-
this.setState({ isLoading: false, isConfirm: false, isLaunch: false, error: null, isCloseTask: false })
233+
this.setState({ isLoading: false, isConfirm: false, isLaunch: false, error: null, isCloseTask: false, isDeleteLaunch: false })
210234
}
211235

212236
/**
@@ -1373,6 +1397,19 @@ class ChallengeEditor extends Component {
13731397
/>
13741398
</div>
13751399
}
1400+
{
1401+
this.state.isDeleteLaunch && !this.state.isConfirm && (
1402+
<ConfirmationModal
1403+
title='Confirm Delete'
1404+
message={`Do you want to delete "${challenge.name}"?`}
1405+
theme={theme}
1406+
isProcessing={isSaving}
1407+
errorMessage={this.state.error}
1408+
onCancel={this.resetModal}
1409+
onConfirm={this.onDeleteChallenge}
1410+
/>
1411+
)
1412+
}
13761413
{ showTimeline && (
13771414
<ChallengeScheduleField
13781415
templates={this.getAvailableTimelineTemplates()}
@@ -1426,6 +1463,7 @@ class ChallengeEditor extends Component {
14261463
</div>
14271464
<div className={styles.title}>{getTitle(isNew)}</div>
14281465
<div className={cn(styles.actionButtons, styles.actionButtonsRight)}>
1466+
{this.props.challengeDetails.status === 'New' && <PrimaryButton text={'Delete'} type={'danger'} onClick={this.deleteModalLaunch} />}
14291467
<PrimaryButton text={'Back'} type={'info'} submit link={`/projects/${projectDetail.id}/challenges`} />
14301468
</div>
14311469
<div className={styles.textRequired}>* Required</div>
@@ -1469,7 +1507,8 @@ ChallengeEditor.propTypes = {
14691507
updateChallengeDetails: PropTypes.func.isRequired,
14701508
createChallenge: PropTypes.func,
14711509
replaceResourceInRole: PropTypes.func,
1472-
partiallyUpdateChallengeDetails: PropTypes.func.isRequired
1510+
partiallyUpdateChallengeDetails: PropTypes.func.isRequired,
1511+
deleteChallenge: PropTypes.func.isRequired
14731512
}
14741513

14751514
export default withRouter(ChallengeEditor)

src/components/ChallengesComponent/ChallengeCard/ChallengeCard.module.scss

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,31 @@
257257
}
258258
}
259259

260+
.deleteButton {
261+
height: 22px;
262+
width: 86px;
263+
border-radius: 11.5px;
264+
display: flex;
265+
justify-content: center;
266+
align-items: center;
267+
background-color: $tc-red;
268+
border-color: $tc-red;
269+
cursor: pointer;
270+
271+
span {
272+
@include roboto;
273+
274+
font-size: 14px;
275+
font-weight: 400;
276+
line-height: 17px;
277+
color: $white;
278+
text-transform: capitalize;
279+
display: flex;
280+
justify-content: center;
281+
align-items: center;
282+
}
283+
}
284+
260285
.icon {
261286
vertical-align: bottom;
262287
}

src/components/ChallengesComponent/ChallengeCard/index.js

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,20 @@ const getPhaseInfo = (c) => {
9696
* @param onUpdateLaunch
9797
* @returns {*}
9898
*/
99-
const hoverComponents = (challenge, onUpdateLaunch) => {
99+
const hoverComponents = (challenge, onUpdateLaunch, deleteModalLaunch) => {
100100
const communityAppUrl = `${COMMUNITY_APP_URL}/challenges/${challenge.id}`
101101
const directUrl = `${DIRECT_PROJECT_URL}/contest/detail?projectId=${challenge.legacyId}`
102102
const orUrl = `${ONLINE_REVIEW_URL}/review/actions/ViewProjectDetails?pid=${challenge.legacyId}`
103103

104104
// NEW projects never have Legacy challenge created, so don't show links and "Activate" button for them at all
105105
if (challenge.status.toUpperCase() === CHALLENGE_STATUS.NEW) {
106-
return null
106+
if (challenge.status.toUpperCase() === CHALLENGE_STATUS.NEW) {
107+
return (
108+
<button className={styles.deleteButton} onClick={deleteModalLaunch}>
109+
<span>Delete</span>
110+
</button>
111+
)
112+
}
107113
}
108114

109115
return challenge.legacyId ? (
@@ -177,10 +183,13 @@ class ChallengeCard extends React.Component {
177183
this.state = {
178184
isConfirm: false,
179185
isLaunch: false,
186+
isDeleteLaunch: false,
180187
isSaving: false
181188
}
182189
this.onUpdateConfirm = this.onUpdateConfirm.bind(this)
183190
this.onUpdateLaunch = this.onUpdateLaunch.bind(this)
191+
this.onDeleteChallenge = this.onDeleteChallenge.bind(this)
192+
this.deleteModalLaunch = this.deleteModalLaunch.bind(this)
184193
this.resetModal = this.resetModal.bind(this)
185194
this.onLaunchChallenge = this.onLaunchChallenge.bind(this)
186195
}
@@ -195,8 +204,14 @@ class ChallengeCard extends React.Component {
195204
}
196205
}
197206

207+
deleteModalLaunch () {
208+
if (!this.state.isDeleteLaunch) {
209+
this.setState({ isDeleteLaunch: true })
210+
}
211+
}
212+
198213
resetModal () {
199-
this.setState({ isConfirm: false, isLaunch: false })
214+
this.setState({ isConfirm: false, isLaunch: false, isDeleteLaunch: false })
200215
}
201216

202217
async onLaunchChallenge () {
@@ -216,12 +231,39 @@ class ChallengeCard extends React.Component {
216231
}
217232
}
218233

234+
async onDeleteChallenge () {
235+
const { deleteChallenge, challenge } = this.props
236+
try {
237+
this.setState({ isSaving: true })
238+
// Call action to delete the challenge
239+
await deleteChallenge(challenge.id)
240+
this.setState({ isSaving: false })
241+
this.resetModal()
242+
} catch (e) {
243+
const error = _.get(e, 'response.data.message', 'Unable to Delete the challenge')
244+
this.setState({ isSaving: false, error })
245+
}
246+
}
247+
219248
render () {
220-
const { isLaunch, isConfirm, isSaving } = this.state
249+
const { isLaunch, isConfirm, isSaving, isDeleteLaunch } = this.state
221250
const { challenge, shouldShowCurrentPhase, reloadChallengeList } = this.props
222251
const { phaseMessage, endTime } = getPhaseInfo(challenge)
223252
return (
224253
<div className={styles.item}>
254+
{
255+
isDeleteLaunch && !isConfirm && (
256+
<ConfirmationModal
257+
title='Confirm Delete'
258+
message={`Do you want to delete "${challenge.name}"?`}
259+
theme={theme}
260+
isProcessing={isSaving}
261+
errorMessage={this.state.error}
262+
onCancel={this.resetModal}
263+
onConfirm={this.onDeleteChallenge}
264+
/>
265+
)
266+
}
225267
{ isLaunch && !isConfirm && (
226268
<ConfirmationModal
227269
title='Confirm Launch'
@@ -263,7 +305,7 @@ class ChallengeCard extends React.Component {
263305
<span className='block light-text'>{endTime}</span>
264306
</Link>)}
265307
<div className={cn(styles.col4, styles.editingContainer)}>
266-
{hoverComponents(challenge, this.onUpdateLaunch, this.props.showError)}
308+
{hoverComponents(challenge, this.onUpdateLaunch, this.deleteModalLaunch)}
267309
</div>
268310
<div className={cn(styles.col4, styles.iconsContainer)}>
269311
<div className={styles.faIconContainer}>
@@ -282,16 +324,15 @@ class ChallengeCard extends React.Component {
282324

283325
ChallengeCard.defaultPrps = {
284326
shouldShowCurrentPhase: true,
285-
showError: () => {},
286327
reloadChallengeList: () => {}
287328
}
288329

289330
ChallengeCard.propTypes = {
290331
challenge: PropTypes.object,
291332
shouldShowCurrentPhase: PropTypes.bool,
292-
showError: PropTypes.func,
293333
reloadChallengeList: PropTypes.func,
294-
partiallyUpdateChallengeDetails: PropTypes.func.isRequired
334+
partiallyUpdateChallengeDetails: PropTypes.func.isRequired,
335+
deleteChallenge: PropTypes.func.isRequired
295336
}
296337

297338
export default withRouter(ChallengeCard)

src/components/ChallengesComponent/ChallengeList/index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ class ChallengeList extends Component {
102102
page,
103103
perPage,
104104
totalChallenges,
105-
partiallyUpdateChallengeDetails
105+
partiallyUpdateChallengeDetails,
106+
deleteChallenge
106107
} = this.props
107108
if (warnMessage) {
108109
return <Message warnMessage={warnMessage} />
@@ -211,9 +212,9 @@ class ChallengeList extends Component {
211212
<ChallengeCard
212213
shouldShowCurrentPhase={selectedTab === 0}
213214
challenge={c}
214-
showError={this.showError}
215215
reloadChallengeList={this.reloadChallengeList}
216216
partiallyUpdateChallengeDetails={partiallyUpdateChallengeDetails}
217+
deleteChallenge={deleteChallenge}
217218
/>
218219
</li>
219220
)
@@ -256,7 +257,8 @@ ChallengeList.propTypes = {
256257
page: PropTypes.number.isRequired,
257258
perPage: PropTypes.number.isRequired,
258259
totalChallenges: PropTypes.number.isRequired,
259-
partiallyUpdateChallengeDetails: PropTypes.func.isRequired
260+
partiallyUpdateChallengeDetails: PropTypes.func.isRequired,
261+
deleteChallenge: PropTypes.func.isRequired
260262
}
261263

262264
export default ChallengeList

src/components/ChallengesComponent/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ const ChallengesComponent = ({
2626
page,
2727
perPage,
2828
totalChallenges,
29-
partiallyUpdateChallengeDetails
29+
partiallyUpdateChallengeDetails,
30+
deleteChallenge
3031
}) => {
3132
return (
3233
<Sticky top={10}>
@@ -86,6 +87,7 @@ const ChallengesComponent = ({
8687
perPage={perPage}
8788
totalChallenges={totalChallenges}
8889
partiallyUpdateChallengeDetails={partiallyUpdateChallengeDetails}
90+
deleteChallenge={deleteChallenge}
8991
/>
9092
)}
9193
</div>
@@ -109,7 +111,8 @@ ChallengesComponent.propTypes = {
109111
page: PropTypes.number.isRequired,
110112
perPage: PropTypes.number.isRequired,
111113
totalChallenges: PropTypes.number.isRequired,
112-
partiallyUpdateChallengeDetails: PropTypes.func.isRequired
114+
partiallyUpdateChallengeDetails: PropTypes.func.isRequired,
115+
deleteChallenge: PropTypes.func.isRequired
113116
}
114117

115118
ChallengesComponent.defaultProps = {

src/config/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ export const CREATE_CHALLENGE_SUCCESS = 'CREATE_CHALLENGE_SUCCESS'
4848
export const CREATE_CHALLENGE_PENDING = 'CREATE_CHALLENGE_PENDING'
4949
export const CREATE_CHALLENGE_FAILURE = 'CREATE_CHALLENGE_FAILURE'
5050

51+
export const DELETE_CHALLENGE_SUCCESS = 'DELETE_CHALLENGE_SUCCESS'
52+
export const DELETE_CHALLENGE_PENDING = 'DELETE_CHALLENGE_PENDING'
53+
export const DELETE_CHALLENGE_FAILURE = 'DELETE_CHALLENGE_FAILURE'
54+
5155
export const LOAD_PROJECT_DETAILS = 'LOAD_PROJECT_DETAILS'
5256
export const LOAD_PROJECT_DETAILS_SUCCESS = 'LOAD_PROJECT_DETAILS_SUCCESS'
5357
export const LOAD_PROJECT_DETAILS_PENDING = 'LOAD_PROJECT_DETAILS_PENDING'

0 commit comments

Comments
 (0)