@@ -14,7 +14,14 @@ import ChallengeStatus from '../ChallengeStatus'
14
14
import ChallengeTag from '../ChallengeTag'
15
15
import styles from './ChallengeCard.module.scss'
16
16
import { getFormattedDuration , formatDate } from '../../../util/date'
17
- import { CHALLENGE_STATUS , COMMUNITY_APP_URL , DIRECT_PROJECT_URL , MESSAGE , ONLINE_REVIEW_URL } from '../../../config/constants'
17
+ import { checkChallengeEditPermission } from '../../../util/tc'
18
+ import {
19
+ CHALLENGE_STATUS ,
20
+ COMMUNITY_APP_URL ,
21
+ DIRECT_PROJECT_URL ,
22
+ MESSAGE ,
23
+ ONLINE_REVIEW_URL
24
+ } from '../../../config/constants'
18
25
import ConfirmationModal from '../../Modal/ConfirmationModal'
19
26
import AlertModal from '../../Modal/AlertModal'
20
27
import Tooltip from '../../Tooltip'
@@ -28,6 +35,9 @@ const DRAFT_MSG = 'In Draft'
28
35
const STALLED_TIME_LEFT_MSG = 'Challenge is currently on hold'
29
36
const FF_TIME_LEFT_MSG = 'Winner is working on fixes'
30
37
38
+ const PERMISSION_DELETE_MESSAGE_ERROR =
39
+ "You don't have permission to delete this challenge"
40
+
31
41
/**
32
42
* Format the remaining time of a challenge phase
33
43
* @param phase Challenge phase
@@ -56,7 +66,7 @@ const getTimeLeft = (phase, status) => {
56
66
* @param c Challenge
57
67
* @returns {{phaseMessage: string, endTime: {late, text}} }
58
68
*/
59
- const getPhaseInfo = ( c ) => {
69
+ const getPhaseInfo = c => {
60
70
const { currentPhaseNames, status, startDate, phases } = c
61
71
/* let checkPhases = (currentPhases && currentPhases.length > 0 ? currentPhases : allPhases)
62
72
if (_.isEmpty(checkPhases)) checkPhases = []
@@ -114,25 +124,36 @@ const hoverComponents = (challenge, onUpdateLaunch, deleteModalLaunch) => {
114
124
return challenge . legacyId || isTask ? (
115
125
< div className = { styles . linkGroup } >
116
126
< div className = { styles . linkGroupLeft } >
117
- < a className = { styles . link } href = { communityAppUrl } target = '_blank' > View Challenge</ a >
127
+ < a className = { styles . link } href = { communityAppUrl } target = '_blank' >
128
+ View Challenge
129
+ </ a >
118
130
{ ! isTask && (
119
131
< div className = { styles . linkGroupLeftBottom } >
120
- < a className = { styles . link } href = { directUrl } target = '_blank' > Direct</ a >
132
+ < a className = { styles . link } href = { directUrl } target = '_blank' >
133
+ Direct
134
+ </ a >
121
135
< span className = { styles . linkDivider } > |</ span >
122
- < a className = { styles . link } href = { orUrl } target = '_blank' > OR</ a >
136
+ < a className = { styles . link } href = { orUrl } target = '_blank' >
137
+ OR
138
+ </ a >
123
139
</ div >
124
140
) }
125
141
</ div >
126
142
{ challenge . status . toUpperCase ( ) === CHALLENGE_STATUS . DRAFT && (
127
- < button className = { styles . activateButton } onClick = { ( ) => onUpdateLaunch ( ) } >
143
+ < button
144
+ className = { styles . activateButton }
145
+ onClick = { ( ) => onUpdateLaunch ( ) }
146
+ >
128
147
< span > Activate</ span >
129
148
</ button >
130
149
) }
131
150
</ div >
132
151
) : (
133
152
< div className = { styles . linkGroup } >
134
153
< div className = { styles . linkGroupLeft } >
135
- < a className = { styles . link } href = { communityAppUrl } > View Challenge</ a >
154
+ < a className = { styles . link } href = { communityAppUrl } >
155
+ View Challenge
156
+ </ a >
136
157
{ ! isTask && (
137
158
< div className = { styles . linkGroupLeftBottom } >
138
159
< Tooltip content = { MESSAGE . NO_LEGACY_CHALLENGE } >
@@ -145,36 +166,41 @@ const hoverComponents = (challenge, onUpdateLaunch, deleteModalLaunch) => {
145
166
</ div >
146
167
) }
147
168
</ div >
148
- {
149
- challenge . status === 'Draft' && (
150
- < Tooltip content = { MESSAGE . NO_LEGACY_CHALLENGE } >
151
- { /* Don't disable button for real inside tooltip, otherwise mouseEnter/Leave events work not good */ }
152
- < button className = { cn ( styles . activateButton , styles . activateButtonDisabled ) } >
153
- < span > Activate </ span >
154
- </ button >
155
- </ Tooltip >
156
- )
157
- }
169
+ { challenge . status === 'Draft' && (
170
+ < Tooltip content = { MESSAGE . NO_LEGACY_CHALLENGE } >
171
+ { /* Don't disable button for real inside tooltip, otherwise mouseEnter/Leave events work not good */ }
172
+ < button
173
+ className = { cn ( styles . activateButton , styles . activateButtonDisabled ) }
174
+ >
175
+ < span > Activate </ span >
176
+ </ button >
177
+ </ Tooltip >
178
+ ) }
158
179
</ div >
159
180
)
160
181
}
161
182
162
- const renderStatus = ( status ) => {
183
+ const renderStatus = status => {
163
184
switch ( status ) {
164
185
case CHALLENGE_STATUS . ACTIVE :
165
186
case CHALLENGE_STATUS . NEW :
166
187
case CHALLENGE_STATUS . DRAFT :
167
188
case CHALLENGE_STATUS . COMPLETED :
168
- return ( < ChallengeStatus status = { status } /> )
189
+ return < ChallengeStatus status = { status } />
169
190
default :
170
- return ( < span className = { styles . statusText } > { status } </ span > )
191
+ return < span className = { styles . statusText } > { status } </ span >
171
192
}
172
193
}
173
194
174
- const renderLastUpdated = ( challenge ) => {
195
+ const renderLastUpdated = challenge => {
175
196
return (
176
- < Link className = { cn ( styles . col2 , styles . lastUpdated ) } to = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` } >
177
- < div className = { styles . lastUpdatedAt } > { formatDate ( challenge . updated ) } </ div >
197
+ < Link
198
+ className = { cn ( styles . col2 , styles . lastUpdated ) }
199
+ to = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` }
200
+ >
201
+ < div className = { styles . lastUpdatedAt } >
202
+ { formatDate ( challenge . updated ) }
203
+ </ div >
178
204
< div className = { styles . lastUpdatedBy } > { challenge . updatedBy } </ div >
179
205
</ Link >
180
206
)
@@ -187,7 +213,9 @@ class ChallengeCard extends React.Component {
187
213
isConfirm : false ,
188
214
isLaunch : false ,
189
215
isDeleteLaunch : false ,
190
- isSaving : false
216
+ isSaving : false ,
217
+ isCheckChalengePermission : false ,
218
+ hasEditChallengePermission : false
191
219
}
192
220
this . onUpdateConfirm = this . onUpdateConfirm . bind ( this )
193
221
this . onUpdateLaunch = this . onUpdateLaunch . bind ( this )
@@ -208,8 +236,19 @@ class ChallengeCard extends React.Component {
208
236
}
209
237
210
238
deleteModalLaunch ( ) {
239
+ const { challenge } = this . props
211
240
if ( ! this . state . isDeleteLaunch ) {
212
- this . setState ( { isDeleteLaunch : true } )
241
+ checkChallengeEditPermission ( challenge . id ) . then ( hasPermission => {
242
+ this . setState ( {
243
+ isCheckChalengePermission : false ,
244
+ hasEditChallengePermission : hasPermission
245
+ } )
246
+ } )
247
+ this . setState ( {
248
+ isDeleteLaunch : true ,
249
+ isCheckChalengePermission : true ,
250
+ hasEditChallengePermission : false
251
+ } )
213
252
}
214
253
}
215
254
@@ -232,9 +271,17 @@ class ChallengeCard extends React.Component {
232
271
}
233
272
// call action to update the challenge with a new status
234
273
await partiallyUpdateChallengeDetails ( challenge . id , payload )
235
- this . setState ( { isLaunch : true , isConfirm : challenge . id , isSaving : false } )
274
+ this . setState ( {
275
+ isLaunch : true ,
276
+ isConfirm : challenge . id ,
277
+ isSaving : false
278
+ } )
236
279
} catch ( e ) {
237
- const error = _ . get ( e , 'response.data.message' , 'Unable to activate the challenge' )
280
+ const error = _ . get (
281
+ e ,
282
+ 'response.data.message' ,
283
+ 'Unable to activate the challenge'
284
+ )
238
285
this . setState ( { isSaving : false , error } )
239
286
}
240
287
}
@@ -248,31 +295,49 @@ class ChallengeCard extends React.Component {
248
295
this . setState ( { isSaving : false } )
249
296
this . resetModal ( )
250
297
} catch ( e ) {
251
- const error = _ . get ( e , 'response.data.message' , 'Unable to Delete the challenge' )
298
+ const error = _ . get (
299
+ e ,
300
+ 'response.data.message' ,
301
+ 'Unable to Delete the challenge'
302
+ )
252
303
this . setState ( { isSaving : false , error } )
253
304
}
254
305
}
255
306
256
307
render ( ) {
257
- const { isLaunch, isConfirm, isSaving, isDeleteLaunch } = this . state
258
- const { challenge, shouldShowCurrentPhase, reloadChallengeList } = this . props
308
+ const { isLaunch, isConfirm, isSaving, isDeleteLaunch,
309
+ isCheckChalengePermission,
310
+ hasEditChallengePermission
311
+ } = this . state
312
+ const {
313
+ challenge,
314
+ shouldShowCurrentPhase,
315
+ reloadChallengeList
316
+ } = this . props
259
317
const { phaseMessage, endTime } = getPhaseInfo ( challenge )
318
+ const deleteMessage = isCheckChalengePermission
319
+ ? 'Checking permissions...'
320
+ : `Do you want to delete "${ challenge . name } "?`
321
+
260
322
return (
261
323
< div className = { styles . item } >
262
- {
263
- isDeleteLaunch && ! isConfirm && (
264
- < ConfirmationModal
265
- title = 'Confirm Delete'
266
- message = { `Do you want to delete "${ challenge . name } "?` }
267
- theme = { theme }
268
- isProcessing = { isSaving }
269
- errorMessage = { this . state . error }
270
- onCancel = { this . resetModal }
271
- onConfirm = { this . onDeleteChallenge }
272
- />
273
- )
274
- }
275
- { isLaunch && ! isConfirm && (
324
+ { isDeleteLaunch && ! isConfirm && (
325
+ < ConfirmationModal
326
+ title = 'Confirm Delete'
327
+ message = { deleteMessage }
328
+ theme = { theme }
329
+ isProcessing = { isSaving }
330
+ disableConfirmButton = { ! hasEditChallengePermission }
331
+ errorMessage = {
332
+ ! isCheckChalengePermission && ! hasEditChallengePermission
333
+ ? PERMISSION_DELETE_MESSAGE_ERROR
334
+ : this . state . error
335
+ }
336
+ onCancel = { this . resetModal }
337
+ onConfirm = { this . onDeleteChallenge }
338
+ />
339
+ ) }
340
+ { isLaunch && ! isConfirm && (
276
341
< ConfirmationModal
277
342
title = 'Confirm Launch'
278
343
message = { `Do you want to launch "${ challenge . name } "?` }
@@ -282,9 +347,8 @@ class ChallengeCard extends React.Component {
282
347
onCancel = { this . resetModal }
283
348
onConfirm = { this . onLaunchChallenge }
284
349
/>
285
- )
286
- }
287
- { isLaunch && isConfirm && (
350
+ ) }
351
+ { isLaunch && isConfirm && (
288
352
< AlertModal
289
353
title = 'Success'
290
354
message = { `Challenge "${ challenge . name } " is activated successfuly` }
@@ -295,25 +359,45 @@ class ChallengeCard extends React.Component {
295
359
okLink = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` }
296
360
onClose = { this . resetModal }
297
361
/>
298
- ) }
362
+ ) }
299
363
300
- < Link className = { styles . col1 } to = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` } >
364
+ < Link
365
+ className = { styles . col1 }
366
+ to = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` }
367
+ >
301
368
< div className = { styles . name } >
302
369
< span className = { styles . block } > { challenge . name } </ span >
303
- < ChallengeTag track = { challenge . trackId } challengeType = { challenge . type } />
304
- < span className = { styles . createdAt } > { `Created by ${ challenge . createdBy } at ${ formatDate ( challenge . created ) } ` } </ span >
370
+ < ChallengeTag
371
+ track = { challenge . trackId }
372
+ challengeType = { challenge . type }
373
+ />
374
+ < span className = { styles . createdAt } > { `Created by ${
375
+ challenge . createdBy
376
+ } at ${ formatDate ( challenge . created ) } `} </ span >
305
377
</ div >
306
378
</ Link >
307
379
{ renderLastUpdated ( challenge ) }
308
- < Link className = { styles . col2 } to = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` } >
380
+ < Link
381
+ className = { styles . col2 }
382
+ to = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` }
383
+ >
309
384
{ renderStatus ( challenge . status . toUpperCase ( ) ) }
310
385
</ Link >
311
- { shouldShowCurrentPhase && ( < Link className = { styles . col3 } to = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` } >
312
- < span className = { styles . block } > { phaseMessage } </ span >
313
- < span className = 'block light-text' > { endTime } </ span >
314
- </ Link > ) }
386
+ { shouldShowCurrentPhase && (
387
+ < Link
388
+ className = { styles . col3 }
389
+ to = { `/projects/${ challenge . projectId } /challenges/${ challenge . id } /view` }
390
+ >
391
+ < span className = { styles . block } > { phaseMessage } </ span >
392
+ < span className = 'block light-text' > { endTime } </ span >
393
+ </ Link >
394
+ ) }
315
395
< div className = { cn ( styles . col4 , styles . editingContainer ) } >
316
- { hoverComponents ( challenge , this . onUpdateLaunch , this . deleteModalLaunch ) }
396
+ { hoverComponents (
397
+ challenge ,
398
+ this . onUpdateLaunch ,
399
+ this . deleteModalLaunch
400
+ ) }
317
401
</ div >
318
402
< div className = { cn ( styles . col4 , styles . iconsContainer ) } >
319
403
< div className = { styles . faIconContainer } >
0 commit comments