diff --git a/src/components/Users/Users.module.scss b/src/components/Users/Users.module.scss index 7451b0c6..a37c2395 100644 --- a/src/components/Users/Users.module.scss +++ b/src/components/Users/Users.module.scss @@ -40,6 +40,11 @@ } } +.textContent { + font-size: 18px; + margin-top: 25px; +} + .row { display: flex; @@ -400,7 +405,7 @@ justify-content: center; } -.addButtonContainer { +.addButtonContainer, .buttonWrapper { display: flex; justify-content: flex-start; height: 30px; @@ -412,10 +417,6 @@ } } -.addUserContentContainer { - -} - .tcRadioButton { .tc-radioButton-label { @include roboto-light(); diff --git a/src/components/Users/index.js b/src/components/Users/index.js index 5ddc2e67..cfbe5671 100644 --- a/src/components/Users/index.js +++ b/src/components/Users/index.js @@ -225,6 +225,9 @@ class Users extends Component { addNewProjectMember={this.props.addNewProjectMember} onMemberInvited={this.props.addNewProjectInvite} onClose={this.resetAddUserState} + projectOption={this.state.projectOption} + projectMembers={projectMembers} + updateProjectMember={updateProjectMember} /> ) } diff --git a/src/components/Users/user-add.modal.js b/src/components/Users/user-add.modal.js index 58b68d20..12a269e4 100644 --- a/src/components/Users/user-add.modal.js +++ b/src/components/Users/user-add.modal.js @@ -6,7 +6,7 @@ import Modal from '../Modal' import SelectUserAutocomplete from '../SelectUserAutocomplete' import { PROJECT_ROLES } from '../../config/constants' import PrimaryButton from '../Buttons/PrimaryButton' -import { addUserToProject, inviteUserToProject } from '../../services/projects' +import { addUserToProject, inviteUserToProject, updateProjectMemberRole } from '../../services/projects' import styles from './Users.module.scss' @@ -14,12 +14,22 @@ const theme = { container: styles.modalContainer } -const UserAddModalContent = ({ projectId, addNewProjectMember, onMemberInvited, onClose }) => { +const UserAddModalContent = ({ + projectMembers, + projectOption, + projectId, + addNewProjectMember, + onMemberInvited, + onClose, + updateProjectMember +}) => { const [userToAdd, setUserToAdd] = useState(null) const [userPermissionToAdd, setUserPermissionToAdd] = useState(PROJECT_ROLES.READ) const [showSelectUserError, setShowSelectUserError] = useState(false) const [addUserError, setAddUserError] = useState(null) const [isAdding, setIsAdding] = useState(false) + const [isUserAddingFailed, setUserAddingFailed] = useState(false) + const [existingRole, setExistingRole] = useState('') const onUpdateUserToAdd = (option) => { if (option && option.value) { @@ -52,8 +62,12 @@ const UserAddModalContent = ({ projectId, addNewProjectMember, onMemberInvited, }) if (failed) { const error = get(failed, '0.message', 'User cannot be invited') + const errorCode = get(failed, '0.error') + const role = get(failed, '0.role') setAddUserError(error) setIsAdding(false) + setUserAddingFailed(errorCode === 'ALREADY_MEMBER') + setExistingRole(role) } else if (rest.message) { setAddUserError(rest.message) setIsAdding(false) @@ -74,113 +88,141 @@ const UserAddModalContent = ({ projectId, addNewProjectMember, onMemberInvited, } } + const onConfirmCopilotRoleChange = async () => { + const member = projectMembers.find(item => item.userId === userToAdd.userId) + const action = member.role === 'manager' ? 'complete-copilot-requests' : '' + const response = await updateProjectMemberRole(projectId, member.id, 'copilot', action) + updateProjectMember(response) + onClose() + } + + const onCancelCopilotRoleChange = () => { + setUserAddingFailed(false) + setAddUserError('') + } + return ( -
-
Add User
-
-
-
- Member* : -
-
- + { + isUserAddingFailed && (['observer', 'customer', 'copilot', 'manager'].includes(existingRole)) && ( +
+
{`The copilot ${userToAdd.handle} is part of ${projectOption.label} project with ${existingRole} role.`}
+
+ +
- {showSelectUserError && ( -
-
Please select a member.
-
- )} -
-
- -
-
-
- setUserPermissionToAdd(PROJECT_ROLES.READ)} - /> - + ) + } + { + !isUserAddingFailed && ( +
+
Add User
+
+
+
+ Member* : +
+
+ +
-
-
-
- setUserPermissionToAdd(PROJECT_ROLES.WRITE)} - /> - + {showSelectUserError && ( +
+
Please select a member.
+
+ )} +
+
+ +
+
+
+ setUserPermissionToAdd(PROJECT_ROLES.READ)} + /> + +
+
+
+
+ setUserPermissionToAdd(PROJECT_ROLES.WRITE)} + /> + +
+
+
+
+ setUserPermissionToAdd(PROJECT_ROLES.MANAGER)} + /> + +
+
+
+
+ setUserPermissionToAdd(PROJECT_ROLES.COPILOT)} + /> + +
+
+ {addUserError && ( +
{addUserError}
+ )}
-
-
- setUserPermissionToAdd(PROJECT_ROLES.MANAGER)} +
+
+ -
-
-
-
- setUserPermissionToAdd(PROJECT_ROLES.COPILOT)} +
+ -
- {addUserError && ( -
{addUserError}
- )} -
-
-
- -
-
- -
-
-
+ ) + } ) } @@ -188,7 +230,10 @@ UserAddModalContent.propTypes = { projectId: PropTypes.number.isRequired, addNewProjectMember: PropTypes.func.isRequired, onMemberInvited: PropTypes.func.isRequired, - onClose: PropTypes.func.isRequired + onClose: PropTypes.func.isRequired, + projectOption: PropTypes.any.isRequired, + projectMembers: PropTypes.array.isRequired, + updateProjectMember: PropTypes.func.isRequired } export default UserAddModalContent diff --git a/src/services/projects.js b/src/services/projects.js index a3cf43c0..1a03221c 100644 --- a/src/services/projects.js +++ b/src/services/projects.js @@ -103,9 +103,10 @@ export async function fetchProjectPhases (id) { * @param newRole the new role * @returns {Promise<*>} */ -export async function updateProjectMemberRole (projectId, memberRecordId, newRole) { +export async function updateProjectMemberRole (projectId, memberRecordId, newRole, action) { const response = await axiosInstance.patch(`${PROJECTS_API_URL}/${projectId}/members/${memberRecordId}`, { - role: newRole + role: newRole, + action }) return _.get(response, 'data') }