diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index bc570df3c591..ade400cb2862 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -23,8 +23,6 @@ import ConfirmModal from '../../components/ConfirmModal'; import personalDetailsPropType from '../personalDetailsPropType'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions'; import OptionRow from '../../components/OptionRow'; -import CheckboxWithTooltip from '../../components/CheckboxWithTooltip'; -import Hoverable from '../../components/Hoverable'; import withPolicy, {policyPropTypes, policyDefaultProps} from './withPolicy'; import CONST from '../../CONST'; import OfflineWithFeedback from '../../components/OfflineWithFeedback'; @@ -32,6 +30,7 @@ import {withNetwork} from '../../components/OnyxProvider'; import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; import networkPropTypes from '../../components/networkPropTypes'; import * as Expensicons from '../../components/Icon/Expensicons'; +import FormHelpMessage from '../../components/FormHelpMessage'; const propTypes = { /** The personal details of the person who is logged in */ @@ -61,7 +60,7 @@ class WorkspaceMembersPage extends React.Component { this.state = { selectedEmployees: [], isRemoveMembersConfirmModalVisible: false, - showTooltipForLogin: '', + errors: {}, }; this.renderItem = this.renderItem.bind(this); @@ -77,6 +76,10 @@ class WorkspaceMembersPage extends React.Component { } componentDidUpdate(prevProps) { + if (prevProps.preferredLocale !== this.props.preferredLocale) { + this.validate(); + } + const isReconnecting = prevProps.network.isOffline && !this.props.network.isOffline; if (!isReconnecting) { return; @@ -110,6 +113,10 @@ class WorkspaceMembersPage extends React.Component { * Remove selected users from the workspace */ removeUsers() { + if (!_.isEmpty(this.state.errors)) { + return; + } + // Remove the admin from the list const membersToRemove = _.without(this.state.selectedEmployees, this.props.session.email); Policy.removeMembers(membersToRemove, this.props.route.params.policyID); @@ -123,6 +130,10 @@ class WorkspaceMembersPage extends React.Component { * Show the modal to confirm removal of the selected members */ askForConfirmationToRemove() { + if (!_.isEmpty(this.state.errors)) { + return; + } + this.setState({isRemoveMembersConfirmModalVisible: true}); } @@ -137,15 +148,14 @@ class WorkspaceMembersPage extends React.Component { * Add or remove all users from the selectedEmployees list */ toggleAllUsers() { - this.setState({showTooltipForLogin: ''}); let policyMemberList = lodashGet(this.props, 'policyMemberList', {}); policyMemberList = _.filter(_.keys(policyMemberList), policyMember => policyMemberList[policyMember].pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); const removableMembers = _.without(policyMemberList, this.props.session.email, this.props.policy.owner); this.setState(prevState => ({ - selectedEmployees: removableMembers.length !== prevState.selectedEmployees.length + selectedEmployees: !_.every(removableMembers, member => _.contains(prevState.selectedEmployees, member)) ? removableMembers : [], - })); + }), () => this.validate()); } /** @@ -156,49 +166,16 @@ class WorkspaceMembersPage extends React.Component { * */ toggleUser(login, pendingAction) { - if (this.willTooltipShowForLogin(login) || pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) { + if (pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) { return; } - // Add or remove the user if the checkbox is enabled and is clickable. + // Add or remove the user if the checkbox is enabled if (_.contains(this.state.selectedEmployees, login)) { this.removeUser(login); } else { this.addUser(login); } - - this.setState({showTooltipForLogin: ''}); - } - - /** - * Shows the tooltip for non removable members - * - * @param {String} login - * @param {Boolean} wasHovered - * @returns {Boolean} Return true if the tooltip was displayed so we can use the state of it in other functions. - */ - willTooltipShowForLogin(login, wasHovered = false) { - const isSmallOrMediumScreen = this.props.isSmallScreenWidth || this.props.isMediumScreenWidth; - - // Small screens only show the tooltip on press, so ignore hovered event on those cases. - if (wasHovered && isSmallOrMediumScreen) { - return false; - } - - const canBeRemoved = this.props.policy.owner !== login && this.props.session.email !== login; - if (!canBeRemoved) { - this.setState({ - showTooltipForLogin: login, - }, () => { - // Immediately reset the login to deactivate the tooltip trigger, otherwise, the tooltip will not open again on further interactions on small screens. - if (!isSmallOrMediumScreen) { - return; - } - this.setState({showTooltipForLogin: ''}); - }); - } - - return !canBeRemoved; } /** @@ -209,7 +186,7 @@ class WorkspaceMembersPage extends React.Component { addUser(login) { this.setState(prevState => ({ selectedEmployees: [...prevState.selectedEmployees, login], - })); + }), () => this.validate()); } /** @@ -220,7 +197,7 @@ class WorkspaceMembersPage extends React.Component { removeUser(login) { this.setState(prevState => ({ selectedEmployees: _.without(prevState.selectedEmployees, login), - })); + }), () => this.validate()); } /** @@ -229,7 +206,6 @@ class WorkspaceMembersPage extends React.Component { * @param {Object} item */ dismissError(item) { - // TODO: login here also probably will need to change when connecting this to the real api if (item.pendingAction === 'delete') { Policy.clearDeleteMemberError(this.props.route.params.policyID, item.login); } else { @@ -237,6 +213,19 @@ class WorkspaceMembersPage extends React.Component { } } + validate() { + const errors = {}; + _.each(this.state.selectedEmployees, (member) => { + if (member !== this.props.policy.owner && member !== this.props.session.email) { + return; + } + + errors[member] = this.props.translate('workspace.people.error.cannotRemove'); + }); + + this.setState({errors}); + } + /** * Do not move this or make it an anonymous function it is a method * so it will not be recreated each time we render an item @@ -252,48 +241,44 @@ class WorkspaceMembersPage extends React.Component { renderItem({ item, }) { - const canBeRemoved = this.props.policy.owner !== item.login && this.props.session.email !== item.login && item.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; return ( this.dismissError(item)} pendingAction={item.pendingAction} errors={item.errors}> - this.willTooltipShowForLogin(item.login, true)} onHoverOut={() => this.setState({showTooltipForLogin: ''})}> - this.toggleUser(item.login, item.pendingAction)} + activeOpacity={0.7} + > + this.toggleUser(item.login, item.pendingAction)} - activeOpacity={0.7} - > - this.toggleUser(item.login, item.pendingAction)} - toggleTooltip={this.state.showTooltipForLogin === item.login} - text={this.props.translate('workspace.people.error.cannotRemove')} + /> + + this.toggleUser(item.login, item.pendingAction)} + boldStyle + option={{ + text: Str.removeSMSDomain(item.displayName), + alternateText: Str.removeSMSDomain(item.login), + participantsList: [item], + icons: [item.avatar], + keyForList: item.login, + }} /> - - this.toggleUser(item.login, item.pendingAction)} - boldStyle - isDisabled={!canBeRemoved} - option={{ - text: Str.removeSMSDomain(item.displayName), - alternateText: Str.removeSMSDomain(item.login), - participantsList: [item], - icons: [item.avatar], - keyForList: item.login, - }} - /> - - {(this.props.session.email === item.login || item.role === 'admin') && ( - - - - {this.props.translate('common.admin')} - - + + {(this.props.session.email === item.login || item.role === 'admin') && ( + + + + {this.props.translate('common.admin')} + - )} - - + + )} + + {!_.isEmpty(this.state.errors[item.login]) && ( + + )} ); } @@ -365,7 +350,7 @@ class WorkspaceMembersPage extends React.Component { _.contains(this.state.selectedEmployees, member))} onPress={() => this.toggleAllUsers()} />