diff --git a/app/mm-redux/actions/teams.test.js b/app/mm-redux/actions/teams.test.js index d6fa96720..4f3dad2ff 100644 --- a/app/mm-redux/actions/teams.test.js +++ b/app/mm-redux/actions/teams.test.js @@ -386,18 +386,18 @@ describe('Actions.Teams', () => { nock(Client4.getTeamRoute(TestHelper.basicTeam.id)). post('/members'). reply(201, {user_id: user1.id, team_id: TestHelper.basicTeam.id}); - const {data: member1} = await Actions.addUserToTeam(TestHelper.basicTeam.id, user1.id)(store.dispatch, store.getState); + const {data: member1} = await store.dispatch(Actions.addUserToTeam(TestHelper.basicTeam.id, user1.id)); nock(Client4.getTeamRoute(TestHelper.basicTeam.id)). post('/members'). reply(201, {user_id: user2.id, team_id: TestHelper.basicTeam.id}); - const {data: member2} = await Actions.addUserToTeam(TestHelper.basicTeam.id, user2.id)(store.dispatch, store.getState); + const {data: member2} = await store.dispatch(Actions.addUserToTeam(TestHelper.basicTeam.id, user2.id)); nock(Client4.getBaseRoute()). get(`/teams/${TestHelper.basicTeam.id}/members`). query(true). reply(200, [member1, member2, TestHelper.basicTeamMember]); - await Actions.getTeamMembers(TestHelper.basicTeam.id)(store.dispatch, store.getState); + await store.dispatch(Actions.getTeamMembers(TestHelper.basicTeam.id)); const membersInTeam = store.getState().entities.teams.membersInTeam; assert.ok(membersInTeam[TestHelper.basicTeam.id]); diff --git a/app/mm-redux/actions/teams.ts b/app/mm-redux/actions/teams.ts index ff0fdcfac..14dfd9265 100644 --- a/app/mm-redux/actions/teams.ts +++ b/app/mm-redux/actions/teams.ts @@ -2,13 +2,12 @@ // See LICENSE.txt for license information. import {Client4} from '@mm-redux/client'; import {General} from '../constants'; -import {ChannelTypes, TeamTypes, UserTypes} from '@mm-redux/action_types'; +import {ChannelTypes, RoleTypes, TeamTypes, UserTypes} from '@mm-redux/action_types'; import EventEmitter from '@mm-redux/utils/event_emitter'; import {isCompatibleWithJoinViewTeamPermissions} from '@mm-redux/selectors/entities/general'; - +import {getRoles} from '@mm-redux/selectors/entities/roles_helpers'; import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; - import {getCurrentUserId} from '@mm-redux/selectors/entities/users'; import {GetStateFunc, DispatchFunc, ActionFunc, ActionResult, batchActions, Action} from '@mm-redux/types/actions'; @@ -417,16 +416,43 @@ export function addUserToTeam(teamId: string, userId: string): ActionFunc { return {error}; } - dispatch(batchActions([ - { - type: UserTypes.RECEIVED_PROFILE_IN_TEAM, - data: {id: teamId, user_id: userId}, - }, - { - type: TeamTypes.RECEIVED_MEMBER_IN_TEAM, - data: member, - }, - ])); + const actions: Array = [{ + type: UserTypes.RECEIVED_PROFILE_IN_TEAM, + data: {id: teamId, user_id: userId}, + }, { + type: TeamTypes.RECEIVED_MY_TEAM_MEMBER, + data: member, + }, { + type: TeamTypes.RECEIVED_MEMBER_IN_TEAM, + data: member, + }]; + + if (member.roles) { + const state = getState(); + const currentRoles = getRoles(state); + const rolesToLoad = new Set(); + for (const role of member.roles?.split(' ')) { + if (!currentRoles[role] && role.trim() !== '') { + rolesToLoad.add(role); + } + } + + if (rolesToLoad.size > 0) { + try { + const roles = await Client4.getRolesByNames(Array.from(rolesToLoad)); + if (roles.length) { + actions.push({ + type: RoleTypes.RECEIVED_ROLES, + data: roles, + }); + } + } catch { + // do nothing + } + } + } + + dispatch(batchActions(actions, 'BATCH_ADD_USER_TO_TEAM')); return {data: member}; }; diff --git a/app/mm-redux/reducers/entities/users.ts b/app/mm-redux/reducers/entities/users.ts index e23971043..65d8de110 100644 --- a/app/mm-redux/reducers/entities/users.ts +++ b/app/mm-redux/reducers/entities/users.ts @@ -280,18 +280,18 @@ function profilesNotInTeam(state: RelationOneToMany = {}, act function profilesWithoutTeam(state: Set = new Set(), action: GenericAction) { switch (action.type) { case UserTypes.RECEIVED_PROFILE_WITHOUT_TEAM: { - const nextSet = new Set(state); + const nextSet = new Set(Array.from(state)); Object.values(action.data).forEach((id: string) => nextSet.add(id)); return nextSet; } case UserTypes.RECEIVED_PROFILES_LIST_WITHOUT_TEAM: { - const nextSet = new Set(state); + const nextSet = new Set(Array.from(state)); action.data.forEach((user: UserProfile) => nextSet.add(user.id)); return nextSet; } case UserTypes.PROFILE_NO_LONGER_VISIBLE: case UserTypes.RECEIVED_PROFILE_IN_TEAM: { - const nextSet = new Set(state); + const nextSet = new Set(Array.from(state)); nextSet.delete(action.data.id); return nextSet; } diff --git a/app/screens/select_team/index.js b/app/screens/select_team/index.js index 582afa91e..c9e8e5336 100644 --- a/app/screens/select_team/index.js +++ b/app/screens/select_team/index.js @@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {getTeams, addUserToTeam, joinTeam} from '@mm-redux/actions/teams'; +import {getTeams, addUserToTeam} from '@mm-redux/actions/teams'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; import {getJoinableTeams} from '@mm-redux/selectors/entities/teams'; import {getCurrentUser} from '@mm-redux/selectors/entities/users'; @@ -24,7 +24,6 @@ function mapStateToProps(state) { currentUserId: currentUser && currentUser.id, currentUserIsGuest, isLandscape: isLandscape(state), - serverVersion: state.entities.general.serverVersion, teamsRequest: state.requests.teams.getTeams, teams: getJoinableTeams(state), theme: getTheme(state), @@ -36,7 +35,6 @@ function mapDispatchToProps(dispatch) { actions: bindActionCreators({ getTeams, handleTeamChange, - joinTeam, addUserToTeam, logout, }, dispatch), diff --git a/app/screens/select_team/select_team.js b/app/screens/select_team/select_team.js index e438b2fb8..74f9d6aa2 100644 --- a/app/screens/select_team/select_team.js +++ b/app/screens/select_team/select_team.js @@ -14,7 +14,6 @@ import {Navigation} from 'react-native-navigation'; import {RequestStatus} from '@mm-redux/constants'; import EventEmitter from '@mm-redux/utils/event_emitter'; -import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; import FormattedText from 'app/components/formatted_text'; import Loading from 'app/components/loading'; @@ -35,7 +34,6 @@ export default class SelectTeam extends PureComponent { actions: PropTypes.shape({ getTeams: PropTypes.func.isRequired, handleTeamChange: PropTypes.func.isRequired, - joinTeam: PropTypes.func.isRequired, addUserToTeam: PropTypes.func.isRequired, logout: PropTypes.func.isRequired, }).isRequired, @@ -47,7 +45,6 @@ export default class SelectTeam extends PureComponent { theme: PropTypes.object, teamsRequest: PropTypes.object.isRequired, isLandscape: PropTypes.bool.isRequired, - serverVersion: PropTypes.string, }; static defaultProps = { @@ -128,23 +125,15 @@ export default class SelectTeam extends PureComponent { onSelectTeam = async (team) => { this.setState({joining: true}); - const {userWithoutTeams, currentUserId, serverVersion} = this.props; + const {userWithoutTeams, currentUserId} = this.props; const { - joinTeam, addUserToTeam, handleTeamChange, } = this.props.actions; - let error; - if (isMinimumServerVersion(serverVersion, 5, 18)) { - const result = await addUserToTeam(team.id, currentUserId); - error = result.error; - } else { - const result = await joinTeam(team.invite_id, team.id); - error = result.error; - } - if (error) { - Alert.alert(error.message); + const result = await addUserToTeam(team.id, currentUserId); + if (result.error) { + Alert.alert(result.error.message); this.setState({joining: false}); return; } diff --git a/app/screens/select_team/select_team.test.js b/app/screens/select_team/select_team.test.js index c92fcd5e4..8a42af1f0 100644 --- a/app/screens/select_team/select_team.test.js +++ b/app/screens/select_team/select_team.test.js @@ -28,7 +28,6 @@ describe('SelectTeam', () => { getTeams, handleTeamChange: jest.fn(), addUserToTeam: jest.fn(), - joinTeam: jest.fn(), logout: jest.fn(), }; @@ -104,10 +103,9 @@ describe('SelectTeam', () => { expect(wrapper.getElement()).toMatchSnapshot(); }); - test('should call joinTeam versions prior to 5.18', async () => { + test('should call addUserToTeam', async () => { const props = { ...baseProps, - serverVersion: '5.17', }; const wrapper = shallow( @@ -115,22 +113,6 @@ describe('SelectTeam', () => { ); wrapper.instance().onSelectTeam({id: 'test_id', invite_id: 'test_invite_id'}); - expect(props.actions.joinTeam).toBeCalledWith('test_invite_id', 'test_id'); - expect(props.actions.addUserToTeam).not.toBeCalled(); - }); - - test('should call joinTeam versions posterior to 5.18', async () => { - const props = { - ...baseProps, - serverVersion: '5.18', - }; - - const wrapper = shallow( - , - ); - wrapper.instance().onSelectTeam({id: 'test_id', invite_id: 'test_invite_id'}); - - expect(props.actions.joinTeam).not.toBeCalled(); expect(props.actions.addUserToTeam).toBeCalledWith('test_id', 'fakeid'); }); });