@@ -8,54 +8,95 @@ import Avatar from 'appirio-tech-react-components/components/Avatar/Avatar'
88import { getAvatarResized } from '../../helpers/tcHelpers'
99import AutocompleteInputContainer from './AutocompleteInputContainer'
1010
11- class Dialog extends React . Component {
11+ class ProjectManagementDialog extends React . Component {
1212 constructor ( props ) {
1313 super ( props )
1414 this . state = {
15- clearText : false ,
1615 showAlreadyMemberError : false ,
17- invitedMembers : { } ,
18- members : { }
16+ errorMessage : null
1917 }
2018 this . onChange = this . onChange . bind ( this )
19+ this . showIndividualErrors = this . showIndividualErrors . bind ( this )
2120 }
2221
23- componentWillMount ( ) {
22+ componentWillReceiveProps ( nextProps ) {
23+ const { processingInvites, selectedMembers } = this . props
24+
25+ if ( processingInvites && ! nextProps . processingInvites ) {
26+ const notInvitedSelectedMembers = _ . reject ( selectedMembers , ( selectedMember ) => (
27+ this . isSelectedMemberAlreadyInvited ( nextProps . invites , selectedMember )
28+ ) )
29+
30+ this . props . onSelectedMembersUpdate ( notInvitedSelectedMembers )
31+
32+ if ( nextProps . error ) {
33+ this . showIndividualErrors ( nextProps . error , notInvitedSelectedMembers )
34+ }
35+ }
36+ }
37+
38+ onChange ( selectedMembers ) {
39+ const { invites } = this . props
40+
41+ const present = _ . some ( selectedMembers , ( selectedMember ) => (
42+ this . isSelectedMemberAlreadyInvited ( invites , selectedMember )
43+ ) )
44+
2445 this . setState ( {
25- invitedMembers : this . props . invites ,
26- members : this . props . members
46+ validUserText : ! present ,
47+ showAlreadyMemberError : present ,
48+ errorMessage : null ,
2749 } )
50+
51+ this . props . onSelectedMembersUpdate ( selectedMembers )
2852 }
2953
30- onChange ( selectedMembers ) {
31- // If a member invited with email exists in selectedMembers
32- let present = _ . some ( this . state . invitedMembers , invited => _ . findIndex ( selectedMembers ,
33- selectedMember => selectedMember . isEmail && selectedMember . label === invited . email ) > - 1 )
34- // If a member invited with handle exists in selectedMembers
35- present = present || _ . some ( this . state . invitedMembers , invited => {
36- if ( ! invited . member ) {
37- return false
38- }
39- return _ . findIndex ( selectedMembers ,
40- selectedMember => ! selectedMember . isEmail && selectedMember . label === invited . member . handle ) > - 1
54+ isSelectedMemberAlreadyInvited ( invites = [ ] , selectedMember ) {
55+ return ! ! invites . find ( ( invite ) => (
56+ invite . email && invite . email === selectedMember . label ||
57+ invite . userId && this . resolveUserHandle ( invite . userId ) === selectedMember . label
58+ ) )
59+ }
60+
61+ /**
62+ * Get user handle using `allMembers` which comes from props and contains all the users
63+ * which are loaded to `members.members` in the Redux store
64+ *
65+ * @param {Number } userId user id
66+ */
67+ resolveUserHandle ( userId ) {
68+ const { allMembers } = this . props
69+
70+ return _ . find ( allMembers , { userId } ) . handle
71+ }
72+
73+ showIndividualErrors ( error ) {
74+ const uniqueMessages = _ . groupBy ( error . failed , 'message' )
75+
76+ const msgs = _ . keys ( uniqueMessages ) . map ( ( message ) => {
77+ const users = uniqueMessages [ message ] . map ( ( failed ) => (
78+ failed . email ? failed . email : this . resolveUserHandle ( failed . userId )
79+ ) )
80+
81+ return ( {
82+ message,
83+ users,
84+ } )
4185 } )
42- // If members exist in selectedMembers
43- present = present || _ . some ( this . state . members , m => _ . findIndex ( selectedMembers ,
44- selectedMember => selectedMember . label === m . handle ) > - 1 )
86+
87+ const listMessages = msgs . map ( ( m ) => ` ${ m . users . join ( ', ' ) } : ${ m . message } ` )
88+
4589 this . setState ( {
46- validInviteText : ! present ,
47- showAlreadyMemberError : present
90+ errorMessage : listMessages . length > 0 ? listMessages . join ( '\n' ) : null
4891 } )
49- this . props . onSelectedMembersUpdate ( selectedMembers )
5092 }
5193
5294 render ( ) {
5395 const {
5496 members, currentUser, isMember, removeMember, removeInvite,
55- onCancel, invites = [ ] , selectedMembers, processingInvites
97+ onCancel, invites = [ ] , selectedMembers, processingInvites,
5698 } = this . props
5799 const showRemove = currentUser . isAdmin || ( ! currentUser . isCopilot && isMember )
58- const allMembers = [ ...members , ...invites . map ( i => i . member ) ]
59100 let i = 0
60101 return (
61102 < Modal
@@ -156,15 +197,17 @@ class Dialog extends React.Component {
156197 currentUser = { currentUser }
157198 selectedMembers = { selectedMembers }
158199 disabled = { processingInvites || ( ! currentUser . isAdmin && ! isMember ) }
159- allMembers = { allMembers }
160200 />
161201 { this . state . showAlreadyMemberError && < div className = "error-message" >
162202 Project Member(s) can't be invited again. Please remove them from list.
163203 </ div > }
204+ { this . state . errorMessage && < div className = "error-message" >
205+ { this . state . errorMessage }
206+ </ div > }
164207 < button
165208 className = "tc-btn tc-btn-primary tc-btn-md"
166209 type = "submit"
167- disabled = { processingInvites || ! this . state . validInviteText || this . state . clearText }
210+ disabled = { processingInvites || this . state . showAlreadyMemberError || selectedMembers . length === 0 }
168211 onClick = { this . props . sendInvite }
169212 >
170213 Send Invite
@@ -177,15 +220,16 @@ class Dialog extends React.Component {
177220 }
178221}
179222
180- Dialog . defaultProps = {
223+ ProjectManagementDialog . defaultProps = {
181224 invites : [ ] ,
182225 members : [ ]
183226}
184227
185- Dialog . propTypes = {
228+ ProjectManagementDialog . propTypes = {
186229 error : PT . oneOfType ( [ PT . object , PT . bool ] ) ,
187230 currentUser : PT . object . isRequired ,
188231 members : PT . arrayOf ( PT . object ) . isRequired ,
232+ allMembers : PT . arrayOf ( PT . object ) . isRequired ,
189233 isMember : PT . bool . isRequired ,
190234 onCancel : PT . func . isRequired ,
191235 removeMember : PT . func . isRequired ,
@@ -197,4 +241,4 @@ Dialog.propTypes = {
197241 processingInvites : PT . bool . isRequired ,
198242}
199243
200- export default Dialog
244+ export default ProjectManagementDialog
0 commit comments