From 2f5f247915efb7377e99b00fb7c3bd10ac1e3950 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 19 Apr 2021 15:21:27 -0400 Subject: [PATCH 01/14] Added Create Team --- app/i18n/locales/en.json | 6 ++++-- app/lib/rocketchat.js | 5 ++++- app/utils/log/events.js | 1 + app/views/CreateChannelView.js | 18 +++++++++++------- app/views/NewMessageView.js | 12 ++++++++++++ 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index ec289d27d8b..a0229ec9a75 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -709,5 +709,7 @@ "This_room_encryption_has_been_disabled_by__username_": "This room's encryption has been disabled by {{username}}", "Teams": "Teams", "No_team_channels_found": "No channels found", - "Team_not_found": "Team not found" -} \ No newline at end of file + "Team_not_found": "Team not found", + "Create_Team": "Create Team", + "Team_Name": "Team Name" +} diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index fc73e375fa0..bdff997ae75 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -728,7 +728,10 @@ const RocketChat = { prid, pmid, t_name, reply, users, encrypted }); }, - + createTeam(name) { + // RC 3.13.0 + return this.post('teams.create', name); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/utils/log/events.js b/app/utils/log/events.js index fc8d704200a..2ee22614828 100644 --- a/app/utils/log/events.js +++ b/app/utils/log/events.js @@ -87,6 +87,7 @@ export default { // NEW MESSAGE VIEW NEW_MSG_CREATE_CHANNEL: 'new_msg_create_channel', + NEW_MSG_CREATE_TEAM: 'new_msg_create_team', NEW_MSG_CREATE_GROUP_CHAT: 'new_msg_create_group_chat', NEW_MSG_CREATE_DISCUSSION: 'new_msg_create_discussion', NEW_MSG_CHAT_WITH_USER: 'new_msg_chat_with_user', diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 9d1e450ff2d..7690de270ca 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -69,11 +69,12 @@ const styles = StyleSheet.create({ class CreateChannelView extends React.Component { static navigationOptions = () => ({ - title: I18n.t('Create_Channel') - }); + title: this.props?.route?.params?.isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') + }) static propTypes = { navigation: PropTypes.object, + route: PropTypes.object, baseUrl: PropTypes.string, create: PropTypes.func.isRequired, removeUser: PropTypes.func.isRequired, @@ -302,7 +303,10 @@ class CreateChannelView extends React.Component { render() { const { channelName } = this.state; - const { users, isFetching, theme } = this.props; + const { + users, isFetching, route, theme + } = this.props; + const { isTeam } = route?.params; const userCount = users.length; return ( @@ -312,18 +316,18 @@ class CreateChannelView extends React.Component { keyboardVerticalOffset={128} > - + navigation.navigate('CreateChannelView') }); } + createTeam = () => { + logEvent(events.NEW_MSG_CREATE_TEAM); + const { navigation } = this.props; + navigation.navigate('SelectedUsersViewCreateChannel', { nextAction: () => navigation.navigate('CreateChannelView', { isTeam: true }) }); + } + createGroupChat = () => { logEvent(events.NEW_MSG_CREATE_GROUP_CHAT); const { createChannel, maxUsers, navigation } = this.props; @@ -172,6 +178,12 @@ class NewMessageView extends React.Component { testID: 'new-message-view-create-channel', first: true })} + {this.renderButton({ + onPress: this.createTeam, + title: I18n.t('Create_Team'), + icon: 'team', + testID: 'new-message-view-create-team' + })} {maxUsers > 2 ? this.renderButton({ onPress: this.createGroupChat, title: I18n.t('Create_Direct_Messages'), From 8b82bd456ea5dd43f922604e920da54092cc61a7 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 20 Apr 2021 05:30:30 -0400 Subject: [PATCH 02/14] Added actionTypes, actions, ENG strings for Teams and updated NewMessageView --- app/actions/actionsTypes.js | 1 + app/actions/createTeam.js | 22 ++++++++++++++++ app/i18n/locales/en.json | 5 +++- app/views/CreateChannelView.js | 46 +++++++++++++++++++++++++--------- app/views/NewMessageView.js | 6 +++-- 5 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 app/actions/createTeam.js diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index 1fd8679bcd1..14635008730 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -38,6 +38,7 @@ export const INQUIRY = createRequestTypes('INQUIRY', [...defaultTypes, 'SET_ENAB export const APP = createRequestTypes('APP', ['START', 'READY', 'INIT', 'INIT_LOCAL_SETTINGS', 'SET_MASTER_DETAIL']); export const MESSAGES = createRequestTypes('MESSAGES', ['REPLY_BROADCAST']); export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes]); +export const CREATE_TEAM = createRequestTypes('CREATE_TEAM', [...defaultTypes]); export const CREATE_DISCUSSION = createRequestTypes('CREATE_DISCUSSION', [...defaultTypes]); export const SELECTED_USERS = createRequestTypes('SELECTED_USERS', ['ADD_USER', 'REMOVE_USER', 'RESET', 'SET_LOADING']); export const SERVER = createRequestTypes('SERVER', [ diff --git a/app/actions/createTeam.js b/app/actions/createTeam.js new file mode 100644 index 00000000000..c91cce2d7cf --- /dev/null +++ b/app/actions/createTeam.js @@ -0,0 +1,22 @@ +import * as types from './actionsTypes'; + +export function createTeamRequest(data) { + return { + type: types.CREATE_TEAM.REQUEST, + data + }; +} + +export function createTeamSuccess(data) { + return { + type: types.CREATE_TEAM.SUCCESS, + data + }; +} + +export function createTeamFailure(err) { + return { + type: types.CREATE_TEAM.FAILURE, + err + }; +} diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index a0229ec9a75..635a7957bde 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -711,5 +711,8 @@ "No_team_channels_found": "No channels found", "Team_not_found": "Team not found", "Create_Team": "Create Team", - "Team_Name": "Team Name" + "Team_Name": "Team Name", + "Private_Team": "Private Team", + "Read_Only_Team": "Read Only Team", + "Broadcast_Team": "Broadcast Team" } diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 7690de270ca..5674f1d5e7c 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -10,6 +10,7 @@ import * as List from '../containers/List'; import TextInput from '../presentation/TextInput'; import Loading from '../containers/Loading'; import { createChannelRequest as createChannelRequestAction } from '../actions/createChannel'; +import { createTeamRequest as createTeamRequestAction } from '../actions/createTeam'; import { removeUser as removeUserAction } from '../actions/selectedUsers'; import sharedStyles from './Styles'; import KeyboardView from '../presentation/KeyboardView'; @@ -68,15 +69,16 @@ const styles = StyleSheet.create({ }); class CreateChannelView extends React.Component { - static navigationOptions = () => ({ - title: this.props?.route?.params?.isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') + static navigationOptions = ({ route }) => ({ + title: route?.params?.isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') }) static propTypes = { navigation: PropTypes.object, route: PropTypes.object, baseUrl: PropTypes.string, - create: PropTypes.func.isRequired, + createChannel: PropTypes.func.isRequired, + createTeam: PropTypes.func.isRequired, removeUser: PropTypes.func.isRequired, error: PropTypes.object, failure: PropTypes.bool, @@ -155,7 +157,10 @@ class CreateChannelView extends React.Component { const { channelName, type, readOnly, broadcast, encrypted } = this.state; - const { users: usersProps, isFetching, create } = this.props; + const { + users: usersProps, isFetching, createTeam, createChannel, route + } = this.props; + const { isTeam } = route?.params; if (!channelName.trim() || isFetching) { return; @@ -164,10 +169,17 @@ class CreateChannelView extends React.Component { // transform users object into array of usernames const users = usersProps.map(user => user.name); - // create channel - create({ - name: channelName, users, type, readOnly, broadcast, encrypted - }); + if (isTeam) { + // create team + createTeam({ + name: channelName, users, type, readOnly, broadcast, encrypted + }); + } else { + // create channel + createChannel({ + name: channelName, users, type, readOnly, broadcast, encrypted + }); + } Review.pushPositiveEvent(); } @@ -198,10 +210,13 @@ class CreateChannelView extends React.Component { renderType() { const { type } = this.state; + const { route } = this.props; + const { isTeam } = route?.params; + return this.renderSwitch({ id: 'type', value: type, - label: 'Private_Channel', + label: isTeam ? 'Private_Team' : 'Private_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_TYPE); // If we set the channel as public, encrypted status should be false @@ -212,10 +227,13 @@ class CreateChannelView extends React.Component { renderReadOnly() { const { readOnly, broadcast } = this.state; + const { route } = this.props; + const { isTeam } = route?.params; + return this.renderSwitch({ id: 'readonly', value: readOnly, - label: 'Read_Only_Channel', + label: isTeam ? 'Read_Only_Team' : 'Read_Only_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_READ_ONLY); this.setState({ readOnly: value }); @@ -246,10 +264,13 @@ class CreateChannelView extends React.Component { renderBroadcast() { const { broadcast, readOnly } = this.state; + const { route } = this.props; + const { isTeam } = route?.params; + return this.renderSwitch({ id: 'broadcast', value: broadcast, - label: 'Broadcast_Channel', + label: isTeam ? 'Broadcast_Team' : 'Broadcast_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_BROADCAST); this.setState({ @@ -364,7 +385,8 @@ const mapStateToProps = state => ({ }); const mapDispatchToProps = dispatch => ({ - create: data => dispatch(createChannelRequestAction(data)), + createChannel: data => dispatch(createChannelRequestAction(data)), + createTeam: data => dispatch(createTeamRequestAction(data)), removeUser: user => dispatch(removeUserAction(user)) }); diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index da0efdb4278..d8cdc01cb1b 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -23,6 +23,7 @@ import { withTheme } from '../theme'; import { getUserSelector } from '../selectors/login'; import Navigation from '../lib/Navigation'; import { createChannelRequest } from '../actions/createChannel'; +import { createTeamRequest } from '../actions/createTeam'; import { goRoom } from '../utils/goRoom'; import SafeAreaView from '../containers/SafeAreaView'; @@ -113,7 +114,7 @@ class NewMessageView extends React.Component { createChannel = () => { logEvent(events.NEW_MSG_CREATE_CHANNEL); const { navigation } = this.props; - navigation.navigate('SelectedUsersViewCreateChannel', { nextAction: () => navigation.navigate('CreateChannelView') }); + navigation.navigate('SelectedUsersViewCreateChannel', { nextAction: () => navigation.navigate('CreateChannelView', { isTeam: false }) }); } createTeam = () => { @@ -265,7 +266,8 @@ const mapStateToProps = state => ({ }); const mapDispatchToProps = dispatch => ({ - createChannel: params => dispatch(createChannelRequest(params)) + createChannel: params => dispatch(createChannelRequest(params)), + createTeam: params => dispatch(createTeamRequest(params)) }); export default connect(mapStateToProps, mapDispatchToProps)(withTheme(NewMessageView)); From c8b868054168ff3405685e6f1f46da50d9a09fd9 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 20 Apr 2021 19:07:33 -0400 Subject: [PATCH 03/14] Added createTeam sagas, createTeam reducer, new Team string and update CreateChannelView --- app/i18n/locales/en.json | 3 +- app/lib/rocketchat.js | 8 +++- app/reducers/createTeam.js | 36 +++++++++++++++ app/reducers/index.js | 2 + app/sagas/createTeam.js | 80 ++++++++++++++++++++++++++++++++++ app/sagas/index.js | 2 + app/views/CreateChannelView.js | 17 +++++--- 7 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 app/reducers/createTeam.js create mode 100644 app/sagas/createTeam.js diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 635a7957bde..f621d00a3bf 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -714,5 +714,6 @@ "Team_Name": "Team Name", "Private_Team": "Private Team", "Read_Only_Team": "Read Only Team", - "Broadcast_Team": "Broadcast Team" + "Broadcast_Team": "Broadcast Team", + "creating_team" : "creating team" } diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index bdff997ae75..9dfa39857a6 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -728,9 +728,13 @@ const RocketChat = { prid, pmid, t_name, reply, users, encrypted }); }, - createTeam(name) { + createTeam({ + name, users, type, readOnly, broadcast, encrypted + }) { // RC 3.13.0 - return this.post('teams.create', name); + return this.post('teams.create', { + name, users, type, readOnly, broadcast, encrypted + }); }, joinRoom(roomId, joinCode, type) { // TODO: join code diff --git a/app/reducers/createTeam.js b/app/reducers/createTeam.js new file mode 100644 index 00000000000..e962c6315e4 --- /dev/null +++ b/app/reducers/createTeam.js @@ -0,0 +1,36 @@ +import { CREATE_TEAM } from '../actions/actionsTypes'; + +const initialState = { + isFetching: false, + failure: false, + result: {}, + error: {} +}; + +export default function(state = initialState, action) { + switch (action.type) { + case CREATE_TEAM.REQUEST: + return { + ...state, + isFetching: true, + failure: false, + error: {} + }; + case CREATE_TEAM.SUCCESS: + return { + ...state, + isFetching: false, + failure: false, + result: action.data + }; + case CREATE_TEAM.FAILURE: + return { + ...state, + isFetching: false, + failure: true, + error: action.err + }; + default: + return state; + } +} diff --git a/app/reducers/index.js b/app/reducers/index.js index dfee5f3eb9c..aaad34fce16 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -7,6 +7,7 @@ import rooms from './rooms'; import server from './server'; import selectedUsers from './selectedUsers'; import createChannel from './createChannel'; +import createTeam from './createTeam'; import app from './app'; import sortPreferences from './sortPreferences'; import share from './share'; @@ -29,6 +30,7 @@ export default combineReducers({ server, selectedUsers, createChannel, + createTeam, app, room, rooms, diff --git a/app/sagas/createTeam.js b/app/sagas/createTeam.js new file mode 100644 index 00000000000..7da3e039447 --- /dev/null +++ b/app/sagas/createTeam.js @@ -0,0 +1,80 @@ +import { + select, put, call, take, takeLatest +} from 'redux-saga/effects'; +import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; + +import { CREATE_TEAM, LOGIN } from '../actions/actionsTypes'; +import { createTeamSuccess, createTeamFailure } from '../actions/createTeam'; +import { showErrorAlert } from '../utils/info'; +import RocketChat from '../lib/rocketchat'; +import Navigation from '../lib/Navigation'; +import database from '../lib/database'; +import I18n from '../i18n'; +import { logEvent, events } from '../utils/log'; +import { goRoom } from '../utils/goRoom'; + +const createTeam = function createTeam(data) { + return RocketChat.createTeam(data); +}; + +const handleRequest = function* handleRequest({ data }) { + try { + const auth = yield select(state => state.login.isAuthenticated); + if (!auth) { + yield take(LOGIN.SUCCESS); + } + + const { + type, readOnly, broadcast, encrypted + } = data; + + logEvent(events.CR_CREATE, { + type, + readOnly, + broadcast, + encrypted + }); + const sub = yield call(createTeam, data); + + try { + const db = database.active; + const subCollection = db.get('subscriptions'); + yield db.action(async() => { + await subCollection.create((s) => { + s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema); + Object.assign(s, sub); + }); + }); + } catch { + // do nothing + } + + yield put(createTeamSuccess(sub)); + } catch (err) { + logEvent(events[data.group ? 'SELECTED_USERS_CREATE_GROUP_F' : 'CR_CREATE_F']); + yield put(createTeamFailure(err)); + } +}; + +const handleSuccess = function* handleSuccess({ data }) { + const isMasterDetail = yield select(state => state.app.isMasterDetail); + if (isMasterDetail) { + Navigation.navigate('DrawerNavigator'); + } + goRoom({ item: data, isMasterDetail }); +}; + +const handleFailure = function handleFailure({ err }) { + setTimeout(() => { + const msg = err.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_team') }); + showErrorAlert(msg); + }, 300); +}; + +const root = function* root() { + yield takeLatest(CREATE_TEAM.REQUEST, handleRequest); + yield takeLatest(CREATE_TEAM.SUCCESS, handleSuccess); + yield takeLatest(CREATE_TEAM.FAILURE, handleFailure); +}; + +export default root; diff --git a/app/sagas/index.js b/app/sagas/index.js index e499d74ec5c..b5787d42441 100644 --- a/app/sagas/index.js +++ b/app/sagas/index.js @@ -5,6 +5,7 @@ import room from './room'; import messages from './messages'; import selectServer from './selectServer'; import createChannel from './createChannel'; +import createTeam from './createTeam'; import init from './init'; import state from './state'; import deepLinking from './deepLinking'; @@ -18,6 +19,7 @@ const root = function* root() { yield all([ init(), createChannel(), + createTeam(), rooms(), room(), login(), diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 5674f1d5e7c..9a300b8afd3 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -376,13 +376,16 @@ class CreateChannelView extends React.Component { } } -const mapStateToProps = state => ({ - baseUrl: state.server.server, - isFetching: state.createChannel.isFetching, - encryptionEnabled: state.encryption.enabled, - users: state.selectedUsers.users, - user: getUserSelector(state) -}); +const mapStateToProps = (state, ownProps) => { + const { route } = ownProps; + return { + baseUrl: state.server.server, + isFetching: route?.params?.isTeam ? state.createTeam.isFetching : state.createChannel.isFetching, + encryptionEnabled: state.encryption.enabled, + users: state.selectedUsers.users, + user: getUserSelector(state) + }; +}; const mapDispatchToProps = dispatch => ({ createChannel: data => dispatch(createChannelRequestAction(data)), From a245af6c1cc27858c7d337f14d8f9a51bdbbc50b Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 23 Apr 2021 08:28:01 -0400 Subject: [PATCH 04/14] Remove unnecessary actionTypes, reducers and sagas, e2e tests and navigation to team view --- app/actions/createTeam.js | 22 -------- app/lib/rocketchat.js | 16 +++++- app/reducers/createTeam.js | 36 ------------ app/reducers/index.js | 2 - app/sagas/createChannel.js | 26 ++++++++- app/sagas/createTeam.js | 80 --------------------------- app/sagas/index.js | 2 - app/utils/goRoom.js | 33 +++++++---- app/views/CreateChannelView.js | 41 +++++--------- app/views/NewMessageView.js | 4 +- e2e/data.js | 5 ++ e2e/helpers/data_setup.js | 27 +++++++++ e2e/tests/team/01-createteam.spec.js | 82 ++++++++++++++++++++++++++++ 13 files changed, 187 insertions(+), 189 deletions(-) delete mode 100644 app/actions/createTeam.js delete mode 100644 app/reducers/createTeam.js delete mode 100644 app/sagas/createTeam.js create mode 100644 e2e/tests/team/01-createteam.spec.js diff --git a/app/actions/createTeam.js b/app/actions/createTeam.js deleted file mode 100644 index c91cce2d7cf..00000000000 --- a/app/actions/createTeam.js +++ /dev/null @@ -1,22 +0,0 @@ -import * as types from './actionsTypes'; - -export function createTeamRequest(data) { - return { - type: types.CREATE_TEAM.REQUEST, - data - }; -} - -export function createTeamSuccess(data) { - return { - type: types.CREATE_TEAM.SUCCESS, - data - }; -} - -export function createTeamFailure(err) { - return { - type: types.CREATE_TEAM.FAILURE, - err - }; -} diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 9dfa39857a6..965f1c2114b 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -731,10 +731,20 @@ const RocketChat = { createTeam({ name, users, type, readOnly, broadcast, encrypted }) { + const params = { + name, + users, + type: type ? 1 : 0, + room: { + readOnly, + extraData: { + broadcast, + encrypted + } + } + }; // RC 3.13.0 - return this.post('teams.create', { - name, users, type, readOnly, broadcast, encrypted - }); + return this.post('teams.create', params); }, joinRoom(roomId, joinCode, type) { // TODO: join code diff --git a/app/reducers/createTeam.js b/app/reducers/createTeam.js deleted file mode 100644 index e962c6315e4..00000000000 --- a/app/reducers/createTeam.js +++ /dev/null @@ -1,36 +0,0 @@ -import { CREATE_TEAM } from '../actions/actionsTypes'; - -const initialState = { - isFetching: false, - failure: false, - result: {}, - error: {} -}; - -export default function(state = initialState, action) { - switch (action.type) { - case CREATE_TEAM.REQUEST: - return { - ...state, - isFetching: true, - failure: false, - error: {} - }; - case CREATE_TEAM.SUCCESS: - return { - ...state, - isFetching: false, - failure: false, - result: action.data - }; - case CREATE_TEAM.FAILURE: - return { - ...state, - isFetching: false, - failure: true, - error: action.err - }; - default: - return state; - } -} diff --git a/app/reducers/index.js b/app/reducers/index.js index aaad34fce16..dfee5f3eb9c 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -7,7 +7,6 @@ import rooms from './rooms'; import server from './server'; import selectedUsers from './selectedUsers'; import createChannel from './createChannel'; -import createTeam from './createTeam'; import app from './app'; import sortPreferences from './sortPreferences'; import share from './share'; @@ -30,7 +29,6 @@ export default combineReducers({ server, selectedUsers, createChannel, - createTeam, app, room, rooms, diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index 613aedec2cb..eb665a0944f 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -21,6 +21,10 @@ const createGroupChat = function createGroupChat() { return RocketChat.createGroupChat(); }; +const createTeam = function createTeam(data) { + return RocketChat.createTeam(data); +}; + const handleRequest = function* handleRequest({ data }) { try { const auth = yield select(state => state.login.isAuthenticated); @@ -29,7 +33,21 @@ const handleRequest = function* handleRequest({ data }) { } let sub; - if (data.group) { + if (data.isTeam) { + const { + type, + readOnly, + broadcast, + encrypted + } = data; + logEvent(events.CR_CREATE, { + type, + readOnly, + broadcast, + encrypted + }); + sub = yield call(createTeam, data); + } else if (data.group) { logEvent(events.SELECTED_USERS_CREATE_GROUP); const result = yield call(createGroupChat); if (result.success) { @@ -76,7 +94,11 @@ const handleSuccess = function* handleSuccess({ data }) { if (isMasterDetail) { Navigation.navigate('DrawerNavigator'); } - goRoom({ item: data, isMasterDetail }); + if (data.team) { + goRoom({ item: data.team, isMasterDetail }); + } else { + goRoom({ item: data, isMasterDetail }); + } }; const handleFailure = function handleFailure({ err }) { diff --git a/app/sagas/createTeam.js b/app/sagas/createTeam.js deleted file mode 100644 index 7da3e039447..00000000000 --- a/app/sagas/createTeam.js +++ /dev/null @@ -1,80 +0,0 @@ -import { - select, put, call, take, takeLatest -} from 'redux-saga/effects'; -import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; - -import { CREATE_TEAM, LOGIN } from '../actions/actionsTypes'; -import { createTeamSuccess, createTeamFailure } from '../actions/createTeam'; -import { showErrorAlert } from '../utils/info'; -import RocketChat from '../lib/rocketchat'; -import Navigation from '../lib/Navigation'; -import database from '../lib/database'; -import I18n from '../i18n'; -import { logEvent, events } from '../utils/log'; -import { goRoom } from '../utils/goRoom'; - -const createTeam = function createTeam(data) { - return RocketChat.createTeam(data); -}; - -const handleRequest = function* handleRequest({ data }) { - try { - const auth = yield select(state => state.login.isAuthenticated); - if (!auth) { - yield take(LOGIN.SUCCESS); - } - - const { - type, readOnly, broadcast, encrypted - } = data; - - logEvent(events.CR_CREATE, { - type, - readOnly, - broadcast, - encrypted - }); - const sub = yield call(createTeam, data); - - try { - const db = database.active; - const subCollection = db.get('subscriptions'); - yield db.action(async() => { - await subCollection.create((s) => { - s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema); - Object.assign(s, sub); - }); - }); - } catch { - // do nothing - } - - yield put(createTeamSuccess(sub)); - } catch (err) { - logEvent(events[data.group ? 'SELECTED_USERS_CREATE_GROUP_F' : 'CR_CREATE_F']); - yield put(createTeamFailure(err)); - } -}; - -const handleSuccess = function* handleSuccess({ data }) { - const isMasterDetail = yield select(state => state.app.isMasterDetail); - if (isMasterDetail) { - Navigation.navigate('DrawerNavigator'); - } - goRoom({ item: data, isMasterDetail }); -}; - -const handleFailure = function handleFailure({ err }) { - setTimeout(() => { - const msg = err.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_team') }); - showErrorAlert(msg); - }, 300); -}; - -const root = function* root() { - yield takeLatest(CREATE_TEAM.REQUEST, handleRequest); - yield takeLatest(CREATE_TEAM.SUCCESS, handleSuccess); - yield takeLatest(CREATE_TEAM.FAILURE, handleFailure); -}; - -export default root; diff --git a/app/sagas/index.js b/app/sagas/index.js index b5787d42441..e499d74ec5c 100644 --- a/app/sagas/index.js +++ b/app/sagas/index.js @@ -5,7 +5,6 @@ import room from './room'; import messages from './messages'; import selectServer from './selectServer'; import createChannel from './createChannel'; -import createTeam from './createTeam'; import init from './init'; import state from './state'; import deepLinking from './deepLinking'; @@ -19,7 +18,6 @@ const root = function* root() { yield all([ init(), createChannel(), - createTeam(), rooms(), room(), login(), diff --git a/app/utils/goRoom.js b/app/utils/goRoom.js index 94adfde4945..40fba6e973f 100644 --- a/app/utils/goRoom.js +++ b/app/utils/goRoom.js @@ -7,18 +7,27 @@ const navigate = ({ item, isMasterDetail, ...props }) => { if (isMasterDetail) { navigationMethod = Navigation.replace; } - - navigationMethod('RoomView', { - rid: item.rid, - name: RocketChat.getRoomTitle(item), - t: item.t, - prid: item.prid, - room: item, - search: item.search, - visitor: item.visitor, - roomUserId: RocketChat.getUidDirectMessage(item), - ...props - }); + console.log({ item }); + if (item.roomId) { + navigationMethod('RoomView', { + rid: item.roomId || item.rid, + name: RocketChat.getRoomTitle(item), + roomUserId: RocketChat.getUidDirectMessage(item), + ...props + }); + } else { + navigationMethod('RoomView', { + rid: item.rid, + name: RocketChat.getRoomTitle(item), + t: item.t, + prid: item.prid, + room: item, + search: item.search, + visitor: item.visitor, + roomUserId: RocketChat.getUidDirectMessage(item), + ...props + }); + } }; export const goRoom = async({ item = {}, isMasterDetail = false, ...props }) => { diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 9a300b8afd3..59b2ac06eab 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -10,7 +10,6 @@ import * as List from '../containers/List'; import TextInput from '../presentation/TextInput'; import Loading from '../containers/Loading'; import { createChannelRequest as createChannelRequestAction } from '../actions/createChannel'; -import { createTeamRequest as createTeamRequestAction } from '../actions/createTeam'; import { removeUser as removeUserAction } from '../actions/selectedUsers'; import sharedStyles from './Styles'; import KeyboardView from '../presentation/KeyboardView'; @@ -77,8 +76,7 @@ class CreateChannelView extends React.Component { navigation: PropTypes.object, route: PropTypes.object, baseUrl: PropTypes.string, - createChannel: PropTypes.func.isRequired, - createTeam: PropTypes.func.isRequired, + create: PropTypes.func.isRequired, removeUser: PropTypes.func.isRequired, error: PropTypes.object, failure: PropTypes.bool, @@ -158,7 +156,7 @@ class CreateChannelView extends React.Component { channelName, type, readOnly, broadcast, encrypted } = this.state; const { - users: usersProps, isFetching, createTeam, createChannel, route + users: usersProps, isFetching, create, route } = this.props; const { isTeam } = route?.params; @@ -169,17 +167,10 @@ class CreateChannelView extends React.Component { // transform users object into array of usernames const users = usersProps.map(user => user.name); - if (isTeam) { - // create team - createTeam({ - name: channelName, users, type, readOnly, broadcast, encrypted - }); - } else { - // create channel - createChannel({ - name: channelName, users, type, readOnly, broadcast, encrypted - }); - } + // create channel or team + create({ + name: channelName, users, type, readOnly, broadcast, encrypted, isTeam + }); Review.pushPositiveEvent(); } @@ -376,20 +367,16 @@ class CreateChannelView extends React.Component { } } -const mapStateToProps = (state, ownProps) => { - const { route } = ownProps; - return { - baseUrl: state.server.server, - isFetching: route?.params?.isTeam ? state.createTeam.isFetching : state.createChannel.isFetching, - encryptionEnabled: state.encryption.enabled, - users: state.selectedUsers.users, - user: getUserSelector(state) - }; -}; +const mapStateToProps = state => ({ + baseUrl: state.server.server, + isFetching: state.createChannel.isFetching, + encryptionEnabled: state.encryption.enabled, + users: state.selectedUsers.users, + user: getUserSelector(state) +}); const mapDispatchToProps = dispatch => ({ - createChannel: data => dispatch(createChannelRequestAction(data)), - createTeam: data => dispatch(createTeamRequestAction(data)), + create: data => dispatch(createChannelRequestAction(data)), removeUser: user => dispatch(removeUserAction(user)) }); diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index d8cdc01cb1b..8d916e456ca 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -23,7 +23,6 @@ import { withTheme } from '../theme'; import { getUserSelector } from '../selectors/login'; import Navigation from '../lib/Navigation'; import { createChannelRequest } from '../actions/createChannel'; -import { createTeamRequest } from '../actions/createTeam'; import { goRoom } from '../utils/goRoom'; import SafeAreaView from '../containers/SafeAreaView'; @@ -266,8 +265,7 @@ const mapStateToProps = state => ({ }); const mapDispatchToProps = dispatch => ({ - createChannel: params => dispatch(createChannelRequest(params)), - createTeam: params => dispatch(createTeamRequest(params)) + create: params => dispatch(createChannelRequest(params)) }); export default connect(mapStateToProps, mapDispatchToProps)(withTheme(NewMessageView)); diff --git a/e2e/data.js b/e2e/data.js index 79e7842e864..c69b72515bd 100644 --- a/e2e/data.js +++ b/e2e/data.js @@ -42,6 +42,11 @@ const data = { name: `detox-private-${ value }` } }, + teams: { + private: { + name: `detox-team-${ value }` + } + }, registeringUser: { username: `newuser${ value }`, password: `password${ value }`, diff --git a/e2e/helpers/data_setup.js b/e2e/helpers/data_setup.js index 1f8f8fb6511..9d0dad492cc 100644 --- a/e2e/helpers/data_setup.js +++ b/e2e/helpers/data_setup.js @@ -57,6 +57,26 @@ const createChannelIfNotExists = async (channelname) => { } } +const createTeamIfNotExists = async (teamname) => { + console.log(`Creating private team ${teamname}`) + try { + const team = await rocketchat.post('teams.create', { + "name": teamname, + "type": 1 + }) + return team + } catch (createError) { + try { //Maybe it exists already? + const team = rocketchat.get(`teams.info?teamName=${teamname}`) + return team + } catch (infoError) { + console.log(JSON.stringify(createError)) + console.log(JSON.stringify(infoError)) + throw "Failed to find or create private team" + } + } +} + const createGroupIfNotExists = async (groupname) => { console.log(`Creating private group ${groupname}`) try { @@ -133,6 +153,13 @@ const setup = async () => { } } + for (var teamKey in data.teams) { + if (data.teams.hasOwnProperty(teamKey)) { + const team = data.teams[teamKey] + await createTeamIfNotExists(team.name) + } + } + return } diff --git a/e2e/tests/team/01-createteam.spec.js b/e2e/tests/team/01-createteam.spec.js new file mode 100644 index 00000000000..6e06b69f059 --- /dev/null +++ b/e2e/tests/team/01-createteam.spec.js @@ -0,0 +1,82 @@ +const { + device, expect, element, by, waitFor +} = require('detox'); +const data = require('../../data'); +const { tapBack, sleep, navigateToLogin, login, tryTapping } = require('../../helpers/app'); + + + +describe('Create team screen', () => { + before(async() => { + await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); + await navigateToLogin(); + await login(data.users.regular.username, data.users.regular.password); + }); + + describe('New Message', async() => { + before(async() => { + await element(by.id('rooms-list-view-create-channel')).tap(); + }); + + describe('Render', async() => { + it('should have team button', async() => { + await waitFor(element(by.id('new-message-view-create-team'))).toBeVisible().withTimeout(2000); + }); + }) + + describe('Usage', async() => { + it('should navigate to select users', async() => { + await element(by.id('new-message-view-create-team')).tap(); + await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(5000); + }); + }) + }); + + describe('Select Users', async() => { + it('should search users', async() => { + await element(by.id('select-users-view-search')).replaceText('rocket.cat'); + await waitFor(element(by.id(`select-users-view-item-rocket.cat`))).toBeVisible().withTimeout(10000); + }); + + it('should select/unselect user', async() => { + // Spotlight issues + await element(by.id('select-users-view-item-rocket.cat')).tap(); + await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(10000); + await element(by.id('selected-user-rocket.cat')).tap(); + await waitFor(element(by.id('selected-user-rocket.cat'))).toBeNotVisible().withTimeout(10000); + // Spotlight issues + await element(by.id('select-users-view-item-rocket.cat')).tap(); + await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(10000); + }); + + it('should create team', async() => { + await element(by.id('selected-users-view-submit')).tap(); + await waitFor(element(by.id('create-team-view'))).toExist().withTimeout(10000); + }); + }) + + describe('Create Team', async() => { + describe('Usage', async() => { + it('should get invalid team name', async() => { + await element(by.id('create-team-name')).typeText(`${data.teams.private.name}`); + await element(by.id('create-channel-submit')).tap(); + await element(by.text('OK')).tap(); + }); + + it('should create private team', async() => { + const room = `private${ data.random }`; + await element(by.id('create-team-name')).replaceText(''); + await element(by.id('create-team-name')).typeText(room); + await element(by.id('create-channel-submit')).tap(); + await waitFor(element(by.id('room-view'))).toExist().withTimeout(20000); + await expect(element(by.id('room-view'))).toExist(); + await waitFor(element(by.id(`room-view-title-${ room }`))).toExist().withTimeout(6000); + await expect(element(by.id(`room-view-title-${ room }`))).toExist(); + await tapBack(); + await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000); + await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(6000); + await expect(element(by.id(`rooms-list-view-item-${ room }`))).toExist(); + }); + }) + }); +}); From 16fd57527a9810ce653f7038d8e721954f1a802a Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 26 Apr 2021 10:08:24 -0400 Subject: [PATCH 05/14] Minor tweaks --- app/actions/actionsTypes.js | 1 - app/i18n/locales/en.json | 3 ++- app/lib/methods/loadMessagesForRoom.js | 13 +++++++--- app/sagas/createChannel.js | 10 +++----- app/utils/goRoom.js | 33 ++++++++++---------------- app/views/SelectedUsersView.js | 6 ++++- 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index 14635008730..1fd8679bcd1 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -38,7 +38,6 @@ export const INQUIRY = createRequestTypes('INQUIRY', [...defaultTypes, 'SET_ENAB export const APP = createRequestTypes('APP', ['START', 'READY', 'INIT', 'INIT_LOCAL_SETTINGS', 'SET_MASTER_DETAIL']); export const MESSAGES = createRequestTypes('MESSAGES', ['REPLY_BROADCAST']); export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes]); -export const CREATE_TEAM = createRequestTypes('CREATE_TEAM', [...defaultTypes]); export const CREATE_DISCUSSION = createRequestTypes('CREATE_DISCUSSION', [...defaultTypes]); export const SELECTED_USERS = createRequestTypes('SELECTED_USERS', ['ADD_USER', 'REMOVE_USER', 'RESET', 'SET_LOADING']); export const SERVER = createRequestTypes('SERVER', [ diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index f621d00a3bf..58438f31954 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -715,5 +715,6 @@ "Private_Team": "Private Team", "Read_Only_Team": "Read Only Team", "Broadcast_Team": "Broadcast Team", - "creating_team" : "creating team" + "creating_team" : "creating team", + "team-name-already-exists": "A team with that name already exists" } diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js index 012e1ea3275..9ab5cf215c5 100644 --- a/app/lib/methods/loadMessagesForRoom.js +++ b/app/lib/methods/loadMessagesForRoom.js @@ -1,13 +1,20 @@ import log from '../../utils/log'; import updateMessages from './updateMessages'; -async function load({ rid: roomId, latest, t }) { - let params = { roomId, count: 50 }; +async function load({ + rid: roomId, latest, t, team +}) { + let params = { roomId: roomId || team.roomId, count: 50 }; + let apiType; if (latest) { params = { ...params, latest: new Date(latest).toISOString() }; } - const apiType = this.roomTypeToApiType(t); + if (team.type) { + apiType = this.roomTypeToApiType('p'); + } else { + apiType = this.roomTypeToApiType(t); + } if (!apiType) { return []; } diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index eb665a0944f..f8e96aeb190 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -74,7 +74,7 @@ const handleRequest = function* handleRequest({ data }) { const subCollection = db.get('subscriptions'); yield db.action(async() => { await subCollection.create((s) => { - s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema); + s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.rid }, subCollection.schema); Object.assign(s, sub); }); }); @@ -94,16 +94,12 @@ const handleSuccess = function* handleSuccess({ data }) { if (isMasterDetail) { Navigation.navigate('DrawerNavigator'); } - if (data.team) { - goRoom({ item: data.team, isMasterDetail }); - } else { - goRoom({ item: data, isMasterDetail }); - } + goRoom({ item: data.team ? data.team : data, isMasterDetail }); }; const handleFailure = function handleFailure({ err }) { setTimeout(() => { - const msg = err.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_channel') }); + const msg = err.data ? I18n.t(err.data.error) : err.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_channel') }); showErrorAlert(msg); }, 300); }; diff --git a/app/utils/goRoom.js b/app/utils/goRoom.js index 40fba6e973f..45736e337a1 100644 --- a/app/utils/goRoom.js +++ b/app/utils/goRoom.js @@ -7,27 +7,18 @@ const navigate = ({ item, isMasterDetail, ...props }) => { if (isMasterDetail) { navigationMethod = Navigation.replace; } - console.log({ item }); - if (item.roomId) { - navigationMethod('RoomView', { - rid: item.roomId || item.rid, - name: RocketChat.getRoomTitle(item), - roomUserId: RocketChat.getUidDirectMessage(item), - ...props - }); - } else { - navigationMethod('RoomView', { - rid: item.rid, - name: RocketChat.getRoomTitle(item), - t: item.t, - prid: item.prid, - room: item, - search: item.search, - visitor: item.visitor, - roomUserId: RocketChat.getUidDirectMessage(item), - ...props - }); - } + + navigationMethod('RoomView', { + rid: item.roomId || item.rid, + name: RocketChat.getRoomTitle(item), + t: item.type ? 'p' : item.t, + prid: item.prid, + room: item, + search: item.search, + visitor: item.visitor, + roomUserId: RocketChat.getUidDirectMessage(item), + ...props + }); }; export const goRoom = async({ item = {}, isMasterDetail = false, ...props }) => { diff --git a/app/views/SelectedUsersView.js b/app/views/SelectedUsersView.js index f9d14e16905..eb3292bb327 100644 --- a/app/views/SelectedUsersView.js +++ b/app/views/SelectedUsersView.js @@ -50,7 +50,7 @@ class SelectedUsersView extends React.Component { constructor(props) { super(props); this.init(); - + this.flatlist = React.createRef(); const maxUsers = props.route.params?.maxUsers; this.state = { maxUsers, @@ -190,9 +190,13 @@ class SelectedUsersView extends React.Component { if (users.length === 0) { return null; } + const ITEM_WIDTH = 250; return ( this.flatlist = ref} + onContentSizeChange={() => this.flatlist.scrollToEnd()} + getItemLayout={(_, index) => ({ length: ITEM_WIDTH, offset: ITEM_WIDTH * index, index })} keyExtractor={item => item._id} style={[sharedStyles.separatorTop, { borderColor: themes[theme].separatorColor }]} contentContainerStyle={{ marginVertical: 5 }} From 1ff77118f525f172b8f99ab2d80e94aeb7fe104e Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 26 Apr 2021 10:21:04 -0400 Subject: [PATCH 06/14] Show TeamChannelsView only if joined the team --- app/views/RoomView/RightButtons.js | 7 ++++--- app/views/RoomView/index.js | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/views/RoomView/RightButtons.js b/app/views/RoomView/RightButtons.js index debc3edb9e5..398f868b8a8 100644 --- a/app/views/RoomView/RightButtons.js +++ b/app/views/RoomView/RightButtons.js @@ -18,7 +18,8 @@ class RightButtonsContainer extends Component { teamId: PropTypes.bool, navigation: PropTypes.object, isMasterDetail: PropTypes.bool, - toggleFollowThread: PropTypes.func + toggleFollowThread: PropTypes.func, + joined: PropTypes.bool }; constructor(props) { @@ -163,7 +164,7 @@ class RightButtonsContainer extends Component { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state; const { - t, tmid, threadsEnabled, teamId + t, tmid, threadsEnabled, teamId, joined } = this.props; if (t === 'l') { return null; @@ -181,7 +182,7 @@ class RightButtonsContainer extends Component { } return ( - {teamId ? ( + {teamId && joined ? ( { const { - room, unreadsCount, roomUserId + room, unreadsCount, roomUserId, joined } = this.state; const { navigation, isMasterDetail, theme, baseUrl, user, insets, route @@ -331,7 +331,7 @@ class RoomView extends React.Component { let numIconsRight = 2; if (tmid) { numIconsRight = 1; - } else if (teamId) { + } else if (teamId && joined) { numIconsRight = 3; } const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight }); @@ -380,6 +380,7 @@ class RoomView extends React.Component { rid={rid} tmid={tmid} teamId={teamId} + joined={joined} t={t} navigation={navigation} toggleFollowThread={this.toggleFollowThread} From 69214bee9363c0f69c4f4b13ae9a0a0084d3b1f2 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 26 Apr 2021 14:03:05 -0400 Subject: [PATCH 07/14] Minor tweak --- app/views/CreateChannelView.js | 49 ++++++++++++++++------------------ app/views/NewMessageView.js | 2 +- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 59b2ac06eab..54d70d80b50 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -68,8 +68,8 @@ const styles = StyleSheet.create({ }); class CreateChannelView extends React.Component { - static navigationOptions = ({ route }) => ({ - title: route?.params?.isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') + static navigationOptions = () => ({ + title: this.isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') }) static propTypes = { @@ -90,12 +90,17 @@ class CreateChannelView extends React.Component { theme: PropTypes.string }; - state = { - channelName: '', - type: true, - readOnly: false, - encrypted: false, - broadcast: false + constructor(props) { + super(props); + const { route } = this.props; + this.isTeam = route?.params?.isTeam || false; + this.state = { + channelName: '', + type: true, + readOnly: false, + encrypted: false, + broadcast: false + }; } shouldComponentUpdate(nextProps, nextState) { @@ -156,9 +161,8 @@ class CreateChannelView extends React.Component { channelName, type, readOnly, broadcast, encrypted } = this.state; const { - users: usersProps, isFetching, create, route + users: usersProps, isFetching, create } = this.props; - const { isTeam } = route?.params; if (!channelName.trim() || isFetching) { return; @@ -169,7 +173,7 @@ class CreateChannelView extends React.Component { // create channel or team create({ - name: channelName, users, type, readOnly, broadcast, encrypted, isTeam + name: channelName, users, type, readOnly, broadcast, encrypted, isTeam: this.isTeam }); Review.pushPositiveEvent(); @@ -201,13 +205,11 @@ class CreateChannelView extends React.Component { renderType() { const { type } = this.state; - const { route } = this.props; - const { isTeam } = route?.params; return this.renderSwitch({ id: 'type', value: type, - label: isTeam ? 'Private_Team' : 'Private_Channel', + label: this.isTeam ? 'Private_Team' : 'Private_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_TYPE); // If we set the channel as public, encrypted status should be false @@ -218,13 +220,11 @@ class CreateChannelView extends React.Component { renderReadOnly() { const { readOnly, broadcast } = this.state; - const { route } = this.props; - const { isTeam } = route?.params; return this.renderSwitch({ id: 'readonly', value: readOnly, - label: isTeam ? 'Read_Only_Team' : 'Read_Only_Channel', + label: this.isTeam ? 'Read_Only_Team' : 'Read_Only_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_READ_ONLY); this.setState({ readOnly: value }); @@ -255,13 +255,11 @@ class CreateChannelView extends React.Component { renderBroadcast() { const { broadcast, readOnly } = this.state; - const { route } = this.props; - const { isTeam } = route?.params; return this.renderSwitch({ id: 'broadcast', value: broadcast, - label: isTeam ? 'Broadcast_Team' : 'Broadcast_Channel', + label: this.isTeam ? 'Broadcast_Team' : 'Broadcast_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_BROADCAST); this.setState({ @@ -316,9 +314,8 @@ class CreateChannelView extends React.Component { render() { const { channelName } = this.state; const { - users, isFetching, route, theme + users, isFetching, theme } = this.props; - const { isTeam } = route?.params; const userCount = users.length; return ( @@ -328,18 +325,18 @@ class CreateChannelView extends React.Component { keyboardVerticalOffset={128} > - + { logEvent(events.NEW_MSG_CREATE_CHANNEL); const { navigation } = this.props; - navigation.navigate('SelectedUsersViewCreateChannel', { nextAction: () => navigation.navigate('CreateChannelView', { isTeam: false }) }); + navigation.navigate('SelectedUsersViewCreateChannel', { nextAction: () => navigation.navigate('CreateChannelView') }); } createTeam = () => { From 7e6a277ede4230a10dbca1a195de7f66f2c4084a Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 11 May 2021 07:39:05 -0400 Subject: [PATCH 08/14] Minor tweaks --- app/lib/methods/loadMessagesForRoom.js | 10 +++--- app/sagas/createChannel.js | 2 +- app/utils/goRoom.js | 2 +- app/views/CreateChannelView.js | 45 +++++++++++++++----------- app/views/RoomView/RightButtons.js | 7 ++-- app/views/RoomView/index.js | 3 +- e2e/helpers/data_setup.js | 6 ++-- e2e/tests/team/01-createteam.spec.js | 12 +++---- 8 files changed, 46 insertions(+), 41 deletions(-) diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js index 9ab5cf215c5..df04aa36761 100644 --- a/app/lib/methods/loadMessagesForRoom.js +++ b/app/lib/methods/loadMessagesForRoom.js @@ -5,16 +5,14 @@ async function load({ rid: roomId, latest, t, team }) { let params = { roomId: roomId || team.roomId, count: 50 }; - let apiType; + if (latest) { params = { ...params, latest: new Date(latest).toISOString() }; } - if (team.type) { - apiType = this.roomTypeToApiType('p'); - } else { - apiType = this.roomTypeToApiType(t); - } + const teamType = team?.type ? 'p' : 'c'; + const apiType = this.roomTypeToApiType(teamType || t); + if (!apiType) { return []; } diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index f8e96aeb190..eabe218dff6 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -94,7 +94,7 @@ const handleSuccess = function* handleSuccess({ data }) { if (isMasterDetail) { Navigation.navigate('DrawerNavigator'); } - goRoom({ item: data.team ? data.team : data, isMasterDetail }); + goRoom({ item: data.success ? data.team : data, isMasterDetail }); }; const handleFailure = function handleFailure({ err }) { diff --git a/app/utils/goRoom.js b/app/utils/goRoom.js index 45736e337a1..d157cc0b604 100644 --- a/app/utils/goRoom.js +++ b/app/utils/goRoom.js @@ -11,7 +11,7 @@ const navigate = ({ item, isMasterDetail, ...props }) => { navigationMethod('RoomView', { rid: item.roomId || item.rid, name: RocketChat.getRoomTitle(item), - t: item.type ? 'p' : item.t, + t: item?.type ? 'p' : 'c' || item.t, prid: item.prid, room: item, search: item.search, diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 54d70d80b50..2e66869ded3 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -68,10 +68,6 @@ const styles = StyleSheet.create({ }); class CreateChannelView extends React.Component { - static navigationOptions = () => ({ - title: this.isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') - }) - static propTypes = { navigation: PropTypes.object, route: PropTypes.object, @@ -93,14 +89,16 @@ class CreateChannelView extends React.Component { constructor(props) { super(props); const { route } = this.props; - this.isTeam = route?.params?.isTeam || false; + const isTeam = route?.params?.isTeam || false; this.state = { channelName: '', type: true, readOnly: false, encrypted: false, - broadcast: false + broadcast: false, + isTeam }; + this.setTitle(); } shouldComponentUpdate(nextProps, nextState) { @@ -140,6 +138,15 @@ class CreateChannelView extends React.Component { return false; } + setTitle = () => { + const { navigation } = this.props; + const { isTeam } = this.state; + + navigation.setOptions({ + title: isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') + }); + } + toggleRightButton = (channelName) => { const { navigation } = this.props; navigation.setOptions({ @@ -158,7 +165,7 @@ class CreateChannelView extends React.Component { submit = () => { const { - channelName, type, readOnly, broadcast, encrypted + channelName, type, readOnly, broadcast, encrypted, isTeam } = this.state; const { users: usersProps, isFetching, create @@ -173,7 +180,7 @@ class CreateChannelView extends React.Component { // create channel or team create({ - name: channelName, users, type, readOnly, broadcast, encrypted, isTeam: this.isTeam + name: channelName, users, type, readOnly, broadcast, encrypted, isTeam }); Review.pushPositiveEvent(); @@ -204,12 +211,12 @@ class CreateChannelView extends React.Component { } renderType() { - const { type } = this.state; + const { type, isTeam } = this.state; return this.renderSwitch({ id: 'type', value: type, - label: this.isTeam ? 'Private_Team' : 'Private_Channel', + label: isTeam ? 'Private_Team' : 'Private_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_TYPE); // If we set the channel as public, encrypted status should be false @@ -219,12 +226,12 @@ class CreateChannelView extends React.Component { } renderReadOnly() { - const { readOnly, broadcast } = this.state; + const { readOnly, broadcast, isTeam } = this.state; return this.renderSwitch({ id: 'readonly', value: readOnly, - label: this.isTeam ? 'Read_Only_Team' : 'Read_Only_Channel', + label: isTeam ? 'Read_Only_Team' : 'Read_Only_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_READ_ONLY); this.setState({ readOnly: value }); @@ -254,12 +261,12 @@ class CreateChannelView extends React.Component { } renderBroadcast() { - const { broadcast, readOnly } = this.state; + const { broadcast, readOnly, isTeam } = this.state; return this.renderSwitch({ id: 'broadcast', value: broadcast, - label: this.isTeam ? 'Broadcast_Team' : 'Broadcast_Channel', + label: isTeam ? 'Broadcast_Team' : 'Broadcast_Channel', onValueChange: (value) => { logEvent(events.CR_TOGGLE_BROADCAST); this.setState({ @@ -312,7 +319,7 @@ class CreateChannelView extends React.Component { } render() { - const { channelName } = this.state; + const { channelName, isTeam } = this.state; const { users, isFetching, theme } = this.props; @@ -325,18 +332,18 @@ class CreateChannelView extends React.Component { keyboardVerticalOffset={128} > - + - {teamId && joined ? ( + {teamId && teamMain && joined ? ( { const createTeamIfNotExists = async (teamname) => { console.log(`Creating private team ${teamname}`) try { - const team = await rocketchat.post('teams.create', { + await rocketchat.post('teams.create', { "name": teamname, "type": 1 }) - return team } catch (createError) { try { //Maybe it exists already? - const team = rocketchat.get(`teams.info?teamName=${teamname}`) - return team + await rocketchat.get(`teams.info?teamName=${teamname}`) } catch (infoError) { console.log(JSON.stringify(createError)) console.log(JSON.stringify(infoError)) diff --git a/e2e/tests/team/01-createteam.spec.js b/e2e/tests/team/01-createteam.spec.js index 6e06b69f059..4dfe17ca3a2 100644 --- a/e2e/tests/team/01-createteam.spec.js +++ b/e2e/tests/team/01-createteam.spec.js @@ -20,13 +20,13 @@ describe('Create team screen', () => { describe('Render', async() => { it('should have team button', async() => { - await waitFor(element(by.id('new-message-view-create-team'))).toBeVisible().withTimeout(2000); + await waitFor(element(by.id('new-message-view-create-channel'))).toBeVisible().withTimeout(2000); }); }) describe('Usage', async() => { it('should navigate to select users', async() => { - await element(by.id('new-message-view-create-team')).tap(); + await element(by.id('new-message-view-create-channel')).tap(); await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(5000); }); }) @@ -51,22 +51,22 @@ describe('Create team screen', () => { it('should create team', async() => { await element(by.id('selected-users-view-submit')).tap(); - await waitFor(element(by.id('create-team-view'))).toExist().withTimeout(10000); + await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(10000); }); }) describe('Create Team', async() => { describe('Usage', async() => { it('should get invalid team name', async() => { - await element(by.id('create-team-name')).typeText(`${data.teams.private.name}`); + await element(by.id('create-channel-name')).typeText(`${data.teams.private.name}`); await element(by.id('create-channel-submit')).tap(); await element(by.text('OK')).tap(); }); it('should create private team', async() => { const room = `private${ data.random }`; - await element(by.id('create-team-name')).replaceText(''); - await element(by.id('create-team-name')).typeText(room); + await element(by.id('create-channel-name')).replaceText(''); + await element(by.id('create-channel-name')).typeText(room); await element(by.id('create-channel-submit')).tap(); await waitFor(element(by.id('room-view'))).toExist().withTimeout(20000); await expect(element(by.id('room-view'))).toExist(); From 300dacc07f7ab9b5a2877c058d386fd340420fcd Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Tue, 11 May 2021 15:10:48 -0300 Subject: [PATCH 09/14] Fix teams icon --- app/views/NewMessageView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index 5e4ef1c99e5..ae0628f19d7 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -181,7 +181,7 @@ class NewMessageView extends React.Component { {this.renderButton({ onPress: this.createTeam, title: I18n.t('Create_Team'), - icon: 'team', + icon: 'teams', testID: 'new-message-view-create-team' })} {maxUsers > 2 ? this.renderButton({ From da6eb448c8461c191e5446211665fcd37a0c87fe Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Tue, 11 May 2021 15:25:29 -0300 Subject: [PATCH 10/14] Fix RoomView not connecting to messages stream after team is created --- app/lib/methods/loadMessagesForRoom.js | 11 +++-------- app/sagas/createChannel.js | 14 ++++++++++++-- app/utils/goRoom.js | 4 ++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js index df04aa36761..012e1ea3275 100644 --- a/app/lib/methods/loadMessagesForRoom.js +++ b/app/lib/methods/loadMessagesForRoom.js @@ -1,18 +1,13 @@ import log from '../../utils/log'; import updateMessages from './updateMessages'; -async function load({ - rid: roomId, latest, t, team -}) { - let params = { roomId: roomId || team.roomId, count: 50 }; - +async function load({ rid: roomId, latest, t }) { + let params = { roomId, count: 50 }; if (latest) { params = { ...params, latest: new Date(latest).toISOString() }; } - const teamType = team?.type ? 'p' : 'c'; - const apiType = this.roomTypeToApiType(teamType || t); - + const apiType = this.roomTypeToApiType(t); if (!apiType) { return []; } diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index eabe218dff6..f2ecfe76d19 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -82,7 +82,17 @@ const handleRequest = function* handleRequest({ data }) { // do nothing } - yield put(createChannelSuccess(sub)); + let successParams = {}; + if (data.isTeam) { + successParams = { + ...sub.team, + rid: sub.team.roomId, + t: sub.team.type ? 'p' : 'c' + }; + } else { + successParams = data; + } + yield put(createChannelSuccess(successParams)); } catch (err) { logEvent(events[data.group ? 'SELECTED_USERS_CREATE_GROUP_F' : 'CR_CREATE_F']); yield put(createChannelFailure(err)); @@ -94,7 +104,7 @@ const handleSuccess = function* handleSuccess({ data }) { if (isMasterDetail) { Navigation.navigate('DrawerNavigator'); } - goRoom({ item: data.success ? data.team : data, isMasterDetail }); + goRoom({ item: data, isMasterDetail }); }; const handleFailure = function handleFailure({ err }) { diff --git a/app/utils/goRoom.js b/app/utils/goRoom.js index d157cc0b604..94adfde4945 100644 --- a/app/utils/goRoom.js +++ b/app/utils/goRoom.js @@ -9,9 +9,9 @@ const navigate = ({ item, isMasterDetail, ...props }) => { } navigationMethod('RoomView', { - rid: item.roomId || item.rid, + rid: item.rid, name: RocketChat.getRoomTitle(item), - t: item?.type ? 'p' : 'c' || item.t, + t: item.t, prid: item.prid, room: item, search: item.search, From 6c8406d59e7948e344186c955ab47a0ea59841e8 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 11 May 2021 21:03:09 -0400 Subject: [PATCH 11/14] util function, ITeam and minor tweaks --- app/definition/ITeam.js | 4 ++++ app/lib/rocketchat.js | 3 ++- app/lib/utils.js | 2 ++ app/views/CreateChannelView.js | 4 ++-- app/views/RoomView/RightButtons.js | 6 +++--- app/views/RoomView/index.js | 3 ++- app/views/SelectedUsersView.js | 15 +++++++++++---- e2e/helpers/data_setup.js | 3 ++- 8 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 app/definition/ITeam.js diff --git a/app/definition/ITeam.js b/app/definition/ITeam.js new file mode 100644 index 00000000000..88a9782e6cb --- /dev/null +++ b/app/definition/ITeam.js @@ -0,0 +1,4 @@ +export const TEAM_TYPE = { + PUBLIC: 0, + PRIVATE: 1 +}; diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 558dcf9c38f..adc7f80ffe0 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -60,6 +60,7 @@ import UserPreferences from './userPreferences'; import { Encryption } from './encryption'; import EventEmitter from '../utils/events'; import { sanitizeLikeString } from './database/utils'; +import { TEAM_TYPE } from '../definition/ITeam'; const TOKEN_KEY = 'reactnativemeteor_usertoken'; const CURRENT_SERVER = 'currentServer'; @@ -738,7 +739,7 @@ const RocketChat = { const params = { name, users, - type: type ? 1 : 0, + type: type ? TEAM_TYPE.PRIVATE : TEAM_TYPE.PUBLIC, room: { readOnly, extraData: { diff --git a/app/lib/utils.js b/app/lib/utils.js index 769fd6d7670..11d4645de35 100644 --- a/app/lib/utils.js +++ b/app/lib/utils.js @@ -20,3 +20,5 @@ export const methods = { }; export const compareServerVersion = (currentServerVersion, versionToCompare, func) => currentServerVersion && func(coerce(currentServerVersion), versionToCompare); + +export const isTeamRoom = params => params.every(currentValue => currentValue ?? currentValue); diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 2e66869ded3..8090ef4fea0 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -98,7 +98,7 @@ class CreateChannelView extends React.Component { broadcast: false, isTeam }; - this.setTitle(); + this.setHeader(); } shouldComponentUpdate(nextProps, nextState) { @@ -138,7 +138,7 @@ class CreateChannelView extends React.Component { return false; } - setTitle = () => { + setHeader = () => { const { navigation } = this.props; const { isTeam } = this.state; diff --git a/app/views/RoomView/RightButtons.js b/app/views/RoomView/RightButtons.js index 362bba5714f..dd5a3b171f1 100644 --- a/app/views/RoomView/RightButtons.js +++ b/app/views/RoomView/RightButtons.js @@ -7,6 +7,7 @@ import * as HeaderButton from '../../containers/HeaderButton'; import database from '../../lib/database'; import { getUserSelector } from '../../selectors/login'; import { logEvent, events } from '../../utils/log'; +import { isTeamRoom } from '../../lib/utils'; class RightButtonsContainer extends Component { static propTypes = { @@ -16,7 +17,6 @@ class RightButtonsContainer extends Component { t: PropTypes.string, tmid: PropTypes.string, teamId: PropTypes.string, - teamMain: PropTypes.bool, navigation: PropTypes.object, isMasterDetail: PropTypes.bool, toggleFollowThread: PropTypes.func, @@ -165,7 +165,7 @@ class RightButtonsContainer extends Component { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state; const { - t, tmid, threadsEnabled, teamId, teamMain, joined + t, tmid, threadsEnabled, teamId, joined } = this.props; if (t === 'l') { return null; @@ -183,7 +183,7 @@ class RightButtonsContainer extends Component { } return ( - {teamId && teamMain && joined ? ( + {isTeamRoom([teamId, joined]) ? ( ({ length: ITEM_WIDTH, offset: ITEM_WIDTH * index, index }); + class SelectedUsersView extends React.Component { static propTypes = { baseUrl: PropTypes.string, @@ -184,19 +187,23 @@ class SelectedUsersView extends React.Component { ); } + setFlatListRef = ref => this.flatlist = ref; + + onContentSizeChange = () => this.flatlist.scrollToEnd({ animated: true }); + renderSelected = () => { const { users, theme } = this.props; if (users.length === 0) { return null; } - const ITEM_WIDTH = 250; + return ( this.flatlist = ref} - onContentSizeChange={() => this.flatlist.scrollToEnd()} - getItemLayout={(_, index) => ({ length: ITEM_WIDTH, offset: ITEM_WIDTH * index, index })} + ref={this.setFlatListRef} + onContentSizeChange={this.onContentSizeChange} + getItemLayout={_getItemLayout} keyExtractor={item => item._id} style={[sharedStyles.separatorTop, { borderColor: themes[theme].separatorColor }]} contentContainerStyle={{ marginVertical: 5 }} diff --git a/e2e/helpers/data_setup.js b/e2e/helpers/data_setup.js index 5ee266b0ca9..ce1d5083e5a 100644 --- a/e2e/helpers/data_setup.js +++ b/e2e/helpers/data_setup.js @@ -1,5 +1,6 @@ const axios = require('axios').default; const data = require('../data'); +const { TEAM_TYPE } = require('../../app/definition/ITeam'); let server = data.server @@ -62,7 +63,7 @@ const createTeamIfNotExists = async (teamname) => { try { await rocketchat.post('teams.create', { "name": teamname, - "type": 1 + "type": TEAM_TYPE.PRIVATE }) } catch (createError) { try { //Maybe it exists already? From 4bda9badc1249164ddf3f27a5532e54225063d6a Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Wed, 12 May 2021 15:26:40 -0300 Subject: [PATCH 12/14] Comment original file URL --- app/definition/ITeam.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/definition/ITeam.js b/app/definition/ITeam.js index 88a9782e6cb..10919715d17 100644 --- a/app/definition/ITeam.js +++ b/app/definition/ITeam.js @@ -1,3 +1,4 @@ +// https://github.com/RocketChat/Rocket.Chat/blob/develop/definition/ITeam.ts export const TEAM_TYPE = { PUBLIC: 0, PRIVATE: 1 From ebd1f9c94fedbe22e46e7b172927317feb5cddc7 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Wed, 12 May 2021 15:27:41 -0300 Subject: [PATCH 13/14] Make isTeamRoom easier to read and move it to utils/room --- app/lib/utils.js | 2 -- app/utils/room.js | 2 ++ app/views/RoomView/RightButtons.js | 4 ++-- app/views/RoomView/index.js | 7 ++++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/lib/utils.js b/app/lib/utils.js index 11d4645de35..769fd6d7670 100644 --- a/app/lib/utils.js +++ b/app/lib/utils.js @@ -20,5 +20,3 @@ export const methods = { }; export const compareServerVersion = (currentServerVersion, versionToCompare, func) => currentServerVersion && func(coerce(currentServerVersion), versionToCompare); - -export const isTeamRoom = params => params.every(currentValue => currentValue ?? currentValue); diff --git a/app/utils/room.js b/app/utils/room.js index 7077c73dcb5..fef926d5fd1 100644 --- a/app/utils/room.js +++ b/app/utils/room.js @@ -45,3 +45,5 @@ export const getBadgeColor = ({ subscription, messageId, theme }) => { }; export const makeThreadName = messageRecord => messageRecord.msg || messageRecord?.attachments[0]?.title; + +export const isTeamRoom = ({ teamId, joined }) => teamId && joined; diff --git a/app/views/RoomView/RightButtons.js b/app/views/RoomView/RightButtons.js index dd5a3b171f1..81b8f153b0c 100644 --- a/app/views/RoomView/RightButtons.js +++ b/app/views/RoomView/RightButtons.js @@ -7,7 +7,7 @@ import * as HeaderButton from '../../containers/HeaderButton'; import database from '../../lib/database'; import { getUserSelector } from '../../selectors/login'; import { logEvent, events } from '../../utils/log'; -import { isTeamRoom } from '../../lib/utils'; +import { isTeamRoom } from '../../utils/room'; class RightButtonsContainer extends Component { static propTypes = { @@ -183,7 +183,7 @@ class RightButtonsContainer extends Component { } return ( - {isTeamRoom([teamId, joined]) ? ( + {isTeamRoom({ teamId, joined }) ? ( Date: Wed, 12 May 2021 15:57:27 -0300 Subject: [PATCH 14/14] Remove layout animation --- app/views/SelectedUsersView.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/SelectedUsersView.js b/app/views/SelectedUsersView.js index f7f646cfc67..bd6740e1f9f 100644 --- a/app/views/SelectedUsersView.js +++ b/app/views/SelectedUsersView.js @@ -17,7 +17,6 @@ import sharedStyles from './Styles'; import * as HeaderButton from '../containers/HeaderButton'; import StatusBar from '../containers/StatusBar'; import { themes } from '../constants/colors'; -import { animateNextTransition } from '../utils/layoutAnimation'; import { withTheme } from '../theme'; import { getUserSelector } from '../selectors/login'; import { @@ -29,7 +28,7 @@ import { showErrorAlert } from '../utils/info'; import SafeAreaView from '../containers/SafeAreaView'; const ITEM_WIDTH = 250; -const _getItemLayout = (_, index) => ({ length: ITEM_WIDTH, offset: ITEM_WIDTH * index, index }); +const getItemLayout = (_, index) => ({ length: ITEM_WIDTH, offset: ITEM_WIDTH * index, index }); class SelectedUsersView extends React.Component { static propTypes = { @@ -154,7 +153,6 @@ class SelectedUsersView extends React.Component { return; } - animateNextTransition(); if (!this.isChecked(user.name)) { if (this.isGroupChat() && users.length === maxUsers) { return showErrorAlert(I18n.t('Max_number_of_users_allowed_is_number', { maxUsers }), I18n.t('Oops')); @@ -203,7 +201,7 @@ class SelectedUsersView extends React.Component { data={users} ref={this.setFlatListRef} onContentSizeChange={this.onContentSizeChange} - getItemLayout={_getItemLayout} + getItemLayout={getItemLayout} keyExtractor={item => item._id} style={[sharedStyles.separatorTop, { borderColor: themes[theme].separatorColor }]} contentContainerStyle={{ marginVertical: 5 }}