Skip to content

Commit 42e921c

Browse files
author
vikasrohit
authored
Merge pull request #834 from topcoder-platform/feature/assign-task-add-submitter-resurce
feat: git#833-Save fails after changing assigned user for a task more than once
2 parents d29d3c9 + a6d5092 commit 42e921c

File tree

9 files changed

+138
-51
lines changed

9 files changed

+138
-51
lines changed

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"react-tabs": "^3.0.0",
8484
"redux": "^4.0.1",
8585
"redux-logger": "^3.0.6",
86+
"redux-promise-middleware": "4.2.1",
8687
"redux-thunk": "^2.3.0",
8788
"resolve": "1.8.1",
8889
"sass-loader": "7.1.0",

src/actions/challenges.js

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ import {
1515
fetchChallengeTracks,
1616
updateChallenge,
1717
patchChallenge,
18-
createChallenge as createChallengeAPI
18+
createChallenge as createChallengeAPI,
19+
createResource as createResourceAPI,
20+
deleteResource as deleteResourceAPI
1921
} from '../services/challenges'
2022
import {
2123
LOAD_CHALLENGE_DETAILS_PENDING,
@@ -32,6 +34,8 @@ import {
3234
LOAD_CHALLENGE_RESOURCES_PENDING,
3335
LOAD_CHALLENGE_RESOURCES_SUCCESS,
3436
LOAD_CHALLENGE_RESOURCES_FAILURE,
37+
CREATE_CHALLENGE_RESOURCE,
38+
DELETE_CHALLENGE_RESOURCE,
3539
REMOVE_ATTACHMENT,
3640
PAGE_SIZE,
3741
UPDATE_CHALLENGE_DETAILS_PENDING,
@@ -452,3 +456,51 @@ export function loadResourceRoles () {
452456
})
453457
}
454458
}
459+
460+
export function deleteResource (challengeId, roleId, memberHandle) {
461+
const resource = {
462+
challengeId,
463+
roleId,
464+
memberHandle
465+
}
466+
return (dispatch, getState) => {
467+
return dispatch({
468+
type: DELETE_CHALLENGE_RESOURCE,
469+
payload: deleteResourceAPI(resource)
470+
})
471+
}
472+
}
473+
474+
export function createResource (challengeId, roleId, memberHandle) {
475+
const resource = {
476+
challengeId,
477+
roleId,
478+
memberHandle
479+
}
480+
return (dispatch, getState) => {
481+
return dispatch({
482+
type: CREATE_CHALLENGE_RESOURCE,
483+
payload: createResourceAPI(resource)
484+
})
485+
}
486+
}
487+
488+
export function replaceResourceInRole (challengeId, roleId, newMember, oldMember) {
489+
return async (dispatch) => {
490+
if (newMember === oldMember) {
491+
return
492+
}
493+
if (oldMember) {
494+
try {
495+
await dispatch(deleteResource(challengeId, roleId, oldMember))
496+
} catch (error) {
497+
const errorMessage = _.get(error, 'response.data.message')
498+
// ignore error where the resource does not exist already
499+
if (errorMessage.indexOf('doesn\'t have resource with roleId') === -1) {
500+
return Promise.reject(new Error('Unable to delete resource'))
501+
}
502+
}
503+
}
504+
await dispatch(createResource(challengeId, roleId, newMember))
505+
}
506+
}

src/components/ChallengeEditor/index.js

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { Helmet } from 'react-helmet'
66
import cn from 'classnames'
77
import moment from 'moment'
88
import { pick } from 'lodash/fp'
9-
// import Modal from '../Modal'
109
import { withRouter } from 'react-router-dom'
1110
import { toastr } from 'react-redux-toastr'
1211
import xss from 'xss'
@@ -39,10 +38,6 @@ import dropdowns from './mock-data/dropdowns'
3938
import LastSavedDisplay from './LastSaved-Display'
4039
import styles from './ChallengeEditor.module.scss'
4140
import Track from '../Track'
42-
import {
43-
createResource,
44-
deleteResource
45-
} from '../../services/challenges'
4641
import ConfirmationModal from '../Modal/ConfirmationModal'
4742
import AlertModal from '../Modal/AlertModal'
4843
import PhaseInput from '../PhaseInput'
@@ -306,22 +301,15 @@ class ChallengeEditor extends Component {
306301
*/
307302
onUpdateAssignedMember (option) {
308303
const { challenge: oldChallenge } = this.state
309-
const newChallenge = { ...oldChallenge }
304+
const newChallenge = { ...oldChallenge, task: { isAssigned: false, memberId: null, isTask: true } }
310305
let assignedMemberDetails
311306

312307
if (option && option.value) {
313-
/* newChallenge.task = {
314-
...oldChallenge.task,
315-
memberId: option.value
316-
// TODO uncomment as soon as issue in API is fixed https://github.com/topcoder-platform/challenge-api/issues/272
317-
// isAssigned: true
318-
} */
319308
assignedMemberDetails = {
320309
handle: option.label,
321310
userId: parseInt(option.value, 10)
322311
}
323312
} else {
324-
// newChallenge.task = _.omit(oldChallenge.task, ['memberId', 'isAssigned'])
325313
assignedMemberDetails = null
326314
}
327315

@@ -864,14 +852,11 @@ class ChallengeEditor extends Component {
864852
const { challenge: { copilot, reviewer }, assignedMemberDetails: assignedMember } = this.state
865853
if (copilot) await this.updateResource(challengeId, 'Copilot', copilot, previousCopilot)
866854
if (reviewer) await this.updateResource(challengeId, 'Reviewer', reviewer, previousReviewer)
867-
console.log(oldAssignedMember, 'oldAssignedMember')
868-
console.log(assignedMember, 'assignedMember')
869855
const oldMemberHandle = _.get(oldAssignedMember, 'handle')
870856
// assigned member has been updated
871857
if (assignedMember && assignedMember.handle !== oldMemberHandle) {
872858
await this.updateResource(challengeId, 'Submitter', assignedMember.handle, oldMemberHandle)
873859
}
874-
this.updateTimeLastSaved()
875860

876861
const draftChallenge = { data: action.challengeDetails }
877862
draftChallenge.data.copilot = copilot
@@ -910,29 +895,8 @@ class ChallengeEditor extends Component {
910895

911896
async updateResource (challengeId, name, value, prevValue) {
912897
const resourceRole = this.getResourceRoleByName(name)
913-
if (value === prevValue) {
914-
return
915-
}
916-
const newResource = {
917-
challengeId,
918-
memberHandle: value,
919-
roleId: resourceRole ? resourceRole.id : null
920-
}
921-
if (prevValue) {
922-
try {
923-
const oldResource = _.pick(newResource, ['challengeId', 'roleId'])
924-
oldResource.memberHandle = prevValue
925-
await deleteResource(oldResource)
926-
} catch (err) {
927-
const errorMessage = _.get(err, 'response.data.message')
928-
// ignore error where the resource does not exist already
929-
if (errorMessage.indexOf('doesn\'t have resource with roleId') === -1) {
930-
throw err
931-
}
932-
}
933-
}
934-
console.log('creating new resource')
935-
await createResource(newResource)
898+
const roleId = resourceRole.id
899+
await this.props.replaceResourceInRole(challengeId, roleId, value, prevValue)
936900
}
937901

938902
updateAttachmentlist (challenge, attachments) {
@@ -1141,7 +1105,6 @@ class ChallengeEditor extends Component {
11411105
)
11421106
}
11431107
}
1144-
11451108
if (!isNew && challenge.status !== 'New' && isLaunch && isConfirm) {
11461109
draftModal = (
11471110
<AlertModal
@@ -1384,6 +1347,7 @@ ChallengeEditor.propTypes = {
13841347
assignedMemberDetails: PropTypes.shape(),
13851348
updateChallengeDetails: PropTypes.func.isRequired,
13861349
createChallenge: PropTypes.func,
1350+
replaceResourceInRole: PropTypes.func,
13871351
partiallyUpdateChallengeDetails: PropTypes.func.isRequired
13881352
}
13891353

src/config/constants.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ export const LOAD_CHALLENGE_RESOURCES_SUCCESS = 'LOAD_CHALLENGE_RESOURCES_SUCCES
6767
export const LOAD_CHALLENGE_RESOURCES_PENDING = 'LOAD_CHALLENGE_RESOURCES_PENDING'
6868
export const LOAD_CHALLENGE_RESOURCES_FAILURE = 'LOAD_CHALLENGE_RESOURCES_FAILURE'
6969

70+
export const CREATE_CHALLENGE_RESOURCE = 'CREATE_CHALLENGE_RESOURCE'
71+
export const CREATE_CHALLENGE_RESOURCE_SUCCESS = 'CREATE_CHALLENGE_RESOURCE_SUCCESS'
72+
export const CREATE_CHALLENGE_RESOURCE_PENDING = 'CREATE_CHALLENGE_RESOURCE_PENDING'
73+
export const CREATE_CHALLENGE_RESOURCE_FAILURE = 'CREATE_CHALLENGE_RESOURCE_FAILURE'
74+
75+
export const DELETE_CHALLENGE_RESOURCE = 'DELETE_CHALLENGE_RESOURCE'
76+
export const DELETE_CHALLENGE_RESOURCE_SUCCESS = 'DELETE_CHALLENGE_RESOURCE_SUCCESS'
77+
export const DELETE_CHALLENGE_RESOURCE_PENDING = 'DELETE_CHALLENGE_RESOURCE_PENDING'
78+
export const DELETE_CHALLENGE_RESOURCE_FAILURE = 'DELETE_CHALLENGE_RESOURCE_FAILURE'
79+
7080
export const REMOVE_ATTACHMENT = 'REMOVE_ATTACHMENT'
7181

7282
export const SET_FILTER_CHALLENGE_VALUE = 'SET_FILTER_CHALLENGE_VALUE'

src/config/store.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44
import { createStore, applyMiddleware } from 'redux'
55
import thunkMiddleware from 'redux-thunk'
66
import { createLogger } from 'redux-logger'
7+
import promiseMiddleware from 'redux-promise-middleware'
78
import reducer from '../reducers'
89

9-
const middlewares = [thunkMiddleware]
10+
const middlewares = [
11+
promiseMiddleware({
12+
promiseTypeSuffixes: ['PENDING', 'SUCCESS', 'FAILURE']
13+
}),
14+
thunkMiddleware
15+
]
1016

1117
if (process.env.NODE_ENV === 'development') {
1218
middlewares.push(createLogger())

src/containers/ChallengeEditor/index.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
loadResourceRoles,
2323
updateChallengeDetails,
2424
partiallyUpdateChallengeDetails,
25-
createChallenge
25+
createChallenge,
26+
replaceResourceInRole
2627
} from '../../actions/challenges'
2728
import {
2829
loadMemberDetails
@@ -126,7 +127,8 @@ class ChallengeEditor extends Component {
126127
projectDetail,
127128
updateChallengeDetails,
128129
partiallyUpdateChallengeDetails,
129-
createChallenge
130+
createChallenge,
131+
replaceResourceInRole
130132
// members
131133
} = this.props
132134
const challengeId = _.get(match.params, 'challengeId', null)
@@ -163,6 +165,7 @@ class ChallengeEditor extends Component {
163165
assignedMemberDetails={assignedMemberDetails}
164166
updateChallengeDetails={updateChallengeDetails}
165167
createChallenge={createChallenge}
168+
replaceResourceInRole={replaceResourceInRole}
166169
partiallyUpdateChallengeDetails={partiallyUpdateChallengeDetails}
167170
/>
168171
))
@@ -187,6 +190,7 @@ class ChallengeEditor extends Component {
187190
projectDetail={projectDetail}
188191
assignedMemberDetails={assignedMemberDetails}
189192
updateChallengeDetails={updateChallengeDetails}
193+
replaceResourceInRole={replaceResourceInRole}
190194
partiallyUpdateChallengeDetails={partiallyUpdateChallengeDetails}
191195
/>
192196
))
@@ -246,7 +250,8 @@ ChallengeEditor.propTypes = {
246250
loadMemberDetails: PropTypes.func,
247251
updateChallengeDetails: PropTypes.func.isRequired,
248252
partiallyUpdateChallengeDetails: PropTypes.func.isRequired,
249-
createChallenge: PropTypes.func.isRequired
253+
createChallenge: PropTypes.func.isRequired,
254+
replaceResourceInRole: PropTypes.func
250255
// members: PropTypes.arrayOf(PropTypes.shape())
251256
}
252257

@@ -279,7 +284,8 @@ const mapDispatchToProps = {
279284
loadMemberDetails,
280285
updateChallengeDetails,
281286
partiallyUpdateChallengeDetails,
282-
createChallenge
287+
createChallenge,
288+
replaceResourceInRole
283289
}
284290

285291
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ChallengeEditor))

src/reducers/challenges.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ import {
2323
UPDATE_CHALLENGE_DETAILS_FAILURE,
2424
UPDATE_CHALLENGE_DETAILS_SUCCESS,
2525
CREATE_CHALLENGE_SUCCESS,
26-
CREATE_CHALLENGE_FAILURE
26+
CREATE_CHALLENGE_FAILURE,
27+
CREATE_CHALLENGE_RESOURCE_SUCCESS,
28+
DELETE_CHALLENGE_RESOURCE_SUCCESS,
29+
DELETE_CHALLENGE_RESOURCE_FAILURE,
30+
CREATE_CHALLENGE_RESOURCE_FAILURE
2731
} from '../config/constants'
2832

2933
const initialState = {
@@ -164,6 +168,43 @@ export default function (state = initialState, action) {
164168
isLoading: false,
165169
failedToLoad: false
166170
}
171+
case CREATE_CHALLENGE_RESOURCE_SUCCESS: {
172+
const resource = action.payload
173+
const challengeResources = _.clone(state.challengeResources)
174+
challengeResources.push(resource)
175+
return {
176+
...state,
177+
challengeResources,
178+
isLoading: false,
179+
failedToLoad: false
180+
}
181+
}
182+
case CREATE_CHALLENGE_RESOURCE_FAILURE: {
183+
const resource = action.payload
184+
console.log(resource)
185+
return { ...state, isLoading: false, failedToCreate: true }
186+
}
187+
case DELETE_CHALLENGE_RESOURCE_SUCCESS: {
188+
const resource = action.payload
189+
const challengeResources = _.clone(state.challengeResources)
190+
_.remove(challengeResources,
191+
r => r.challengeId === resource.challengeId && r.roleId === resource.roleId && r.memberHandle === resource.memberHandle)
192+
return {
193+
...state,
194+
challengeResources,
195+
isLoading: false,
196+
failedToLoad: false
197+
}
198+
}
199+
case DELETE_CHALLENGE_RESOURCE_FAILURE: {
200+
const err = action.payload
201+
const errorMessage = _.get(err, 'response.data.message')
202+
// ignore error where the resource does not exist already
203+
if (errorMessage.indexOf('doesn\'t have resource with roleId') === -1) {
204+
return { ...state, isLoading: false, failedToDelete: true }
205+
}
206+
return { ...state, isLoading: false, failedToDelete: false }
207+
}
167208
case LOAD_CHALLENGE_METADATA_SUCCESS:
168209
return {
169210
...state,

src/services/challenges.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,9 @@ export async function fetchChallengeTerms () {
172172
* @param challenge challenge data
173173
* @returns {Promise<*>}
174174
*/
175-
export function createResource (resource) {
176-
return axiosInstance.post(RESOURCES_API_URL, resource)
175+
export async function createResource (resource) {
176+
const resp = await axiosInstance.post(RESOURCES_API_URL, resource)
177+
return _.get(resp, 'data', {})
177178
}
178179

179180
/**
@@ -200,6 +201,7 @@ export async function fetchResourceRoles () {
200201
* @param {object} resource to delete
201202
* @returns {Promise<*>}
202203
*/
203-
export function deleteResource (resource) {
204-
return axiosInstance.delete(RESOURCES_API_URL, { data: resource })
204+
export async function deleteResource (resource) {
205+
const resp = await axiosInstance.delete(RESOURCES_API_URL, { data: resource })
206+
return _.get(resp, 'data', {})
205207
}

0 commit comments

Comments
 (0)