Skip to content

Commit f2408b2

Browse files
authored
Merge pull request #1034 from mark-nakachon/fixes-#927
fixes - #927
2 parents 6597d74 + a000be0 commit f2408b2

File tree

12 files changed

+206
-20
lines changed

12 files changed

+206
-20
lines changed

src/actions/challenges.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
fetchGroupDetail,
1717
updateChallenge,
1818
patchChallenge,
19+
deleteChallenge as deleteChallengeAPI,
1920
createChallenge as createChallengeAPI,
2021
createResource as createResourceAPI,
2122
deleteResource as deleteResourceAPI
@@ -39,6 +40,9 @@ import {
3940
CREATE_CHALLENGE_PENDING,
4041
CREATE_CHALLENGE_SUCCESS,
4142
CREATE_CHALLENGE_FAILURE,
43+
DELETE_CHALLENGE_PENDING,
44+
DELETE_CHALLENGE_SUCCESS,
45+
DELETE_CHALLENGE_FAILURE,
4246
LOAD_CHALLENGE_RESOURCES
4347
} from '../config/constants'
4448
import { loadProject } from './projects'
@@ -276,6 +280,26 @@ export function partiallyUpdateChallengeDetails (challengeId, partialChallengeDe
276280
}
277281
}
278282

283+
export function deleteChallenge (challengeId) {
284+
return async (dispatch) => {
285+
dispatch({
286+
type: DELETE_CHALLENGE_PENDING
287+
})
288+
289+
return deleteChallengeAPI(challengeId).then((challenge) => {
290+
return dispatch({
291+
type: DELETE_CHALLENGE_SUCCESS,
292+
challengeDetails: challenge
293+
})
294+
}).catch((error) => {
295+
dispatch({
296+
type: DELETE_CHALLENGE_FAILURE
297+
})
298+
throw error
299+
})
300+
}
301+
}
302+
279303
export function loadTimelineTemplates () {
280304
return async (dispatch) => {
281305
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: 40 additions & 1 deletion
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,
@@ -122,6 +123,8 @@ class ChallengeEditor extends Component {
122123
this.getAvailableTimelineTemplates = this.getAvailableTimelineTemplates.bind(this)
123124
this.autoUpdateChallengeThrottled = _.throttle(this.validateAndAutoUpdateChallenge.bind(this), 3000) // 3s
124125
this.updateResource = this.updateResource.bind(this)
126+
this.onDeleteChallenge = this.onDeleteChallenge.bind(this)
127+
this.deleteModalLaunch = this.deleteModalLaunch.bind(this)
125128
}
126129

127130
componentDidMount () {
@@ -132,6 +135,27 @@ class ChallengeEditor extends Component {
132135
this.resetChallengeData(this.setState.bind(this))
133136
}
134137

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

209233
resetModal () {
210-
this.setState({ isLoading: false, isConfirm: false, isLaunch: false, error: null, isCloseTask: false })
234+
this.setState({ isLoading: false, isConfirm: false, isLaunch: false, error: null, isCloseTask: false, isDeleteLaunch: false })
211235
}
212236

213237
/**
@@ -1391,6 +1415,19 @@ class ChallengeEditor extends Component {
13911415
/>
13921416
</div>
13931417
}
1418+
{
1419+
this.state.isDeleteLaunch && !this.state.isConfirm && (
1420+
<ConfirmationModal
1421+
title='Confirm Delete'
1422+
message={`Do you want to delete "${challenge.name}"?`}
1423+
theme={theme}
1424+
isProcessing={isSaving}
1425+
errorMessage={this.state.error}
1426+
onCancel={this.resetModal}
1427+
onConfirm={this.onDeleteChallenge}
1428+
/>
1429+
)
1430+
}
13941431
{ showTimeline && (
13951432
<ChallengeScheduleField
13961433
templates={this.getAvailableTimelineTemplates()}
@@ -1444,6 +1481,7 @@ class ChallengeEditor extends Component {
14441481
</div>
14451482
<div className={styles.title}>{getTitle(isNew)}</div>
14461483
<div className={cn(styles.actionButtons, styles.actionButtonsRight)}>
1484+
{this.props.challengeDetails.status === 'New' && <PrimaryButton text={'Delete'} type={'danger'} onClick={this.deleteModalLaunch} />}
14471485
<PrimaryButton text={'Back'} type={'info'} submit link={`/projects/${projectDetail.id}/challenges`} />
14481486
</div>
14491487
<div className={styles.textRequired}>* Required</div>
@@ -1488,6 +1526,7 @@ ChallengeEditor.propTypes = {
14881526
createChallenge: PropTypes.func,
14891527
replaceResourceInRole: PropTypes.func,
14901528
partiallyUpdateChallengeDetails: PropTypes.func.isRequired,
1529+
deleteChallenge: PropTypes.func.isRequired,
14911530
loggedInUser: PropTypes.shape().isRequired
14921531
}
14931532

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)