Skip to content

Commit 6c948ff

Browse files
authored
Merge pull request #3403 from sumitdaga/F2F_30109948
feat: show loading indicator during member role switching ref issue #3391
2 parents fe1c2b9 + ff0f4de commit 6c948ff

File tree

7 files changed

+74
-36
lines changed

7 files changed

+74
-36
lines changed

src/components/TeamManagement/TeamManagement.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class TeamManagement extends React.Component {
5959
projectTeamInvites, onProjectInviteDeleteConfirm, onProjectInviteSend, deletingInvite, changeRole,
6060
onDeleteInvite, isShowTopcoderDialog, onShowTopcoderDialog, processingInvites, processingMembers,
6161
onTopcoderInviteSend, onTopcoderInviteDeleteConfirm, topcoderTeamInvites, onAcceptOrRefuse, error,
62-
onSelectedMembersUpdate, selectedMembers, allMembers,
62+
onSelectedMembersUpdate, selectedMembers, allMembers, updatingMemberIds
6363
} = this.props
6464
const currentMember = members.filter((member) => member.userId === currentUser.userId)[0]
6565
const modalActive = isAddingTeamMember || deletingMember || isShowJoin || showNewMemberConfirmation || deletingInvite
@@ -222,6 +222,7 @@ class TeamManagement extends React.Component {
222222
return (
223223
<TopcoderDialog
224224
processingInvites={processingInvites}
225+
updatingMemberIds={updatingMemberIds}
225226
error={error}
226227
currentUser={currentUser}
227228
members={members}
@@ -438,6 +439,11 @@ TeamManagement.propTypes = {
438439
*/
439440
processingMembers: PropTypes.bool.isRequired,
440441

442+
/**
443+
* List of member ids being updated
444+
*/
445+
updatingMemberIds: PropTypes.arrayOf(PropTypes.number).isRequired,
446+
441447
/**
442448
* Flag indicates if invite API is running
443449
*/

src/components/TeamManagement/TeamManagement.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,14 @@
260260
background: white;
261261
min-width: 300px;
262262

263+
&.is-processing {
264+
justify-content: center;
265+
align-items: center;
266+
height: 36px;
267+
border: 0;
268+
background: transparent;
269+
}
270+
263271
.Tooltip {
264272
align-items: center;
265273
display: flex;

src/components/TeamManagement/TopcoderManagementDialog.js

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class TopcoderManagementDialog extends React.Component {
154154
render() {
155155
const {
156156
members, currentUser, isMember, removeMember, onCancel, removeInvite, approveOrDecline, topcoderTeamInvites = [],
157-
selectedMembers, processingInvites,
157+
selectedMembers, processingInvites, updatingMemberIds
158158
} = this.props
159159
const { processingInviteRequestId } = this.state
160160
const showRemove = currentUser.isAdmin || (isMember && checkPermission(PERMISSIONS.INVITE_TOPCODER_MEMBER))
@@ -187,6 +187,7 @@ class TopcoderManagementDialog extends React.Component {
187187
}
188188
const userFullName = getFullNameWithFallback(member)
189189
const role = _.get(_.find(this.roles, r => r.value === member.role), 'title')
190+
const isMemberProcessing = _.includes(updatingMemberIds, member.id)
190191
return (
191192
<div
192193
key={i}
@@ -229,36 +230,39 @@ class TopcoderManagementDialog extends React.Component {
229230
this.onUserRoleChange(member.userId, member.id, type)
230231
}
231232
return (
232-
<div className="member-role-container">
233-
{types.map((type) => {
234-
const isCopilotDisabled =
235-
type === 'Copilot' &&
236-
type !== currentType &&
237-
!(currentUser.isCopilotManager || currentUser.isAdmin)
238-
239-
return (
240-
isCopilotDisabled ? (
241-
<Tooltip theme="light" key={type}>
242-
<div className="tooltip-target">
243-
<div className="member-role disabled">
233+
<div className={`member-role-container ${isMemberProcessing ? 'is-processing' : ''}`}>
234+
{
235+
isMemberProcessing ? <LoadingIndicator isSmall /> :
236+
types.map((type) => {
237+
const isCopilotDisabled =
238+
type === 'Copilot' &&
239+
type !== currentType &&
240+
!(currentUser.isCopilotManager || currentUser.isAdmin)
241+
242+
return (
243+
isCopilotDisabled ? (
244+
<Tooltip theme="light" key={type}>
245+
<div className="tooltip-target">
246+
<div className="member-role disabled">
247+
{type}
248+
</div>
249+
</div>
250+
<div className="tooltip-body">
251+
{'Only Connect Copilot Managers can change member role to copilots.'}
252+
</div>
253+
</Tooltip>
254+
) : (
255+
<div
256+
key={type}
257+
onClick={() => onClick(type)}
258+
className={cn('member-role', { active: type === currentType })}
259+
>
244260
{type}
245261
</div>
246-
</div>
247-
<div className="tooltip-body">
248-
{'Only Connect Copilot Managers can change member role to copilots.'}
249-
</div>
250-
</Tooltip>
251-
) : (
252-
<div
253-
key={type}
254-
onClick={() => onClick(type)}
255-
className={cn('member-role', { active: type === currentType })}
256-
>
257-
{type}
258-
</div>
259-
)
260-
)
261-
})}
262+
)
263+
)
264+
})
265+
}
262266
</div>
263267
)
264268
})()}

src/projects/actions/projectMember.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ export function updateProjectMember(projectId, memberId, member) {
7474
return (dispatch) => {
7575
return dispatch({
7676
type: UPDATE_PROJECT_MEMBER,
77-
payload: updateMember(projectId, memberId, member)
77+
payload: updateMember(projectId, memberId, member),
78+
meta: { memberId }
7879
})
7980
}
8081
}

src/projects/detail/containers/TeamManagementContainer.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ class TeamManagementContainer extends Component {
203203
history={this.props.history}
204204
onUserInviteAction={this.onUserInviteAction}
205205
processingMembers={this.props.processingMembers}
206+
updatingMemberIds={this.props.updatingMemberIds}
206207
processingInvites={this.props.processingInvites}
207208
error={this.props.error}
208209
currentUser={this.props.currentUser}
@@ -246,6 +247,7 @@ const mapStateToProps = ({loadUser, members, projectState}) => {
246247
allMembers: _.values(members.members),
247248
processingInvites: projectState.processingInvites,
248249
processingMembers: projectState.processingMembers,
250+
updatingMemberIds: projectState.updatingMemberIds,
249251
error: projectState.error,
250252
topcoderTeamInvites: _.filter(projectState.project.invites, i => i.role !== 'customer'),
251253
projectTeamInvites: _.filter(projectState.project.invites, i => i.role === 'customer')
@@ -277,6 +279,7 @@ TeamManagementContainer.propTypes = {
277279
allMembers: PropTypes.arrayOf(PropTypes.object).isRequired,
278280
projectId: PropTypes.number.isRequired,
279281
processingMembers: PropTypes.bool.isRequired,
282+
updatingMemberIds: PropTypes.arrayOf(PropTypes.number).isRequired,
280283
processingInvites: PropTypes.bool.isRequired,
281284
error: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
282285
projectTeamInvites: PropTypes.arrayOf(PropTypes.object),

src/projects/reducers/project.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const initialState = {
3232
isLoading: true,
3333
processing: false,
3434
processingMembers: false,
35+
updatingMemberIds: [],
3536
processingInvites: false,
3637
processingAttachments: false,
3738
attachmentsAwaitingPermission: null,
@@ -624,11 +625,15 @@ export const projectState = function (state=initialState, action) {
624625

625626
case ADD_PROJECT_MEMBER_PENDING:
626627
case REMOVE_PROJECT_MEMBER_PENDING:
627-
case UPDATE_PROJECT_MEMBER_PENDING:
628628
return Object.assign({}, state, {
629629
processingMembers: true
630630
})
631631

632+
case UPDATE_PROJECT_MEMBER_PENDING:
633+
return Object.assign({}, state, {
634+
updatingMemberIds: [ ...state.updatingMemberIds, action.meta.memberId ]
635+
})
636+
632637
case ADD_PROJECT_MEMBER_SUCCESS:
633638
return update (state, {
634639
processingMembers: { $set : false },
@@ -694,9 +699,9 @@ export const projectState = function (state=initialState, action) {
694699
})
695700
updatedMembers.splice(idx, 1, action.payload)
696701
return update(state, {
697-
processingMembers: { $set : false },
698702
project: { members: { $set: updatedMembers } },
699-
projectNonDirty: { members: { $set: updatedMembers } }
703+
projectNonDirty: { members: { $set: updatedMembers } },
704+
updatingMemberIds: { $set: _.xor(state.updatingMemberIds, [action.payload.id]) }
700705
})
701706
}
702707

@@ -821,7 +826,6 @@ export const projectState = function (state=initialState, action) {
821826
case REMOVE_TOPCODER_MEMBER_INVITE_FAILURE:
822827
case REMOVE_CUSTOMER_INVITE_FAILURE:
823828
case REMOVE_PROJECT_MEMBER_FAILURE:
824-
case UPDATE_PROJECT_MEMBER_FAILURE:
825829
case UPDATE_PROJECT_ATTACHMENT_FAILURE:
826830
case ADD_PROJECT_ATTACHMENT_FAILURE:
827831
case REMOVE_PROJECT_ATTACHMENT_FAILURE:
@@ -848,6 +852,11 @@ export const projectState = function (state=initialState, action) {
848852
error: parseErrorObj(action),
849853
inviteError: parseErrorObj(action)
850854
})
855+
case UPDATE_PROJECT_MEMBER_FAILURE:
856+
return Object.assign({}, state, {
857+
updatingMemberIds: _.remove(state.updatingMemberIds, [action.payload.id]),
858+
error: parseErrorObj(action)
859+
})
851860

852861
default:
853862
return state

src/reducers/alerts.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,14 @@ export default function(state = {}, action) {
217217
Alert.error('You are unable to invite members successfully.')
218218
return state
219219

220+
case UPDATE_PROJECT_MEMBER_SUCCESS:
221+
Alert.success('Member updated successfully.')
222+
return state
223+
224+
case UPDATE_PROJECT_MEMBER_FAILURE:
225+
Alert.error('Error updating member.')
226+
return state
227+
220228
case ACCEPT_OR_REFUSE_INVITE_SUCCESS:
221229
if (action.payload.status===PROJECT_MEMBER_INVITE_STATUS_ACCEPTED){
222230
Alert.success('You\'ve successfully joined the project.')
@@ -243,7 +251,6 @@ export default function(state = {}, action) {
243251
case UPDATE_PROJECT_ATTACHMENT_FAILURE:
244252
case REMOVE_PROJECT_ATTACHMENT_FAILURE:
245253
case ADD_PROJECT_MEMBER_FAILURE:
246-
case UPDATE_PROJECT_MEMBER_FAILURE:
247254
case REMOVE_PROJECT_MEMBER_FAILURE:
248255
case CREATE_PROJECT_FEED_COMMENT_FAILURE:
249256
case SAVE_PROJECT_FEED_COMMENT_FAILURE:

0 commit comments

Comments
 (0)