Skip to content

Commit 52a089f

Browse files
committed
- GitIssue#2742[Team Management 2.0] Inviting already invited user fails without clear error message
1 parent 86db357 commit 52a089f

File tree

3 files changed

+79
-41
lines changed

3 files changed

+79
-41
lines changed

src/components/TeamManagement/ProjectManagementDialog.js

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import Modal from 'react-modal'
66
import XMarkIcon from '../../assets/icons/icon-x-mark.svg'
77
import Avatar from 'appirio-tech-react-components/components/Avatar/Avatar'
88
import { getAvatarResized } from '../../helpers/tcHelpers'
9+
import FormsyForm from 'appirio-tech-react-components/components/Formsy'
10+
const TCFormFields = FormsyForm.Fields
911

1012
class Dialog extends React.Component {
1113
constructor(props) {
@@ -14,11 +16,21 @@ class Dialog extends React.Component {
1416
inviteText: '',
1517
validInviteText: false,
1618
clearText: false,
19+
showAlreadyMemberError: false,
20+
invitedMembers: {},
21+
members: {}
1722
}
18-
this.onInviteChange = this.onInviteChange.bind(this)
23+
this.onChange = this.onChange.bind(this)
1924
this.sendInvites = this.sendInvites.bind(this)
2025
}
2126

27+
componentWillMount(){
28+
this.setState({
29+
invitedMembers: this.props.invites,
30+
members: this.props.members
31+
})
32+
}
33+
2234
componentWillReceiveProps(nextProps) {
2335
if (this.state.clearText && nextProps.processingInvites !== this.props.processingInvites &&
2436
!nextProps.processingInvites) {
@@ -30,16 +42,19 @@ class Dialog extends React.Component {
3042
}
3143
}
3244

33-
onInviteChange(evt) {
34-
const text = evt.target.value
45+
onChange(currentValues) {
46+
const text = currentValues.emails
3547
const invites = text.split(/[,;]/g)
3648
const isValid = invites.every(invite => {
3749
invite = invite.trim()
3850
return invite.length > 1 && (/(.+)@(.+){2,}\.(.+){2,}/.test(invite) || invite.startsWith('@'))
3951
})
52+
let present = _.some(this.state.invitedMembers, invited => invites.indexOf(invited.email) > -1)
53+
present = present || _.some(this.state.members, member => invites.indexOf(member.email) > -1)
4054
this.setState({
41-
validInviteText: isValid && text.trim().length > 0,
42-
inviteText: evt.target.value
55+
validInviteText: !present && isValid && text.trim().length > 0,
56+
inviteText: currentValues.emails,
57+
showAlreadyMemberError: present
4358
})
4459
}
4560

@@ -148,24 +163,27 @@ class Dialog extends React.Component {
148163
}))}
149164
</div>
150165

151-
<div className="input-container">
166+
<Formsy.Form className="input-container" onValidSubmit={this.sendInvites} onChange={this.onChange} >
152167
<div className="hint">invite more people</div>
153-
<input
168+
<TCFormFields.TextInput
169+
name="emails"
170+
wrapperClass="inviteTextInput"
154171
type="text"
155172
value={this.state.inviteText}
156-
onInput={this.onInviteChange}
157173
placeholder="Enter one or more emails separated by ';' or comma ','"
158-
className="tc-file-field__inputs"
159174
disabled={!isMember || this.state.clearText}
160175
/>
176+
{ this.state.showAlreadyMemberError && <div className="error-message">
177+
Project Member(s) can't be invited again. Please remove them from list.
178+
</div> }
161179
<button
162180
className="tc-btn tc-btn-primary tc-btn-md"
163-
onClick={this.sendInvites}
181+
type="submit"
164182
disabled={!this.state.validInviteText || this.state.clearText}
165183
>
166184
Send Invite
167185
</button>
168-
</div>
186+
</Formsy.Form>
169187
</div>
170188

171189
</Modal>

src/components/TeamManagement/TeamManagement.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,16 @@
322322
text-transform: uppercase;
323323
}
324324

325+
.inviteTextInput {
326+
@include roboto-medium;
327+
margin-top: $base-unit*2;
328+
width: 100%;
329+
text-align: center;
330+
font-size: $tc-label-xs;
331+
color: $tc-gray-50;
332+
text-transform: uppercase;
333+
}
334+
325335
input {
326336
width: stretch;
327337
margin: $base-unit*4 $base-unit*2;

src/components/TeamManagement/TopcoderManagementDialog.js

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import XMarkIcon from '../../assets/icons/icon-x-mark.svg'
88
import Avatar from 'appirio-tech-react-components/components/Avatar/Avatar'
99
import { getAvatarResized } from '../../helpers/tcHelpers'
1010
import Dropdown from 'appirio-tech-react-components/components/Dropdown/Dropdown'
11-
12-
11+
import FormsyForm from 'appirio-tech-react-components/components/Formsy'
12+
const TCFormFields = FormsyForm.Fields
1313

1414

1515
class Dialog extends React.Component {
@@ -21,12 +21,14 @@ class Dialog extends React.Component {
2121
validUserText: false,
2222
managerType: {},
2323
clearText: false,
24+
members: {},
25+
showAlreadyMemberError: false
2426
}
2527

2628
this.onUserRoleChange = this.onUserRoleChange.bind(this)
27-
this.onInviteChange = this.onInviteChange.bind(this)
2829
this.handleRoles = this.handleRoles.bind(this)
2930
this.addUsers = this.addUsers.bind(this)
31+
this.onChange = this.onChange.bind(this)
3032
}
3133

3234
componentWillMount(){
@@ -40,16 +42,19 @@ class Dialog extends React.Component {
4042
title: 'Copilot',
4143
value: 'copilot',
4244
}]
45+
this.setState({
46+
members: this.props.members
47+
})
4348
}
4449

45-
4650
componentWillReceiveProps(nextProps) {
4751
if (this.state.clearText && nextProps.processingInvites !== this.props.processingInvites &&
4852
!nextProps.processingInvites) {
4953
this.setState({
5054
userText: '',
5155
validUserText: false,
5256
clearText: false,
57+
members: this.props.members
5358
})
5459
}
5560
}
@@ -61,22 +66,6 @@ class Dialog extends React.Component {
6166
this.setState({managerType})
6267
}
6368

64-
onInviteChange(evt) {
65-
const text = evt.target.value
66-
const users = text.split(/[,;]/g)
67-
const isInvalid = users.some(user => {
68-
user = user.trim()
69-
if (user === '') {
70-
return false
71-
}
72-
return !(user.startsWith('@') && user.length > 1)
73-
})
74-
this.setState({
75-
validUserText: !isInvalid && text.trim().length > 0,
76-
userText: evt.target.value
77-
})
78-
}
79-
8069
handleRoles(value) {
8170
this.setState({
8271
userRole: value
@@ -96,6 +85,27 @@ class Dialog extends React.Component {
9685
this.setState({clearText: true})
9786
}
9887

88+
onChange(currentValues) {
89+
const text = currentValues.handlesText
90+
let handles = text.split(/[,;]/g)
91+
const isInvalid = handles.some(user => {
92+
user = user.trim()
93+
if (user === '') {
94+
return false
95+
}
96+
return !(user.startsWith('@') && user.length > 1)
97+
})
98+
const validText = !isInvalid && text.trim().length > 0
99+
handles = handles.filter((handle) => (handle.trim().startsWith('@') && handle.length > 1))
100+
handles = handles.map(handle => handle.trim().replace(/^@/, ''))
101+
const present = _.some(this.state.members, m => handles.indexOf(m.handle) > -1)
102+
this.setState({
103+
validUserText: !present && validText,
104+
showAlreadyMemberError: present,
105+
userText: text
106+
})
107+
}
108+
99109
render() {
100110
const {members, currentUser, isMember, removeMember, onCancel, removeInvite, invites = []} = this.props
101111
const showRemove = currentUser.isAdmin || (isMember && currentUser.isManager)
@@ -221,17 +231,19 @@ class Dialog extends React.Component {
221231
}))}
222232
</div>
223233

224-
{showRemove && <div className="input-container">
234+
{showRemove && <Formsy.Form className="input-container" onValidSubmit={this.addUsers} onChange={this.onChange} >
225235
<div className="hint">invite more people</div>
226-
<input
236+
<TCFormFields.TextInput
237+
name="handlesText"
238+
wrapperClass="inviteTextInput"
227239
type="text"
228240
value={this.state.userText}
229-
onInput={this.onInviteChange}
230241
placeholder="Enter one or more user @handles separated by ';' or comma ','"
231-
className="tc-file-field__inputs"
232242
disabled={!isMember || this.state.clearText}
233243
/>
234-
244+
{ this.state.showAlreadyMemberError && <div className="error-message">
245+
Project Member(s) can't be invited again. Please remove them from list.
246+
</div> }
235247
<Dropdown className="role-drop-down default">
236248
<div className="dropdown-menu-header">
237249
{(() => {
@@ -254,17 +266,15 @@ class Dialog extends React.Component {
254266
</ul>
255267
</div>
256268
</Dropdown>
257-
258-
259269
<button
260270
className="tc-btn tc-btn-primary tc-btn-md"
261-
onClick={this.addUsers}
271+
type="submit"
262272
disabled={!this.state.validUserText || this.state.clearText}
263273
>
264274
Send Invite
265275
</button>
266-
</div>}
267-
276+
</Formsy.Form>
277+
}
268278
{!showRemove && <div className="dialog-placeholder" />}
269279
</div>
270280
</Modal>

0 commit comments

Comments
 (0)