Skip to content

Commit 8f00892

Browse files
committed
Allow for add / delete users on the Resources tab
https://topcoder.atlassian.net/browse/PROD-4270
1 parent a31fcc9 commit 8f00892

File tree

13 files changed

+510
-25
lines changed

13 files changed

+510
-25
lines changed

src/actions/challenges.js

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ import {
3535
REMOVE_ATTACHMENT_FAILURE,
3636
REMOVE_ATTACHMENT_PENDING,
3737
REMOVE_ATTACHMENT_SUCCESS,
38-
CREATE_CHALLENGE_RESOURCE,
38+
CREATE_CHALLENGE_RESOURCE_PENDING,
39+
CREATE_CHALLENGE_RESOURCE_SUCCESS,
40+
CREATE_CHALLENGE_RESOURCE_FAILURE,
3941
DELETE_CHALLENGE_RESOURCE,
4042
PAGE_SIZE,
4143
UPDATE_CHALLENGE_DETAILS_PENDING,
@@ -661,18 +663,41 @@ export function deleteResource (challengeId, roleId, memberHandle) {
661663
* @param {UUID} challengeId id of the challenge for which resource is to be created
662664
* @param {UUID} roleId id of the role, the resource should be in
663665
* @param {String} memberHandle handle of the resource
666+
* @param {String} email email of member
667+
* @param {String} userId id of member
664668
*/
665-
export function createResource (challengeId, roleId, memberHandle) {
669+
export function createResource (challengeId, roleId, memberHandle, email, userId) {
666670
const resource = {
667671
challengeId,
668672
roleId,
669673
memberHandle
670674
}
671-
return (dispatch, getState) => {
672-
return dispatch({
673-
type: CREATE_CHALLENGE_RESOURCE,
674-
payload: createResourceAPI(resource)
675+
return async (dispatch, getState) => {
676+
dispatch({
677+
type: CREATE_CHALLENGE_RESOURCE_PENDING
675678
})
679+
680+
try {
681+
const newResource = await createResourceAPI(resource)
682+
let userEmail = email
683+
if (!userEmail) {
684+
const memberInfos = await searchProfilesByUserIds([userId])
685+
if (memberInfos.length > 0) {
686+
userEmail = memberInfos[0].email
687+
}
688+
}
689+
dispatch({
690+
type: CREATE_CHALLENGE_RESOURCE_SUCCESS,
691+
payload: {
692+
...newResource,
693+
email: userEmail
694+
}
695+
})
696+
} catch (error) {
697+
dispatch({
698+
type: CREATE_CHALLENGE_RESOURCE_FAILURE
699+
})
700+
}
676701
}
677702
}
678703

src/assets/images/ico-trash.svg

Lines changed: 3 additions & 0 deletions
Loading

src/components/ChallengeEditor/ChallengeViewTabs/index.js

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import LegacyLinks from '../../LegacyLinks'
1313
import ForumLink from '../../ForumLink'
1414
import ResourcesTab from '../Resources'
1515
import Submissions from '../Submissions'
16-
import { checkAdmin, checkReadOnlyRoles } from '../../../util/tc'
16+
import { checkAdmin, checkEditResourceRoles, checkReadOnlyRoles } from '../../../util/tc'
1717
import { CHALLENGE_STATUS, MESSAGE } from '../../../config/constants'
1818
import Tooltip from '../../Tooltip'
1919
import CancelDropDown from '../Cancel-Dropdown'
2020
import 'react-tabs/style/react-tabs.css'
2121
import styles from './ChallengeViewTabs.module.scss'
22+
import ResourcesAdd from '../ResourcesAdd'
2223

2324
function getSelectorStyle (selectedView, currentView) {
2425
return cn(styles['challenge-selector-common'], {
@@ -47,9 +48,13 @@ const ChallengeViewTabs = ({
4748
assignYourselfCopilot,
4849
showRejectChallengeModal,
4950
loggedInUser,
50-
onApproveChallenge
51+
onApproveChallenge,
52+
createResource,
53+
deleteResource
5154
}) => {
5255
const [selectedTab, setSelectedTab] = useState(0)
56+
const [showAddResourceModal, setShowAddResourceModal] = useState(false)
57+
const { resourceRoles } = metadata
5358
const loggedInUserResource = useMemo(
5459
() => {
5560
if (!loggedInUser) {
@@ -60,7 +65,6 @@ const ChallengeViewTabs = ({
6065
if (loggedInUserResourceTmps.length > 0) {
6166
loggedInUserResourceTmp = loggedInUserResourceTmps[0]
6267
loggedInUserResourceTmp.resources = loggedInUserResourceTmps
63-
const { resourceRoles } = metadata
6468
if (resourceRoles) {
6569
let roles = []
6670
_.forEach(loggedInUserResourceTmps, resource => {
@@ -74,12 +78,21 @@ const ChallengeViewTabs = ({
7478
},
7579
[loggedInUser, challengeResources, metadata]
7680
)
81+
const canEditResource = useMemo(
82+
() =>
83+
((loggedInUserResource &&
84+
checkEditResourceRoles(loggedInUserResource.roles)) ||
85+
checkAdmin(token)) &&
86+
selectedTab === 1,
87+
[loggedInUserResource, token, selectedTab]
88+
)
7789

7890
const allResources = useMemo(() => {
79-
const { resourceRoles } = metadata
8091
return challengeResources.map(rs => {
81-
const roleInfo = _.find(resourceRoles, { id: rs.roleId })
82-
rs.role = roleInfo ? roleInfo.name : ''
92+
if (!rs.role) {
93+
const roleInfo = _.find(resourceRoles, { id: rs.roleId })
94+
rs.role = roleInfo ? roleInfo.name : ''
95+
}
8396
return rs
8497
})
8598
}, [metadata, challengeResources])
@@ -180,9 +193,14 @@ const ChallengeViewTabs = ({
180193
)}
181194
</div>
182195
)}
183-
{enableEdit && (
196+
{enableEdit && !canEditResource && (
184197
<PrimaryButton text={'Edit'} type={'info'} submit link={`./edit`} />
185198
)}
199+
{canEditResource && (
200+
<PrimaryButton text={'Add'} type={'info'} onClick={() => {
201+
setShowAddResourceModal(true)
202+
}} />
203+
)}
186204
{isSelfService && isDraft && (isAdmin || isSelfServiceCopilot || enableEdit) && (
187205
<div className={styles.button}>
188206
<PrimaryButton
@@ -192,7 +210,7 @@ const ChallengeViewTabs = ({
192210
/>
193211
</div>
194212
)}
195-
<PrimaryButton text={'Back'} type={'info'} submit link={`..`} />
213+
{!canEditResource ? (<PrimaryButton text={'Back'} type={'info'} submit link={`..`} />) : null}
196214
</div>
197215
</div>
198216
<div className={styles['challenge-view-selector']}>
@@ -264,7 +282,12 @@ const ChallengeViewTabs = ({
264282
/>
265283
)}
266284
{selectedTab === 1 && (
267-
<ResourcesTab challenge={challenge} resources={allResources} />
285+
<ResourcesTab
286+
challenge={challenge}
287+
resources={allResources}
288+
canEditResource={canEditResource}
289+
deleteResource={deleteResource}
290+
/>
268291
)}
269292
{selectedTab === 2 && (
270293
<Submissions
@@ -274,6 +297,13 @@ const ChallengeViewTabs = ({
274297
loggedInUserResource={loggedInUserResource}
275298
/>
276299
)}
300+
{showAddResourceModal ? (<ResourcesAdd
301+
onClose={() => setShowAddResourceModal(false)}
302+
challenge={challenge}
303+
loggedInUser={loggedInUser}
304+
resourceRoles={resourceRoles}
305+
createResource={createResource}
306+
/>) : null}
277307
</div>
278308
)
279309
}
@@ -304,6 +334,8 @@ ChallengeViewTabs.propTypes = {
304334
onCloseTask: PropTypes.func,
305335
projectPhases: PropTypes.arrayOf(PropTypes.object),
306336
assignYourselfCopilot: PropTypes.func.isRequired,
337+
createResource: PropTypes.func.isRequired,
338+
deleteResource: PropTypes.func.isRequired,
307339
showRejectChallengeModal: PropTypes.func.isRequired,
308340
loggedInUser: PropTypes.object.isRequired,
309341
onApproveChallenge: PropTypes.func

src/components/ChallengeEditor/Resources/index.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import { getTCMemberURL } from '../../../config/constants'
1212
import ReactSVG from 'react-svg'
1313
import { getRatingLevel, sortList } from '../../../util/tc'
1414
import styles from './styles.module.scss'
15+
import ResourcesDeleteModal from '../ResourcesDeleteModal'
1516

1617
const assets = require.context('../../../assets/images', false, /svg/)
1718
const ArrowDown = './arrow-down.svg'
19+
const Trash = './ico-trash.svg'
1820

1921
function getSelectorStyle (selectedView, currentView) {
2022
return cn(styles['challenge-selector-common'], {
@@ -59,7 +61,8 @@ export default class Resources extends React.Component {
5961
field: '',
6062
sort: ''
6163
},
62-
selectedTab: 0
64+
selectedTab: 0,
65+
showDeleteResourceModal: null
6366
}
6467

6568
this.sortResources = this.sortResources.bind(this)
@@ -180,10 +183,10 @@ export default class Resources extends React.Component {
180183
}
181184

182185
render () {
183-
const { challenge } = this.props
186+
const { challenge, canEditResource, deleteResource } = this.props
184187
const { track } = challenge
185188

186-
const { sortedResources, selectedTab } = this.state
189+
const { sortedResources, selectedTab, showDeleteResourceModal } = this.state
187190

188191
const { field, sort } = this.getResourcesSortParam()
189192
const revertSort = sort === 'desc' ? 'asc' : 'desc'
@@ -312,6 +315,12 @@ export default class Resources extends React.Component {
312315
</div>
313316
</button>
314317
</th>
318+
319+
{canEditResource ? (<th
320+
className={cn(styles['col-8Table'])}
321+
>
322+
<span>Actions</span>
323+
</th>) : null}
315324
</tr>
316325
</thead>
317326
<tbody role='rowgroup'>
@@ -343,12 +352,29 @@ export default class Resources extends React.Component {
343352
<td className={styles['col-4']}>
344353
<span role='cell'>{formatDate(r.created)}</span>
345354
</td>
355+
356+
{canEditResource ? (<td className={cn(styles['col-8Table'], styles['col-bodyTable'])}>
357+
<button
358+
onClick={() => {
359+
this.setState({
360+
showDeleteResourceModal: r
361+
})
362+
}}
363+
>
364+
<ReactSVG path={assets(`${Trash}`)} />
365+
</button>
366+
</td>) : null}
346367
</tr>
347368
)
348369
})}
349370
</tbody>
350371
</table>
351372
</div>
373+
{showDeleteResourceModal ? (<ResourcesDeleteModal
374+
onClose={() => this.setState({ showDeleteResourceModal: null })}
375+
resource={showDeleteResourceModal}
376+
deleteResource={deleteResource}
377+
/>) : null}
352378
</div>
353379
)
354380
}
@@ -382,5 +408,7 @@ Resources.propTypes = {
382408
resourcesSort: PT.shape({
383409
field: PT.string,
384410
sort: PT.string
385-
})
411+
}),
412+
canEditResource: PT.bool.isRequired,
413+
deleteResource: PT.func.isRequired
386414
}

src/components/ChallengeEditor/Resources/styles.module.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ $tc-white: #FFFFFF;
6666
white-space: nowrap;
6767
overflow: hidden;
6868
}
69+
70+
button {
71+
padding: 0;
72+
border: none;
73+
background-color: transparent;
74+
outline: none;
75+
}
6976
}
7077
}
7178

0 commit comments

Comments
 (0)