@@ -6,20 +6,30 @@ import Modal from '../Modal'
66import SelectUserAutocomplete from '../SelectUserAutocomplete'
77import { PROJECT_ROLES } from '../../config/constants'
88import PrimaryButton from '../Buttons/PrimaryButton'
9- import { addUserToProject , inviteUserToProject } from '../../services/projects'
9+ import { addUserToProject , inviteUserToProject , updateProjectMemberRole } from '../../services/projects'
1010
1111import styles from './Users.module.scss'
1212
1313const theme = {
1414 container : styles . modalContainer
1515}
1616
17- const UserAddModalContent = ( { projectId, addNewProjectMember, onMemberInvited, onClose } ) => {
17+ const UserAddModalContent = ( {
18+ projectMembers,
19+ projectOption,
20+ projectId,
21+ addNewProjectMember,
22+ onMemberInvited,
23+ onClose,
24+ updateProjectMember
25+ } ) => {
1826 const [ userToAdd , setUserToAdd ] = useState ( null )
1927 const [ userPermissionToAdd , setUserPermissionToAdd ] = useState ( PROJECT_ROLES . READ )
2028 const [ showSelectUserError , setShowSelectUserError ] = useState ( false )
2129 const [ addUserError , setAddUserError ] = useState ( null )
2230 const [ isAdding , setIsAdding ] = useState ( false )
31+ const [ isUserAddingFailed , setUserAddingFailed ] = useState ( false )
32+ const [ existingRole , setExistingRole ] = useState ( '' )
2333
2434 const onUpdateUserToAdd = ( option ) => {
2535 if ( option && option . value ) {
@@ -52,8 +62,12 @@ const UserAddModalContent = ({ projectId, addNewProjectMember, onMemberInvited,
5262 } )
5363 if ( failed ) {
5464 const error = get ( failed , '0.message' , 'User cannot be invited' )
65+ const errorCode = get ( failed , '0.error' )
66+ const role = get ( failed , '0.role' )
5567 setAddUserError ( error )
5668 setIsAdding ( false )
69+ setUserAddingFailed ( errorCode === 'ALREADY_MEMBER' )
70+ setExistingRole ( role )
5771 } else if ( rest . message ) {
5872 setAddUserError ( rest . message )
5973 setIsAdding ( false )
@@ -74,121 +88,152 @@ const UserAddModalContent = ({ projectId, addNewProjectMember, onMemberInvited,
7488 }
7589 }
7690
91+ const onConfirmCopilotRoleChange = async ( ) => {
92+ const member = projectMembers . find ( item => item . userId === userToAdd . userId )
93+ const action = member . role === 'manager' ? 'complete-copilot-requests' : ''
94+ const response = await updateProjectMemberRole ( projectId , member . id , 'copilot' , action )
95+ updateProjectMember ( response )
96+ onClose ( )
97+ }
98+
99+ const onCancelCopilotRoleChange = ( ) => {
100+ setUserAddingFailed ( false )
101+ setAddUserError ( '' )
102+ }
103+
77104 return (
78105 < Modal theme = { theme } onCancel = { onClose } >
79- < div className = { cn ( styles . contentContainer , styles . confirm ) } >
80- < div className = { styles . title } > Add User</ div >
81- < div className = { styles . addUserContentContainer } >
82- < div className = { styles . row } >
83- < div className = { cn ( styles . field , styles . col1 , styles . addUserTitle ) } >
84- Member< span className = { styles . required } > *</ span > :
85- </ div >
86- < div className = { cn ( styles . field , styles . col2 ) } >
87- < SelectUserAutocomplete
88- value = { userToAdd ? { label : userToAdd . handle , value : userToAdd . userId . toString ( ) } : null }
89- onChange = { onUpdateUserToAdd }
90- />
106+ {
107+ isUserAddingFailed && ( [ 'observer' , 'customer' , 'copilot' , 'manager' ] . includes ( existingRole ) ) && (
108+ < div className = { cn ( styles . contentContainer , styles . confirm ) } >
109+ < div className = { styles . textContent } > { `The copilot ${ userToAdd . handle } is part of ${ projectOption . label } project with ${ existingRole } role.` } </ div >
110+ < div className = { styles . buttonWrapper } >
111+ < PrimaryButton onClick = { onConfirmCopilotRoleChange } text = { 'Confirm' } type = { 'info' } />
112+ < PrimaryButton onClick = { onCancelCopilotRoleChange } text = { 'Cancel' } type = { 'disabled' } />
91113 </ div >
92114 </ div >
93- { showSelectUserError && (
94- < div className = { styles . row } >
95- < div className = { styles . errorMesssage } > Please select a member.</ div >
96- </ div >
97- ) }
98- < div className = { styles . row } >
99- < div className = { cn ( styles . field , styles . col1 , styles . addUserTitle ) } >
100- < label htmlFor = 'memberToAdd' > Role :</ label >
101- </ div >
102- < div className = { cn ( styles . col5 ) } >
103- < div className = { styles . tcRadioButton } >
104- < input
105- name = { `add-user-radio` }
106- type = 'radio'
107- id = { `read-add-user` }
108- checked = { userPermissionToAdd === PROJECT_ROLES . READ }
109- onChange = { ( ) => setUserPermissionToAdd ( PROJECT_ROLES . READ ) }
110- />
111- < label htmlFor = { `read-add-user` } >
112- < div > Read</ div >
113- < input type = 'hidden' />
114- </ label >
115+ )
116+ }
117+ {
118+ ! isUserAddingFailed && (
119+ < div className = { cn ( styles . contentContainer , styles . confirm ) } >
120+ < div className = { styles . title } > Add User</ div >
121+ < div className = { styles . addUserContentContainer } >
122+ < div className = { styles . row } >
123+ < div className = { cn ( styles . field , styles . col1 , styles . addUserTitle ) } >
124+ Member< span className = { styles . required } > *</ span > :
125+ </ div >
126+ < div className = { cn ( styles . field , styles . col2 ) } >
127+ < SelectUserAutocomplete
128+ value = { userToAdd ? { label : userToAdd . handle , value : userToAdd . userId . toString ( ) } : null }
129+ onChange = { onUpdateUserToAdd }
130+ />
131+ </ div >
115132 </ div >
116- </ div >
117- < div className = { cn ( styles . col5 ) } >
118- < div className = { styles . tcRadioButton } >
119- < input
120- name = { `add-user-radio` }
121- type = 'radio'
122- id = { `write-add-user` }
123- checked = { userPermissionToAdd === PROJECT_ROLES . WRITE }
124- onChange = { ( ) => setUserPermissionToAdd ( PROJECT_ROLES . WRITE ) }
125- />
126- < label htmlFor = { `write-add-user` } >
127- < div > Write</ div >
128- < input type = 'hidden' />
129- </ label >
133+ { showSelectUserError && (
134+ < div className = { styles . row } >
135+ < div className = { styles . errorMesssage } > Please select a member.</ div >
136+ </ div >
137+ ) }
138+ < div className = { styles . row } >
139+ < div className = { cn ( styles . field , styles . col1 , styles . addUserTitle ) } >
140+ < label htmlFor = 'memberToAdd' > Role :</ label >
141+ </ div >
142+ < div className = { cn ( styles . col5 ) } >
143+ < div className = { styles . tcRadioButton } >
144+ < input
145+ name = { `add-user-radio` }
146+ type = 'radio'
147+ id = { `read-add-user` }
148+ checked = { userPermissionToAdd === PROJECT_ROLES . READ }
149+ onChange = { ( ) => setUserPermissionToAdd ( PROJECT_ROLES . READ ) }
150+ />
151+ < label htmlFor = { `read-add-user` } >
152+ < div > Read</ div >
153+ < input type = 'hidden' />
154+ </ label >
155+ </ div >
156+ </ div >
157+ < div className = { cn ( styles . col5 ) } >
158+ < div className = { styles . tcRadioButton } >
159+ < input
160+ name = { `add-user-radio` }
161+ type = 'radio'
162+ id = { `write-add-user` }
163+ checked = { userPermissionToAdd === PROJECT_ROLES . WRITE }
164+ onChange = { ( ) => setUserPermissionToAdd ( PROJECT_ROLES . WRITE ) }
165+ />
166+ < label htmlFor = { `write-add-user` } >
167+ < div > Write</ div >
168+ < input type = 'hidden' />
169+ </ label >
170+ </ div >
171+ </ div >
172+ < div className = { cn ( styles . col5 ) } >
173+ < div className = { styles . tcRadioButton } >
174+ < input
175+ name = { `add-user-radio` }
176+ type = 'radio'
177+ id = { `full-access-add-user` }
178+ checked = { userPermissionToAdd === PROJECT_ROLES . MANAGER }
179+ onChange = { ( ) => setUserPermissionToAdd ( PROJECT_ROLES . MANAGER ) }
180+ />
181+ < label htmlFor = { `full-access-add-user` } >
182+ < div > Full Access</ div >
183+ < input type = 'hidden' />
184+ </ label >
185+ </ div >
186+ </ div >
187+ < div className = { cn ( styles . col5 ) } >
188+ < div className = { styles . tcRadioButton } >
189+ < input
190+ name = { `add-user-radio` }
191+ type = 'radio'
192+ id = { `copilot-add-user` }
193+ checked = { userPermissionToAdd === PROJECT_ROLES . COPILOT }
194+ onChange = { ( ) => setUserPermissionToAdd ( PROJECT_ROLES . COPILOT ) }
195+ />
196+ < label htmlFor = { `copilot-add-user` } >
197+ < div > Copilot</ div >
198+ < input type = 'hidden' />
199+ </ label >
200+ </ div >
201+ </ div >
130202 </ div >
203+ { addUserError && (
204+ < div className = { styles . errorMesssage } > { addUserError } </ div >
205+ ) }
131206 </ div >
132- < div className = { cn ( styles . col5 ) } >
133- < div className = { styles . tcRadioButton } >
134- < input
135- name = { `add-user-radio` }
136- type = 'radio'
137- id = { `full-access-add-user` }
138- checked = { userPermissionToAdd === PROJECT_ROLES . MANAGER }
139- onChange = { ( ) => setUserPermissionToAdd ( PROJECT_ROLES . MANAGER ) }
207+ < div className = { styles . buttonGroup } >
208+ < div className = { styles . buttonSizeA } >
209+ < PrimaryButton
210+ text = { 'Close' }
211+ type = { 'info' }
212+ onClick = { onClose }
140213 />
141- < label htmlFor = { `full-access-add-user` } >
142- < div > Full Access</ div >
143- < input type = 'hidden' />
144- </ label >
145214 </ div >
146- </ div >
147- < div className = { cn ( styles . col5 ) } >
148- < div className = { styles . tcRadioButton } >
149- < input
150- name = { `add-user-radio` }
151- type = 'radio'
152- id = { `copilot-add-user` }
153- checked = { userPermissionToAdd === PROJECT_ROLES . COPILOT }
154- onChange = { ( ) => setUserPermissionToAdd ( PROJECT_ROLES . COPILOT ) }
215+ < div className = { styles . buttonSizeA } >
216+ < PrimaryButton
217+ text = { isAdding ? 'Adding user...' : 'Add User' }
218+ type = { 'info' }
219+ onClick = { onAddUserConfirmClick }
155220 />
156- < label htmlFor = { `copilot-add-user` } >
157- < div > Copilot</ div >
158- < input type = 'hidden' />
159- </ label >
160221 </ div >
161222 </ div >
162223 </ div >
163- { addUserError && (
164- < div className = { styles . errorMesssage } > { addUserError } </ div >
165- ) }
166- </ div >
167- < div className = { styles . buttonGroup } >
168- < div className = { styles . buttonSizeA } >
169- < PrimaryButton
170- text = { 'Close' }
171- type = { 'info' }
172- onClick = { onClose }
173- />
174- </ div >
175- < div className = { styles . buttonSizeA } >
176- < PrimaryButton
177- text = { isAdding ? 'Adding user...' : 'Add User' }
178- type = { 'info' }
179- onClick = { onAddUserConfirmClick }
180- />
181- </ div >
182- </ div >
183- </ div >
224+ )
225+ }
184226 </ Modal >
185227 )
186228}
187229UserAddModalContent . propTypes = {
188230 projectId : PropTypes . number . isRequired ,
189231 addNewProjectMember : PropTypes . func . isRequired ,
190232 onMemberInvited : PropTypes . func . isRequired ,
191- onClose : PropTypes . func . isRequired
233+ onClose : PropTypes . func . isRequired ,
234+ projectOption : PropTypes . any . isRequired ,
235+ projectMembers : PropTypes . array . isRequired ,
236+ updateProjectMember : PropTypes . func . isRequired
192237}
193238
194239export default UserAddModalContent
0 commit comments