Skip to content

Commit fb36ae7

Browse files
authored
Merge pull request #2844 from appirio-tech/feature/copilotWorkflow
Copilot workflow changes
2 parents da52543 + 2cd725d commit fb36ae7

File tree

9 files changed

+120
-36
lines changed

9 files changed

+120
-36
lines changed

src/components/TeamManagement/TeamManagement.jsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class TeamManagement extends React.Component {
5656
showNewMemberConfirmation, onJoin, onJoinConfirm, onShowProjectDialog, isShowProjectDialog,
5757
projectTeamInvites, onProjectInviteDeleteConfirm, onProjectInviteSend, deletingInvite, changeRole,
5858
onDeleteInvite, isShowTopcoderDialog, onShowTopcoderDialog, processingInvites, processingMembers,
59-
onTopcoderInviteSend, onTopcoderInviteDeleteConfirm, topcoderTeamInvites, error,
59+
onTopcoderInviteSend, onTopcoderInviteDeleteConfirm, topcoderTeamInvites, onAcceptOrRefuse, error,
6060
onSelectedMembersUpdate, selectedMembers
6161
} = this.props
6262
const currentMember = members.filter((member) => member.userId === currentUser.userId)[0]
@@ -188,6 +188,7 @@ class TeamManagement extends React.Component {
188188
}
189189
return (
190190
<ProjectDialog
191+
processingInvites={processingInvites}
191192
error={error}
192193
currentUser={currentUser}
193194
members={members}
@@ -203,8 +204,11 @@ class TeamManagement extends React.Component {
203204
/>
204205
)
205206
})())}
206-
{(!modalActive && isShowTopcoderDialog) && ((() => {
207-
const onClickCancel = () => onShowTopcoderDialog(false)
207+
{(!modalActive && (isShowTopcoderDialog || this.props.history.location.hash === '#manageTopcoderTeam')) && ((() => {
208+
const onClickCancel = () => {
209+
this.props.history.push(this.props.history.location.pathname)
210+
onShowTopcoderDialog(false)
211+
}
208212
const removeMember = (member) => {
209213
onMemberDelete(member)
210214
}
@@ -213,13 +217,15 @@ class TeamManagement extends React.Component {
213217
}
214218
return (
215219
<TopcoderDialog
220+
processingInvites={processingInvites}
216221
error={error}
217222
currentUser={currentUser}
218223
members={members}
219224
isMember={!!currentMember}
220225
onCancel={onClickCancel}
221226
removeMember={removeMember}
222227
addUsers={onTopcoderInviteSend}
228+
approveOrDecline={onAcceptOrRefuse}
223229
invites={topcoderTeamInvites}
224230
removeInvite={removeInvite}
225231
changeRole={changeRole}
@@ -389,6 +395,11 @@ TeamManagement.propTypes = {
389395
*/
390396
selectedMembers: PropTypes.arrayOf(PropTypes.object),
391397

398+
/**
399+
* Callback to accept or refuse invite
400+
*/
401+
onAcceptOrRefuse: PropTypes.func,
402+
392403
/**
393404
* Callback to send member role
394405
*/

src/components/TeamManagement/TeamManagement.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,13 @@
212212
font-size: $tc-label-sm;
213213
cursor: pointer;
214214

215+
span {
216+
margin-left: $base-unit*3;
217+
}
218+
215219
.email-date {
216220
cursor: default;
217221
color: $tc-gray-40;
218-
margin-left: $base-unit*3;
219222

220223
@media screen and (max-width: $screen-md - 1px) {
221224
display: none;

src/components/TeamManagement/TopcoderManagementDialog.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ class Dialog extends React.Component {
9393

9494
render() {
9595
const {
96-
members, currentUser, isMember, removeMember, onCancel, removeInvite, invites = [],
96+
members, currentUser, isMember, removeMember, onCancel, removeInvite, approveOrDecline, invites = [],
9797
selectedMembers, processingInvites
9898
} = this.props
9999
const showRemove = currentUser.isAdmin || (isMember && currentUser.isManager)
100+
const showApproveDecline = currentUser.isCopilotManager
100101
let i = 0
101102
const allMembers = [...members, ...invites.map(i => i.member)]
102103
return (
@@ -210,6 +211,18 @@ class Dialog extends React.Component {
210211
const remove = () => {
211212
removeInvite(invite)
212213
}
214+
const approve = () => {
215+
approveOrDecline({
216+
userId: invite.userId,
217+
status: 'accepted'
218+
})
219+
}
220+
const decline = () => {
221+
approveOrDecline({
222+
userId: invite.userId,
223+
status: 'refused'
224+
})
225+
}
213226
const firstName = _.get(invite.member, 'firstName', '')
214227
const lastName = _.get(invite.member, 'lastName', '')
215228
let userFullName = `${firstName} ${lastName}`
@@ -231,7 +244,14 @@ class Dialog extends React.Component {
231244
@{invite.member.handle || 'ConnectUser'}
232245
</span>
233246
</div>
234-
{showRemove && <div className="member-remove" onClick={remove}>
247+
{showApproveDecline && <div className="member-remove">
248+
<span onClick={approve}>approve</span>
249+
<span onClick={decline}>decline</span>
250+
<span className="email-date">
251+
requested {moment(invite.createdAt).format('MMM D, YY')}
252+
</span>
253+
</div>}
254+
{!showApproveDecline && showRemove && <div className="member-remove" onClick={remove}>
235255
Remove
236256
<span className="email-date">
237257
Invited {moment(invite.createdAt).format('MMM D, YY')}
@@ -252,7 +272,7 @@ class Dialog extends React.Component {
252272
allMembers={allMembers}
253273
/>
254274
{ this.state.showAlreadyMemberError && <div className="error-message">
255-
Project Member(s) can't be invited again. Please remove them from list.
275+
'Project Member(s) can\'t be invited again. Please remove them from list.'
256276
</div> }
257277
<Formsy.Form>
258278
<SelectDropdown
@@ -295,6 +315,7 @@ Dialog.propTypes = {
295315
changeRole: PT.func.isRequired,
296316
invites: PT.arrayOf(PT.object),
297317
addUsers: PT.func.isRequired,
318+
approveOrDecline: PT.func.isRequired,
298319
removeInvite: PT.func.isRequired,
299320
onSelectedMembersUpdate: PT.func.isRequired,
300321
selectedMembers: PT.arrayOf(PT.object),

src/config/constants.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,8 +783,8 @@ export const EVENT_TYPE = {
783783
COPILOT_JOINED: 'notifications.connect.project.member.copilotJoined',
784784
ASSIGNED_AS_OWNER: 'notifications.connect.project.member.assignedAsOwner',
785785
INVITE_REQUESTED: 'notifications.connect.project.member.invite.requested',
786-
INVITE_APPROVED: 'notifications.connect.project.member.copilot.added',
787-
INVITE_REFUSED: 'notifications.connect.project.member.copilot.refused',
786+
INVITE_APPROVED: 'notifications.connect.project.member.invite.approved',
787+
INVITE_REFUSED: 'notifications.connect.project.member.invite.refused',
788788
},
789789
PROJECT: {
790790
ACTIVE: 'notifications.connect.project.active',

src/projects/detail/containers/TeamManagementContainer.jsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class TeamManagementContainer extends Component {
3838
this.onTopcoderInviteSend = this.onTopcoderInviteSend.bind(this)
3939
this.onMemberDeleteConfirm = this.onMemberDeleteConfirm.bind(this)
4040
this.onJoinConfirm = this.onJoinConfirm.bind(this)
41+
this.onAcceptOrRefuse = this.onAcceptOrRefuse.bind(this)
4142
this.changeRole = this.changeRole.bind(this)
4243
this.onSelectedMembersUpdate = this.onSelectedMembersUpdate.bind(this)
4344
this.onShowDialog = this.onShowDialog.bind(this)
@@ -100,6 +101,10 @@ class TeamManagementContainer extends Component {
100101
this.props.inviteProjectMembers(this.props.projectId, emails, handles)
101102
}
102103

104+
onAcceptOrRefuse(invite) {
105+
this.props.acceptOrRefuseInvite(this.props.projectId, invite)
106+
}
107+
103108
changeRole(memberId, item) {
104109
this.props.updateProjectMember(this.props.projectId, memberId, item)
105110
}
@@ -178,6 +183,7 @@ class TeamManagementContainer extends Component {
178183
<div>
179184
<TeamManagement
180185
{...this.state}
186+
history={this.props.history}
181187
onUserInviteAction={this.onUserInviteAction}
182188
processingMembers={this.props.processingMembers}
183189
processingInvites={this.props.processingInvites}
@@ -189,6 +195,7 @@ class TeamManagementContainer extends Component {
189195
onMemberDeleteConfirm={this.onMemberDeleteConfirm}
190196
onJoinConfirm={this.onJoinConfirm}
191197
onProjectInviteDeleteConfirm={this.onProjectInviteDelete}
198+
onAcceptOrRefuse={this.onAcceptOrRefuse}
192199
onProjectInviteSend={this.onProjectInviteSend}
193200
onTopcoderInviteDeleteConfirm={this.onTopcoderInviteDelete}
194201
onTopcoderInviteSend={this.onTopcoderInviteSend}

src/projects/reducers/project.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
INVITE_TOPCODER_MEMBER_SUCCESS, REMOVE_TOPCODER_MEMBER_INVITE_SUCCESS, INVITE_TOPCODER_MEMBER_PENDING, REMOVE_CUSTOMER_INVITE_PENDING,
2020
REMOVE_TOPCODER_MEMBER_INVITE_PENDING, REMOVE_TOPCODER_MEMBER_INVITE_FAILURE, REMOVE_CUSTOMER_INVITE_FAILURE,
2121
INVITE_CUSTOMER_FAILURE, INVITE_TOPCODER_MEMBER_FAILURE, INVITE_CUSTOMER_PENDING,
22-
ACCEPT_OR_REFUSE_INVITE_SUCCESS, ACCEPT_OR_REFUSE_INVITE_FAILURE, ACCEPT_OR_REFUSE_INVITE_PENDING,
22+
ACCEPT_OR_REFUSE_INVITE_SUCCESS, ACCEPT_OR_REFUSE_INVITE_FAILURE, ACCEPT_OR_REFUSE_INVITE_PENDING,
2323
UPLOAD_PROJECT_ATTACHMENT_FILES, DISCARD_PROJECT_ATTACHMENT, CHANGE_ATTACHMENT_PERMISSION
2424
} from '../../config/constants'
2525
import _ from 'lodash'
@@ -165,7 +165,7 @@ export const projectState = function (state=initialState, action) {
165165

166166
case LOAD_PROJECT_MEMBER_INVITES_SUCCESS: {
167167
return Object.assign({}, state, {
168-
showUserInvited: true
168+
showUserInvited: true && action.payload.role !== 'copilot'
169169
})
170170
}
171171

@@ -177,7 +177,7 @@ export const projectState = function (state=initialState, action) {
177177

178178
case ACCEPT_OR_REFUSE_INVITE_PENDING:
179179
return Object.assign({}, state, {
180-
showUserInvited: true
180+
showUserInvited: false
181181
})
182182

183183
case ACCEPT_OR_REFUSE_INVITE_SUCCESS: {
@@ -388,7 +388,7 @@ export const projectState = function (state=initialState, action) {
388388
attachmentsAwaitingPermission: action.payload,
389389
attachmentPermissions: null
390390
}
391-
391+
392392
case DISCARD_PROJECT_ATTACHMENT:
393393
return {
394394
...state,

src/routes/notifications/constants/notifications.js

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77
import {
88
NOTIFICATION_TYPE,
9-
ROLE_CONNECT_COPILOT, ROLE_CONNECT_MANAGER, ROLE_CONNECT_ACCOUNT_MANAGER, ROLE_ADMINISTRATOR,
9+
ROLE_CONNECT_COPILOT, ROLE_CONNECT_MANAGER, ROLE_CONNECT_ACCOUNT_MANAGER, ROLE_CONNECT_COPILOT_MANAGER, ROLE_ADMINISTRATOR,
1010
PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER, PROJECT_ROLE_OWNER, PROJECT_ROLE_MEMBER,
1111
EVENT_TYPE,
1212
} from '../../../config/constants'
@@ -18,7 +18,8 @@ export const GOTO = {
1818
TOPIC: '/projects/{{projectId}}/#feed-{{topicId}}',
1919
POST: '/projects/{{projectId}}/#comment-{{postId}}',
2020
FILE_LIST: '/projects/{{projectId}}/specification#appDefinition-files',
21-
PHASE: '/projects/{{projectId}}/plan#phase-{{phaseId}}'
21+
PHASE: '/projects/{{projectId}}/plan#phase-{{phaseId}}',
22+
TOPCODER_TEAM: '/projects/{{projectId}}#manageTopcoderTeam'
2223
}
2324

2425
// each notification can be displayed differently depend on WHO see them
@@ -217,11 +218,45 @@ export const NOTIFICATIONS = [
217218
}]
218219
},
219220

221+
{
222+
eventType: EVENT_TYPE.MEMBER.INVITE_REQUESTED,
223+
type: NOTIFICATION_TYPE.MEMBER_ADDED,
224+
rules: [{
225+
text: 'You are requested to add <strong>{{userFullName}}</strong> as a copilot',
226+
topcoderRoles: [ROLE_CONNECT_COPILOT_MANAGER],
227+
goTo: GOTO.TOPCODER_TEAM
228+
}]
229+
},
230+
231+
{
232+
eventType: EVENT_TYPE.MEMBER.INVITE_APPROVED,
233+
type: NOTIFICATION_TYPE.MEMBER_ADDED,
234+
rules: [{
235+
text: 'You are added as a copilot',
236+
toUserHandle: true,
237+
goTo: GOTO.PROJECT_DASHBOARD
238+
}, {
239+
text: 'Your request to add invite the copilot was approved',
240+
creator: true,
241+
goTo: GOTO.PROJECT_DASHBOARD
242+
}]
243+
},
244+
245+
{
246+
eventType: EVENT_TYPE.MEMBER.INVITE_REFUSED,
247+
type: NOTIFICATION_TYPE.MEMBER_ADDED,
248+
rules: [{
249+
text: 'Your request to add invite the member was refused',
250+
creator: true,
251+
goTo: GOTO.PROJECT_DASHBOARD
252+
}]
253+
},
254+
220255
{
221256
eventType: EVENT_TYPE.MEMBER.COPILOT_JOINED,
222257
type: NOTIFICATION_TYPE.MEMBER_ADDED,
223258
rules: [{
224-
text: 'A copilot joined your project team',
259+
text: 'A copilot joined your project team',
225260
shouldBundle: true,
226261
bundledText: '{{bundledCount}} copilots joined your project team',
227262
projectRoles: [PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER],
@@ -293,8 +328,8 @@ export const NOTIFICATIONS = [
293328
projectRoles: [PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER, PROJECT_ROLE_MEMBER],
294329
goTo: GOTO.POST
295330
}]
296-
},
297-
331+
},
332+
298333
{
299334
version: 2,
300335
eventType: EVENT_TYPE.POST.UPDATED,
@@ -307,8 +342,8 @@ export const NOTIFICATIONS = [
307342
toTopicStarter: true,
308343
goTo: GOTO.POST
309344
}]
310-
},
311-
345+
},
346+
312347
{
313348
version: 2,
314349
eventType: EVENT_TYPE.POST.MENTION,
@@ -384,7 +419,7 @@ export const NOTIFICATIONS = [
384419
goTo: GOTO.PROJECT_SPECIFICATION
385420
}]
386421
},
387-
422+
388423
{
389424
eventType: EVENT_TYPE.PROJECT_PLAN.READY,
390425
type: NOTIFICATION_TYPE.UPDATES,
@@ -474,7 +509,7 @@ export const NOTIFICATIONS = [
474509
goTo: GOTO.PHASE
475510
}]
476511
},
477-
512+
478513
{
479514
eventType: EVENT_TYPE.PROJECT_PLAN.PHASE_PROGRESS_UPDATED,
480515
type: NOTIFICATION_TYPE.UPDATES,
@@ -529,7 +564,7 @@ export const NOTIFICATIONS = [
529564
goTo: GOTO.PROJECT_PLAN
530565
}]
531566
},
532-
567+
533568
{
534569
eventType: EVENT_TYPE.PROJECT_PLAN.TIMELINE_ADJUSTED,
535570
type: NOTIFICATION_TYPE.UPDATES,

0 commit comments

Comments
 (0)