From 2f5f247915efb7377e99b00fb7c3bd10ac1e3950 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 19 Apr 2021 15:21:27 -0400 Subject: [PATCH 01/77] 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 ec289d27d8..a0229ec9a7 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 fc73e375fa..bdff997ae7 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 fc8d704200..2ee2261482 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 9d1e450ff2..7690de270c 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/77] 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 1fd8679bcd..1463500873 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 0000000000..c91cce2d7c --- /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 a0229ec9a7..635a7957bd 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 7690de270c..5674f1d5e7 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 da0efdb427..d8cdc01cb1 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/77] 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 635a7957bd..f621d00a3b 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 bdff997ae7..9dfa39857a 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 0000000000..e962c6315e --- /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 dfee5f3eb9..aaad34fce1 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 0000000000..7da3e03944 --- /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 e499d74ec5..b5787d4244 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 5674f1d5e7..9a300b8afd 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/77] 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 c91cce2d7c..0000000000 --- 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 9dfa39857a..965f1c2114 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 e962c6315e..0000000000 --- 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 aaad34fce1..dfee5f3eb9 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 613aedec2c..eb665a0944 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 7da3e03944..0000000000 --- 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 b5787d4244..e499d74ec5 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 94adfde494..40fba6e973 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 9a300b8afd..59b2ac06ea 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 d8cdc01cb1..8d916e456c 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 79e7842e86..c69b72515b 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 1f8f8fb651..9d0dad492c 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 0000000000..6e06b69f05 --- /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/77] 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 1463500873..1fd8679bcd 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 f621d00a3b..58438f3195 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 012e1ea327..9ab5cf215c 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 eb665a0944..f8e96aeb19 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 40fba6e973..45736e337a 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 f9d14e1690..eb3292bb32 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/77] 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 debc3edb9e..398f868b8a 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/77] 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 59b2ac06ea..54d70d80b5 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 0cf173d7bafc1a4c5be3e514141ec4606cbd025b Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 26 Apr 2021 14:06:22 -0400 Subject: [PATCH 08/77] Added AddChannelTeamView --- app/i18n/locales/en.json | 5 +- app/stacks/InsideStack.js | 6 ++ app/views/AddChannelTeamView.js | 123 ++++++++++++++++++++++++++++++++ app/views/TeamChannelsView.js | 3 +- 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 app/views/AddChannelTeamView.js diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 58438f3195..06e3167ebf 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -716,5 +716,8 @@ "Read_Only_Team": "Read Only Team", "Broadcast_Team": "Broadcast Team", "creating_team" : "creating team", - "team-name-already-exists": "A team with that name already exists" + "team-name-already-exists": "A team with that name already exists", + "Add_Channel_to_Team": "Add Channel to Team", + "Create_New": "Create New", + "Add_Existing": "Add Existing" } diff --git a/app/stacks/InsideStack.js b/app/stacks/InsideStack.js index bda56f0d23..9052b1310e 100644 --- a/app/stacks/InsideStack.js +++ b/app/stacks/InsideStack.js @@ -71,6 +71,7 @@ import ShareView from '../views/ShareView'; import CreateDiscussionView from '../views/CreateDiscussionView'; import QueueListView from '../ee/omnichannel/views/QueueListView'; +import AddChannelTeamView from '../views/AddChannelTeamView'; // ChatsStackNavigator const ChatsStack = createStackNavigator(); @@ -174,6 +175,11 @@ const ChatsStackNavigator = () => { component={TeamChannelsView} options={TeamChannelsView.navigationOptions} /> + { + const { navigation, isMasterDetail, theme } = this.props; + + const options = { + headerShown: true, + headerTitleAlign: 'center', + headerTitle: () => ( + + ) + }; + + if (isMasterDetail) { + options.headerLeft = () => ; + } else { + options.headerLeft = () => ( + navigation.pop()} + tintColor={themes[theme].headerTintColor} + /> + ); + } + + navigation.setOptions(options); + } + + renderButton = ({ + onPress, testID, title, icon, first + }) => { + const { theme } = this.props; + + return ( + onPress()} + style={{ backgroundColor: themes[theme].backgroundColor }} + testID={testID} + theme={theme} + > + + + {title} + + + ); + } + + render() { + const { navigation } = this.props; + + return ( + + + + {this.renderButton({ + onPress: navigation.navigate('NewMessageStackNavigator', { screen: 'CreateChannelView', isTeam: false }), + title: I18n.t('Create_New'), + icon: 'channel-public', + testID: 'add-channel-team-view-create-channel', + first: true + })} + {this.renderButton({ + // onPress: navigation.navigate('AddExistingChannelView'), + title: I18n.t('Add_Existing'), + icon: 'team', + testID: 'add-channel-team-view-create-channel' + })} + + + ); + } +} + +AddChannelTeamView.propTypes = { + route: PropTypes.object, + navigation: PropTypes.object, + isMasterDetail: PropTypes.bool, + theme: PropTypes.string +}; + +export default withDimensions(withTheme(AddChannelTeamView)); diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 15724ab5cb..83c206298d 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -146,7 +146,7 @@ class TeamChannelsView extends React.Component { return; } - const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 }); + const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 2 }); if (isSearching) { return { @@ -201,6 +201,7 @@ class TeamChannelsView extends React.Component { options.headerRight = () => ( + navigation.navigate('AddChannelTeamView')} /> ); return options; From bb0632b6895ac42d76d41e74ddbb8349451a7bba Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 30 Apr 2021 13:09:10 -0400 Subject: [PATCH 09/77] Added permissions, translations strings for teams, deleteTeamRoom and addTeamRooms, AddExistingChannelView, updated CreateChannelView, TeamChannelsView --- .../__snapshots__/Storyshots.test.js.snap | 9776 +++++++++-------- app/i18n/locales/en.json | 5 +- app/lib/methods/getPermissions.js | 7 +- app/lib/rocketchat.js | 18 +- app/presentation/RoomItem/RoomItem.js | 3 + app/presentation/RoomItem/Touchable.js | 21 +- app/presentation/RoomItem/index.js | 7 + app/sagas/createChannel.js | 17 +- app/stacks/InsideStack.js | 6 + app/utils/goRoom.js | 39 +- app/utils/touch.js | 4 +- app/views/AddChannelTeamView.js | 14 +- app/views/AddExistingChannelView.js | 256 + app/views/CreateChannelView.js | 6 +- app/views/RoomView/RightButtons.js | 4 +- app/views/TeamChannelsView.js | 92 +- 16 files changed, 5680 insertions(+), 4595 deletions(-) create mode 100644 app/views/AddExistingChannelView.js diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 52cde22be2..4c88d8e5c9 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -44348,162 +44348,182 @@ exports[`Storyshots Room Item Alerts 1`] = ` } > - + > + + - - - + -  - - - rocket.cat - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + rocket.cat + + @@ -44736,202 +44756,222 @@ exports[`Storyshots Room Item Alerts 1`] = ` } > - - - - - - -  - - - unread - + "bottom": 0, + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + } + } + /> + + + +  + + - 1 + unread + + + 1 + + @@ -45165,202 +45205,222 @@ exports[`Storyshots Room Item Alerts 1`] = ` } > - + > + + - - - + -  - - - unread - - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + - +999 + unread + + + +999 + + @@ -45594,202 +45654,222 @@ exports[`Storyshots Room Item Alerts 1`] = ` } > - - - - - - -  - - - user mentions - + "bottom": 0, + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + } + } + /> + + + - 1 +  + + + user mentions + + + 1 + + @@ -46023,208 +46103,228 @@ exports[`Storyshots Room Item Alerts 1`] = ` } > - - - - - - -  - - - group mentions - + "bottom": 0, + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + } + } + /> + + + - 1 +  - - - - - - + + group mentions + + + + 1 + + + + + + + + - + > + + - - - + -  - - - thread unread - - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + - 1 + thread unread - - - - - - - - + + 1 + + + + + + + + + + - + > + + - - - + -  - - - thread unread user - - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + - 1 + thread unread user - - - - - - - - - + + 1 + + + + + + + + + + + - + > + + - - - + -  - - - thread unread group - - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + - 1 + thread unread group - - - - - - - - + + 1 + + + + + + + + + + - + > + + - - - + -  - - - user mentions priority 1 - - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + - 1 + user mentions priority 1 - - - - - - - - - + + 1 + + + + + + + + + + + - + > + + - - - + -  - - - group mentions priority 2 - - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + - 1 + group mentions priority 2 - - - - - - - - + + 1 + + + + + + + + + + - + > + + - - - + -  - - - thread unread priority 3 - - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + - 1 + thread unread priority 3 - - - - - - - - -`; - -exports[`Storyshots Room Item Basic 1`] = ` - - - - + + 1 + + + + + + + + + + +`; + +exports[`Storyshots Room Item Basic 1`] = ` + + + + - + > + + - - - + -  - - - rocket.cat - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + rocket.cat + + @@ -49435,216 +49675,236 @@ exports[`Storyshots Room Item Last Message 1`] = ` } > - + > + + - - - + -  - - - rocket.cat - - - 10:00 - - - - +  + + + rocket.cat + + + 10:00 + + + - No Message - + + No Message + + @@ -49877,216 +50137,236 @@ exports[`Storyshots Room Item Last Message 1`] = ` } > - - - - - - -  - - - rocket.cat - - - 10:00 - + "bottom": 0, + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + } + } + /> + - + +  + + + rocket.cat + + + 10:00 + + + - 2 - + + 2 + + @@ -50319,216 +50599,236 @@ exports[`Storyshots Room Item Last Message 1`] = ` } > - - - - - - -  - - - rocket.cat - - - 10:00 - + "bottom": 0, + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + } + } + /> + - - You: 1 - + +  + + + rocket.cat + + + 10:00 + + + + + You: 1 + + @@ -50761,216 +51061,236 @@ exports[`Storyshots Room Item Last Message 1`] = ` } > - - - - - - - -  - - + + - rocket.cat - - - 10:00 - + "bottom": 0, + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + } + } + /> + - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - + +  + + + rocket.cat + + + 10:00 + + + + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + @@ -51203,174 +51523,162 @@ exports[`Storyshots Room Item Last Message 1`] = ` } > + + + + + - - - - - - + -  - - - rocket.cat - - +  + + - 10:00 - - - - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - + ] + } + > + rocket.cat + + + 10:00 + + - 1 + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + 1 + + @@ -51701,271 +52041,291 @@ exports[`Storyshots Room Item Last Message 1`] = ` } > - + > + + - - - + +  + + + rocket.cat + + -  - - + 10:00 + + + - rocket.cat - - - 10:00 - - - - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - - - - +999 + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + +999 + + @@ -52199,174 +52559,162 @@ exports[`Storyshots Room Item Last Message 1`] = ` } > - - - - - - -  - - + + + + - rocket.cat - - +  + + - 10:00 - - - - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - + ] + } + > + rocket.cat + + + 10:00 + + - 1 + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + 1 + + @@ -52710,157 +53090,177 @@ exports[`Storyshots Room Item Type 1`] = ` } > - + + /> + - - - + -  - - - rocket.cat - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + rocket.cat + + @@ -53093,145 +53493,165 @@ exports[`Storyshots Room Item Type 1`] = ` } > - + > + + - - - + +  + + -  - - - rocket.cat - + ] + } + > + rocket.cat + + @@ -53464,145 +53884,165 @@ exports[`Storyshots Room Item Type 1`] = ` } > - + > + + - - - -  - - - rocket.cat - + +  + + + rocket.cat + + @@ -53835,145 +54275,165 @@ exports[`Storyshots Room Item Type 1`] = ` } > - - - - - - - -  - - + + + + - rocket.cat - + +  + + + rocket.cat + + @@ -54206,145 +54666,165 @@ exports[`Storyshots Room Item Type 1`] = ` } > - + > + + - - - + +  + + -  - - - rocket.cat - + ] + } + > + rocket.cat + + @@ -54577,145 +55057,165 @@ exports[`Storyshots Room Item Type 1`] = ` } > - + > + + - - - -  - - - rocket.cat - + +  + + + rocket.cat + + @@ -54948,145 +55448,165 @@ exports[`Storyshots Room Item Type 1`] = ` } > - + + /> + - - - -  - - - rocket.cat - + +  + + + rocket.cat + + @@ -55332,157 +55852,177 @@ exports[`Storyshots Room Item User 1`] = ` } > - + > + + - - - + -  - - - diego.mello - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + diego.mello + + @@ -55715,157 +56255,177 @@ exports[`Storyshots Room Item User 1`] = ` } > - + > + + - - - + -  - - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + @@ -56111,157 +56671,177 @@ exports[`Storyshots Room Item User status 1`] = ` } > - - - - - - -  - - + + + + - rocket.cat - + +  + + + rocket.cat + + @@ -56494,157 +57074,177 @@ exports[`Storyshots Room Item User status 1`] = ` } > - - - - - - -  - - + + + + - rocket.cat - + +  + + + rocket.cat + + @@ -56877,157 +57477,177 @@ exports[`Storyshots Room Item User status 1`] = ` } > - + > + + - - - + -  - - - rocket.cat - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + rocket.cat + + @@ -57260,157 +57880,177 @@ exports[`Storyshots Room Item User status 1`] = ` } > - + > + + - - - + -  - - - rocket.cat - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + rocket.cat + + @@ -57643,157 +58283,177 @@ exports[`Storyshots Room Item User status 1`] = ` } > - + > + + - - - + -  - - - rocket.cat - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + rocket.cat + + @@ -58026,157 +58686,177 @@ exports[`Storyshots Room Item User status 1`] = ` } > - + > + + - - - + -  - - - rocket.cat - + Object { + "fontFamily": "custom", + "fontStyle": "normal", + "fontWeight": "normal", + }, + Object {}, + ] + } + > +  + + + rocket.cat + + diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 06e3167ebf..2854728ab9 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -719,5 +719,8 @@ "team-name-already-exists": "A team with that name already exists", "Add_Channel_to_Team": "Add Channel to Team", "Create_New": "Create New", - "Add_Existing": "Add Existing" + "Add_Existing": "Add Existing", + "Add_Existing_Channel": "Add Existing Channel", + "Remove_from_Team": "Remove from Team", + "Auto-join": "Auto-join" } diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index 09b91aa631..1f4bcb9cb1 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -13,6 +13,7 @@ const PERMISSIONS = [ 'add-user-to-any-c-room', 'add-user-to-any-p-room', 'add-user-to-joined-room', + 'add-team-channel', 'archive-room', 'auto-translate', 'create-invite-links', @@ -21,11 +22,13 @@ const PERMISSIONS = [ 'delete-p', 'edit-message', 'edit-room', + 'edit-team-channel', 'force-delete-message', 'mute-user', 'pin-message', 'post-readonly', 'remove-user', + 'remove-team-channel', 'set-leader', 'set-moderator', 'set-owner', @@ -38,7 +41,9 @@ const PERMISSIONS = [ 'view-privileged-setting', 'view-room-administration', 'view-statistics', - 'view-user-administration' + 'view-user-administration', + 'view-all-teams', + 'view-all-team-channels' ]; export async function setPermissions() { diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 965f1c2114..b98ab49582 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -734,7 +734,7 @@ const RocketChat = { const params = { name, users, - type: type ? 1 : 0, + type, room: { readOnly, extraData: { @@ -746,6 +746,22 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.create', params); }, + addTeamRooms({ rooms, teamId }) { + const params = { + rooms: rooms.length ? [...rooms] : [rooms], + teamId + }; + // RC 3.13.0 + return this.post('teams.addRooms', params); + }, + deleteTeamRoom({ rid, teamId }) { + const params = { + roomId: rid, + teamId + }; + // RC 3.13.0 + return this.post('teams.removeRoom', params); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/presentation/RoomItem/RoomItem.js b/app/presentation/RoomItem/RoomItem.js index b3922787b5..6d8c31c202 100644 --- a/app/presentation/RoomItem/RoomItem.js +++ b/app/presentation/RoomItem/RoomItem.js @@ -42,6 +42,7 @@ const RoomItem = ({ testID, swipeEnabled, onPress, + onLongPress, toggleFav, toggleRead, hideChannel, @@ -49,6 +50,7 @@ const RoomItem = ({ }) => ( { + const { rowState } = this.state; + if (rowState !== 0) { + this.close(); + return; + } + const { onLongPress } = this.props; + if (onLongPress) { + onLongPress(); + } + }; + render() { const { testID, isRead, width, favorite, children, theme, isFocused, swipeEnabled @@ -237,8 +249,9 @@ class Touchable extends React.Component { transform: [{ translateX: this.transX }] }} > - {children} - + diff --git a/app/presentation/RoomItem/index.js b/app/presentation/RoomItem/index.js index 80bcf063b1..ee131867d0 100644 --- a/app/presentation/RoomItem/index.js +++ b/app/presentation/RoomItem/index.js @@ -25,6 +25,7 @@ class RoomItemContainer extends React.Component { showLastMessage: PropTypes.bool, id: PropTypes.string, onPress: PropTypes.func, + onLongPress: PropTypes.func, username: PropTypes.string, avatarSize: PropTypes.number, width: PropTypes.number, @@ -112,6 +113,11 @@ class RoomItemContainer extends React.Component { return onPress(item); } + onLongPress = () => { + const { item, onLongPress } = this.props; + return onLongPress(item); + } + render() { const { item, @@ -160,6 +166,7 @@ class RoomItemContainer extends React.Component { isGroupChat={this.isGroupChat} isRead={isRead} onPress={this.onPress} + onLongPress={this.onLongPress} date={date} accessibilityLabel={accessibilityLabel} width={width} diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index f8e96aeb19..5cd1c5d0c4 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -25,6 +25,10 @@ const createTeam = function createTeam(data) { return RocketChat.createTeam(data); }; +const addTeamRoom = function addRoomToTeam(params) { + return RocketChat.addTeamRoom(params); +}; + const handleRequest = function* handleRequest({ data }) { try { const auth = yield select(state => state.login.isAuthenticated); @@ -40,6 +44,7 @@ const handleRequest = function* handleRequest({ data }) { broadcast, encrypted } = data; + // TODO: Create event CT_CREATE logEvent(events.CR_CREATE, { type, readOnly, @@ -67,14 +72,22 @@ const handleRequest = function* handleRequest({ data }) { encrypted }); sub = yield call(createChannel, data); - } + if (data.teamId) { + // TODO: Log when adding room to team + const channels = yield call(addTeamRoom, { rooms: sub.rid, teamId: data.teamId }); + if (channels.success) { + sub.teamId = channels.teamId; + sub.isTeamChannel = true; + } + } + } try { const db = database.active; const subCollection = db.get('subscriptions'); yield db.action(async() => { await subCollection.create((s) => { - s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.rid }, subCollection.schema); + s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.rid, team_id: sub.teamId }, subCollection.schema); Object.assign(s, sub); }); }); diff --git a/app/stacks/InsideStack.js b/app/stacks/InsideStack.js index 9052b1310e..75758960b1 100644 --- a/app/stacks/InsideStack.js +++ b/app/stacks/InsideStack.js @@ -72,6 +72,7 @@ import CreateDiscussionView from '../views/CreateDiscussionView'; import QueueListView from '../ee/omnichannel/views/QueueListView'; import AddChannelTeamView from '../views/AddChannelTeamView'; +import AddExistingChannelView from '../views/AddExistingChannelView'; // ChatsStackNavigator const ChatsStack = createStackNavigator(); @@ -180,6 +181,11 @@ const ChatsStackNavigator = () => { component={AddChannelTeamView} options={AddChannelTeamView.navigationOptions} /> + { navigationMethod = Navigation.replace; } - 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 - }); + if (item.isTeamChannel) { + // TODO: Refactor + Navigation.navigate('TeamChannelsView'); + Navigation.push('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), + teamId: item.teamId, + ...props + }); + } else { + 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/utils/touch.js b/app/utils/touch.js index d5c22d4df1..ae9d01bb09 100644 --- a/app/utils/touch.js +++ b/app/utils/touch.js @@ -15,13 +15,14 @@ class Touch extends React.Component { render() { const { - children, onPress, theme, underlayColor, ...props + children, onPress, onLongPress, theme, underlayColor, ...props } = this.props; return ( ( - - ) + headerTitle: I18n.t('Add_Channel_to_Team') }; if (isMasterDetail) { @@ -74,7 +71,7 @@ class AddChannelTeamView extends React.Component { return ( onPress()} + onPress={onPress} style={{ backgroundColor: themes[theme].backgroundColor }} testID={testID} theme={theme} @@ -88,21 +85,22 @@ class AddChannelTeamView extends React.Component { } render() { - const { navigation } = this.props; + const { navigation, route } = this.props; + const { teamChannels } = route?.params; return ( {this.renderButton({ - onPress: navigation.navigate('NewMessageStackNavigator', { screen: 'CreateChannelView', isTeam: false }), + onPress: () => navigation.navigate('NewMessageStackNavigator', { screen: 'SelectedUsersViewCreateChannel', params: { nextAction: () => navigation.navigate('CreateChannelView', { teamId: this.teamId }) } }), title: I18n.t('Create_New'), icon: 'channel-public', testID: 'add-channel-team-view-create-channel', first: true })} {this.renderButton({ - // onPress: navigation.navigate('AddExistingChannelView'), + onPress: () => navigation.navigate('AddExistingChannelView', { teamId: this.teamId, teamChannels }), title: I18n.t('Add_Existing'), icon: 'team', testID: 'add-channel-team-view-create-channel' diff --git a/app/views/AddExistingChannelView.js b/app/views/AddExistingChannelView.js new file mode 100644 index 0000000000..d8c4da808f --- /dev/null +++ b/app/views/AddExistingChannelView.js @@ -0,0 +1,256 @@ +/* eslint-disable no-mixed-spaces-and-tabs */ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + View, StyleSheet, FlatList, Text +} from 'react-native'; +import { connect } from 'react-redux'; +import { Q } from '@nozbe/watermelondb'; +import { HeaderBackButton } from '@react-navigation/stack'; +import * as List from '../containers/List'; + +import Touch from '../utils/touch'; +import database from '../lib/database'; +import RocketChat from '../lib/rocketchat'; +import sharedStyles from './Styles'; +import I18n from '../i18n'; +import log from '../utils/log'; +import SearchBox from '../containers/SearchBox'; +import { CustomIcon } from '../lib/Icons'; +import * as HeaderButton from '../containers/HeaderButton'; +import StatusBar from '../containers/StatusBar'; +import { themes } from '../constants/colors'; +import { withTheme } from '../theme'; +import SafeAreaView from '../containers/SafeAreaView'; +import { animateNextTransition } from '../utils/layoutAnimation'; +import { goRoom } from '../utils/goRoom'; +import Loading from '../containers/Loading'; + +const QUERY_SIZE = 15; + +const styles = StyleSheet.create({ + button: { + height: 46, + flexDirection: 'row', + alignItems: 'center' + }, + buttonIcon: { + marginLeft: 18, + marginRight: 16 + }, + buttonText: { + fontSize: 17, + ...sharedStyles.textRegular + }, + textContainer: { + flex: 1, + flexDirection: 'column', + justifyContent: 'center', + marginRight: 15 + }, + icon: { + marginHorizontal: 15, + alignSelf: 'center' + } +}); + +class AddExistingChannelView extends React.Component { + static propTypes = { + navigation: PropTypes.object, + route: PropTypes.object, + user: PropTypes.shape({ + id: PropTypes.string, + token: PropTypes.string + }), + theme: PropTypes.string, + isMasterDetail: PropTypes.bool + }; + + constructor(props) { + super(props); + this.init(); + this.teamId = props.route?.params?.teamId; + this.state = { + search: [], + channels: [], + selected: [], + loading: false + }; + this.setHeader(); + } + + setHeader = () => { + const { navigation, isMasterDetail, theme } = this.props; + const { selected } = this.state; + + const options = { + headerShown: true, + headerTitleAlign: 'center', + headerTitle: I18n.t('Add_Existing_Channel') + }; + + if (isMasterDetail) { + options.headerLeft = () => ; + } else { + options.headerLeft = () => navigation.pop()} tintColor={themes[theme].headerTintColor} />; + } + + options.headerRight = () => selected.length > 0 && ( + + + + ); + + navigation.setOptions(options); + } + + // eslint-disable-next-line react/sort-comp + init = async() => { + try { + const db = database.active; + const channels = await db.collections + .get('subscriptions') + .query( + Q.where('t', 'p'), + Q.where('team_id', ''), + Q.experimentalTake(QUERY_SIZE), + Q.experimentalSortBy('room_updated_at', Q.desc) + ) + .fetch(); + this.setState({ channels }); + } catch (e) { + log(e); + } + } + + onSearchChangeText(text) { + this.search(text); + } + + dismiss = () => { + const { navigation } = this.props; + return navigation.pop(); + } + + search = async(text) => { + const result = await RocketChat.search({ text, filterUsers: false }); + this.setState({ + search: result + }); + } + + submit = async() => { + const { selected } = this.state; + const { isMasterDetail } = this.props; + + this.setState({ loading: true }); + try { + // TODO: Log request + const result = await RocketChat.addTeamRooms({ rooms: selected, teamId: this.teamId }); + if (result.success) { + this.setState({ loading: false }); + goRoom(result, isMasterDetail); + } + } catch (e) { + // TODO: Log error + this.setState({ loading: false }); + } + } + + renderChannel = ({ + onPress, testID, title, icon, checked + }) => { + const { theme } = this.props; + return ( + + + + + {title} + + {checked ? : null} + + + ); + } + + renderHeader = () => { + const { theme } = this.props; + return ( + + this.onSearchChangeText(text)} testID='add-existing-channel-view-search' /> + + ); + } + + isChecked = (rid) => { + const { selected } = this.state; + return selected.includes(rid); + } + + toggleChannel = (rid) => { + const { selected } = this.state; + + animateNextTransition(); + if (!this.isChecked(rid)) { + // logEvent(events.SELECTED_USERS_ADD_USER); + this.setState({ selected: [...selected, rid] }, () => this.setHeader()); + } else { + // logEvent(events.SELECTED_USERS_REMOVE_USER); + const filterSelected = selected.filter(el => el !== rid); + this.setState({ selected: filterSelected }, () => this.setHeader()); + } + } + + renderItem = ({ item }) => ( + <> + {this.renderChannel({ + onPress: () => this.toggleChannel(item.rid), + title: item.name, + icon: item.t === 'p' && !item.teamId ? 'channel-private' : 'channel-public', + checked: this.isChecked(item.rid) ? 'check' : null, + testID: 'add-existing-channel-view-item' + })} + + ) + + renderList = () => { + const { search, channels } = this.state; + const { theme } = this.props; + return ( + 0 ? search : channels} + extraData={this.state} + keyExtractor={item => item._id} + ListHeaderComponent={this.renderHeader} + renderItem={this.renderItem} + ItemSeparatorComponent={List.Separator} + contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} + keyboardShouldPersistTaps='always' + /> + ); + } + + render() { + const { loading } = this.state; + + return ( + + + {this.renderList()} + + + ); + } +} + +const mapStateToProps = state => ({ + isMasterDetail: state.app.isMasterDetail +}); + +export default connect(mapStateToProps, null)(withTheme(AddExistingChannelView)); diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 54d70d80b5..de2804c339 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -87,13 +87,15 @@ class CreateChannelView extends React.Component { id: PropTypes.string, token: PropTypes.string }), - theme: PropTypes.string + theme: PropTypes.string, + teamId: PropTypes.string }; constructor(props) { super(props); const { route } = this.props; this.isTeam = route?.params?.isTeam || false; + this.teamId = route?.params?.teamId; this.state = { channelName: '', type: true, @@ -173,7 +175,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: this.isTeam, teamId: this.teamId }); Review.pushPositiveEvent(); diff --git a/app/views/RoomView/RightButtons.js b/app/views/RoomView/RightButtons.js index 398f868b8a..c2c1a43ae3 100644 --- a/app/views/RoomView/RightButtons.js +++ b/app/views/RoomView/RightButtons.js @@ -114,7 +114,7 @@ class RightButtonsContainer extends Component { goTeamChannels = () => { logEvent(events.ROOM_GO_TEAM_CHANNELS); const { - navigation, isMasterDetail, teamId + navigation, isMasterDetail, teamId, rid } = this.props; if (isMasterDetail) { navigation.navigate('ModalStackNavigator', { @@ -122,7 +122,7 @@ class RightButtonsContainer extends Component { params: { teamId } }); } else { - navigation.navigate('TeamChannelsView', { teamId }); + navigation.navigate('TeamChannelsView', { teamId, rid }); } } diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 83c206298d..4fa8bb2c09 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -1,5 +1,5 @@ import React from 'react'; -import { Keyboard } from 'react-native'; +import { Keyboard, Alert } from 'react-native'; import PropTypes from 'prop-types'; import { Q } from '@nozbe/watermelondb'; import { withSafeAreaInsets } from 'react-native-safe-area-context'; @@ -28,6 +28,8 @@ import debounce from '../utils/debounce'; import { showErrorAlert } from '../utils/info'; import { goRoom } from '../utils/goRoom'; import I18n from '../i18n'; +import { withActionSheet } from '../containers/ActionSheet'; +import { deleteRoom as deleteRoomAction } from '../actions/room'; const API_FETCH_COUNT = 25; @@ -47,12 +49,16 @@ class TeamChannelsView extends React.Component { theme: PropTypes.string, useRealName: PropTypes.bool, width: PropTypes.number, - StoreLastMessage: PropTypes.bool + StoreLastMessage: PropTypes.bool, + addTeamChannelPermission: PropTypes.array, + showActionSheet: PropTypes.func, + deleteRoom: PropTypes.func } constructor(props) { super(props); this.teamId = props.route.params?.teamId; + this.rid = props.route.params?.rid; this.state = { loading: true, loadingMore: false, @@ -60,9 +66,11 @@ class TeamChannelsView extends React.Component { isSearching: false, searchText: '', search: [], - end: false + end: false, + showCreate: false }; this.loadTeam(); + this.setHeader(); } componentDidMount() { @@ -70,6 +78,7 @@ class TeamChannelsView extends React.Component { } loadTeam = async() => { + const { addTeamChannelPermission } = this.props; const db = database.active; try { const subCollection = db.get('subscriptions'); @@ -82,6 +91,11 @@ class TeamChannelsView extends React.Component { if (!this.team) { throw new Error(); } + + const permissions = await RocketChat.hasPermission([addTeamChannelPermission], this.team.rid); + if (permissions[0]) { + this.setState({ showCreate: true }, () => this.setHeader()); + } } catch { const { navigation } = this.props; navigation.pop(); @@ -135,8 +149,8 @@ class TeamChannelsView extends React.Component { } }, 300) - getHeader = () => { - const { isSearching } = this.state; + setHeader = () => { + const { isSearching, showCreate, data } = this.state; const { navigation, isMasterDetail, insets, theme } = this.props; @@ -201,15 +215,11 @@ class TeamChannelsView extends React.Component { options.headerRight = () => ( - navigation.navigate('AddChannelTeamView')} /> + { showCreate + ? navigation.navigate('AddChannelTeamView', { teamId: this.teamId, teamChannels: data })} /> + : null} ); - return options; - } - - setHeader = () => { - const { navigation } = this.props; - const options = this.getHeader(); navigation.setOptions(options); } @@ -288,6 +298,54 @@ class TeamChannelsView extends React.Component { } }, 1000, true); + options = item => ([ + { + title: I18n.t('Auto-join'), + icon: item.t === 'p' ? 'channel-private' : 'channel-public' + // onPress: this.autoJoin + }, + { + title: I18n.t('Remove_from_Team'), + icon: 'close', + danger: true, + onPress: this.removeFromTeam(item.id, this.teamId) + }, + { + title: I18n.t('Delete'), + icon: 'delete', + danger: true, + onPress: this.delete + } + ]) + + delete = () => { + const { room } = this.state; + const { deleteRoom } = this.props; + + Alert.alert( + I18n.t('Are_you_sure_question_mark'), + I18n.t('Delete_Room_Warning'), + [ + { + text: I18n.t('Cancel'), + style: 'cancel' + }, + { + text: I18n.t('Yes_action_it', { action: I18n.t('delete') }), + style: 'destructive', + onPress: () => deleteRoom(room.rid, room.t) + } + ], + { cancelable: false } + ); + } + + showChannelActions = (item) => { + logEvent(events.ROOM_SHOW_BOX_ACTIONS); + const { showActionSheet } = this.props; + showActionSheet({ options: this.options(item) }); + } + renderItem = ({ item }) => { const { StoreLastMessage, @@ -303,6 +361,7 @@ class TeamChannelsView extends React.Component { showLastMessage={StoreLastMessage} onPress={this.onPressItem} width={width} + onLongPress={this.showChannelActions} useRealName={useRealName} getRoomTitle={this.getRoomTitle} getRoomAvatar={this.getRoomAvatar} @@ -366,7 +425,12 @@ const mapStateToProps = state => ({ user: getUserSelector(state), useRealName: state.settings.UI_Use_Real_Name, isMasterDetail: state.app.isMasterDetail, - StoreLastMessage: state.settings.Store_Last_Message + StoreLastMessage: state.settings.Store_Last_Message, + addTeamChannelPermission: state.permissions['add-team-channel'] +}); + +const mapDispatchToProps = dispatch => ({ + deleteRoom: (rid, t) => dispatch(deleteRoomAction(rid, t)) }); -export default connect(mapStateToProps)(withDimensions(withSafeAreaInsets(withTheme(TeamChannelsView)))); +export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withSafeAreaInsets(withTheme(withActionSheet(TeamChannelsView))))); From c3ffa37323397550aad118362d8f102f5fa40287 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 4 May 2021 14:02:01 -0400 Subject: [PATCH 10/77] Refactor touch component and update removeRoom and deleteRoom methods --- .../__snapshots__/Storyshots.test.js.snap | 6372 +++++++++-------- app/containers/List/ListItem.js | 3 +- app/i18n/locales/en.json | 4 +- app/lib/rocketchat.js | 8 +- app/presentation/RoomItem/RoomItem.js | 3 - app/presentation/RoomItem/Touchable.js | 14 +- app/presentation/RoomItem/index.js | 4 - app/utils/touch.js | 14 +- app/views/AddChannelTeamView.js | 1 - app/views/NewMessageView.js | 1 - app/views/RoomsListView/index.js | 7 +- app/views/TeamChannelsView.js | 68 +- 12 files changed, 3517 insertions(+), 2982 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 4c88d8e5c9..f99bbe10df 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -4154,49 +4154,72 @@ exports[`Storyshots List pressable 1`] = ` } /> - - Press me - + + Press me + + - - I'm disabled - + + I'm disabled + + - -  - + +  + + - - - - Chats - - - All - - - + Chats + + -  + All + + + +  + + + - -  - + +  + + - - - - Chats - - - All - - - -  + Chats - - - - + All + + + + + +  + + + + + + - -  - + +  + + - - - - Chats - - - All - - - + Chats + + -  + All + + + +  + + + - -  - + +  + + - - - - Chats - - - All - - - + Chats + + -  + All + + + +  + + + - -  - + +  + + - - - - Chats - - - All - - - -  + Chats + + All + + + + + +  + + @@ -6509,149 +6670,172 @@ exports[`Storyshots List with black theme 1`] = ` } /> - -  - + +  + + - - - - Chats - - - All - - - -  + Chats + + All + + + + + +  + + @@ -6745,147 +6929,170 @@ exports[`Storyshots List with black theme 1`] = ` } /> - -  - + +  + + - - - - Chats - - - All - - - -  + Chats + + All + + + + + +  + + @@ -6903,149 +7110,172 @@ exports[`Storyshots List with black theme 1`] = ` } /> + + +  + + + + + Chats + + -  + All - - - - Chats - - - All - - - - -  - + +  + + @@ -7193,49 +7423,73 @@ exports[`Storyshots List with custom colors 1`] = ` } /> - - Press me! - + + Press me! + + - -  - + +  + + - - - - Chats - - - All - - - -  + Chats + + All + + + + + +  + + @@ -7498,149 +7775,172 @@ exports[`Storyshots List with dark theme 1`] = ` } /> + + +  + + + + + Chats + + -  + All - - - - Chats - - - All - - - - -  - + +  + + @@ -7734,148 +8034,171 @@ exports[`Storyshots List with dark theme 1`] = ` } /> - -  - + +  + + - - - - Chats - - - All - - - + Chats + + -  + All + + + +  + + + - -  - + +  + + - - - - Chats - - - All - - - + Chats + + -  + All + + + +  + + + - -  - + +  + + - - - - Chats - - - All - - - + Chats + + -  + All + + + +  + + + + + +  + + + + + Chats + + -  + All - - - - Chats - - - All - - - - -  - + +  + + @@ -9855,148 +10247,171 @@ exports[`Storyshots List with small font 1`] = ` } /> - -  - + +  + + - - - - Chats - - - All - - - + Chats + + -  + All + + + +  + + + - -  - + +  + + - - - - Chats - - - All - - - + Chats + + -  + All + + + +  + + + + + + + + + + + + +  + + + rocket.cat + + + + + + + + + + + + +  + + + Read + + + + + + + +  + + + Favorite + + + + +  + + + Hide + + + + + - - - - - - - - - -  - - - rocket.cat - - - - - - - - - - - - -  - - - Read - - - - - - - -  - - - Favorite - - - - -  - - - Hide - - - - - + + + + + + + + + +  + + + rocket.cat + + + + + + + + + +`; + +exports[`Storyshots Room Item Last Message 1`] = ` + + + + + + + +  + + + Read + + + + + + + +  + + + Favorite + + + + +  + + + Hide + + + + + rocket.cat + + 10:00 + + + + + No Message + - - -`; - -exports[`Storyshots Room Item Last Message 1`] = ` - - - No Message + 2 @@ -50138,6 +51066,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` > - 2 + You: 1 @@ -50600,6 +51530,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` > - You: 1 + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries @@ -51062,6 +51994,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` > @@ -51283,13 +52232,54 @@ exports[`Storyshots Room Item Last Message 1`] = ` "textAlign": "left", }, Object { - "color": "#9ca2a8", + "color": "#2f343d", }, ] } > Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + 1 + + @@ -51524,6 +52514,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` > - 1 + +999 @@ -52042,6 +53034,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` > - +999 + 1 @@ -52332,6 +53326,19 @@ exports[`Storyshots Room Item Last Message 1`] = ` + + +`; + +exports[`Storyshots Room Item Type 1`] = ` + + rocket.cat - - 10:00 - - - - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - - - - 1 - - - - -`; - -exports[`Storyshots Room Item Type 1`] = ` - - -  +  -  +  -  +  -  +  -  +  -  +  + + +`; + +exports[`Storyshots Room Item User 1`] = ` + + -  +  - rocket.cat + diego.mello @@ -55612,19 +56520,6 @@ exports[`Storyshots Room Item Type 1`] = ` - - -`; - -exports[`Storyshots Room Item User 1`] = ` - - - diego.mello + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries @@ -56028,6 +56925,19 @@ exports[`Storyshots Room Item User 1`] = ` + + +`; + +exports[`Storyshots Room Item User status 1`] = ` + + -  +  - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + rocket.cat @@ -56431,19 +57343,6 @@ exports[`Storyshots Room Item User 1`] = ` - - -`; - -exports[`Storyshots Room Item User status 1`] = ` - - -  +  -  +  - - - - - - - - - -  - - - rocket.cat - - - - - - - - - - - - -  - - - Read - - - - - - - -  - - - Favorite - - - - -  - - - Hide - - - - - ( onPress(props.title)} - style={{ backgroundColor: backgroundColor || themes[props.theme].backgroundColor }} underlayColor={underlayColor} enabled={!props.disabled} theme={props.theme} diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 2854728ab9..08532be5e1 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -722,5 +722,7 @@ "Add_Existing": "Add Existing", "Add_Existing_Channel": "Add Existing Channel", "Remove_from_Team": "Remove from Team", - "Auto-join": "Auto-join" + "Auto-join": "Auto-join", + "Delete_Team_Room_Warning": "Woud you like to remove this channel from the team? The channel will be moved back to the workspace", + "Confirmation": "Confirmation" } diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index b98ab49582..d9cfbc2013 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -754,13 +754,9 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.addRooms', params); }, - deleteTeamRoom({ rid, teamId }) { - const params = { - roomId: rid, - teamId - }; + removeTeamRoom({ roomId, teamId }) { // RC 3.13.0 - return this.post('teams.removeRoom', params); + return this.post('teams.removeRoom', { roomId, teamId }); }, joinRoom(roomId, joinCode, type) { // TODO: join code diff --git a/app/presentation/RoomItem/RoomItem.js b/app/presentation/RoomItem/RoomItem.js index 6d8c31c202..bfbce938e8 100644 --- a/app/presentation/RoomItem/RoomItem.js +++ b/app/presentation/RoomItem/RoomItem.js @@ -24,7 +24,6 @@ const RoomItem = ({ status, useRealName, theme, - isFocused, isGroupChat, isRead, date, @@ -61,7 +60,6 @@ const RoomItem = ({ testID={testID} type={type} theme={theme} - isFocused={isFocused} swipeEnabled={swipeEnabled} > - {children} - + diff --git a/app/presentation/RoomItem/index.js b/app/presentation/RoomItem/index.js index ee131867d0..2815db35d4 100644 --- a/app/presentation/RoomItem/index.js +++ b/app/presentation/RoomItem/index.js @@ -14,7 +14,6 @@ const attrs = [ 'status', 'connected', 'theme', - 'isFocused', 'forceUpdate', 'showLastMessage' ]; @@ -37,7 +36,6 @@ class RoomItemContainer extends React.Component { getUserPresence: PropTypes.func, connected: PropTypes.bool, theme: PropTypes.string, - isFocused: PropTypes.bool, getRoomTitle: PropTypes.func, getRoomAvatar: PropTypes.func, getIsGroupChat: PropTypes.func, @@ -129,7 +127,6 @@ class RoomItemContainer extends React.Component { toggleRead, hideChannel, theme, - isFocused, avatarSize, status, showLastMessage, @@ -178,7 +175,6 @@ class RoomItemContainer extends React.Component { testID={testID} type={item.t} theme={theme} - isFocused={isFocused} size={avatarSize} prid={item.prid} status={status} diff --git a/app/utils/touch.js b/app/utils/touch.js index ae9d01bb09..f7dc6c8669 100644 --- a/app/utils/touch.js +++ b/app/utils/touch.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { RectButton } from 'react-native-gesture-handler'; +import { Pressable } from 'react-native'; import { themes } from '../constants/colors'; class Touch extends React.Component { @@ -15,21 +15,23 @@ class Touch extends React.Component { render() { const { - children, onPress, onLongPress, theme, underlayColor, ...props + children, onPress, onLongPress, theme, ...props } = this.props; return ( - [{ + backgroundColor: pressed ? themes[theme].chatComponentBackground : themes[theme].backgroundColor + }]} + android_ripple={{ color: themes[theme].bannerBackground }} {...props} > {children} - + ); } } diff --git a/app/views/AddChannelTeamView.js b/app/views/AddChannelTeamView.js index 4d3cf20158..27cf6646ab 100644 --- a/app/views/AddChannelTeamView.js +++ b/app/views/AddChannelTeamView.js @@ -72,7 +72,6 @@ class AddChannelTeamView extends React.Component { return ( diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index 5e4ef1c99e..66ea00482d 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -148,7 +148,6 @@ class NewMessageView extends React.Component { return ( diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 19df2c3b0f..0daf85dc7b 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -586,10 +586,7 @@ class RoomsListView extends React.Component { } onPressItem = (item = {}) => { - const { navigation, isMasterDetail } = this.props; - if (!navigation.isFocused()) { - return; - } + const { isMasterDetail } = this.props; this.cancelSearch(); this.goRoom({ item, isMasterDetail }); @@ -894,7 +891,6 @@ class RoomsListView extends React.Component { return this.renderSectionHeader(item.rid); } - const { item: currentItem } = this.state; const { user: { username }, StoreLastMessage, @@ -925,7 +921,6 @@ class RoomsListView extends React.Component { getIsGroupChat={this.isGroupChat} getIsRead={this.isRead} visitor={item.visitor} - isFocused={currentItem?.rid === item.rid} /> ); }; diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 4fa8bb2c09..129980881e 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -51,6 +51,7 @@ class TeamChannelsView extends React.Component { width: PropTypes.number, StoreLastMessage: PropTypes.bool, addTeamChannelPermission: PropTypes.array, + removeTeamChannelPermission: PropTypes.array, showActionSheet: PropTypes.func, deleteRoom: PropTypes.func } @@ -79,6 +80,8 @@ class TeamChannelsView extends React.Component { loadTeam = async() => { const { addTeamChannelPermission } = this.props; + const { loading } = this.state; + const db = database.active; try { const subCollection = db.get('subscriptions'); @@ -96,6 +99,9 @@ class TeamChannelsView extends React.Component { if (permissions[0]) { this.setState({ showCreate: true }, () => this.setHeader()); } + if (loading) { + this.setState({ loading: false }); + } } catch { const { navigation } = this.props; navigation.pop(); @@ -103,7 +109,7 @@ class TeamChannelsView extends React.Component { } } - load = debounce(async() => { + load = async() => { const { loadingMore, data, search, isSearching, searchText, end } = this.state; @@ -147,7 +153,7 @@ class TeamChannelsView extends React.Component { log(e); this.setState({ loading: false, loadingMore: false }); } - }, 300) + } setHeader = () => { const { isSearching, showCreate, data } = this.state; @@ -308,18 +314,54 @@ class TeamChannelsView extends React.Component { title: I18n.t('Remove_from_Team'), icon: 'close', danger: true, - onPress: this.removeFromTeam(item.id, this.teamId) + onPress: () => this.remove(item) }, { title: I18n.t('Delete'), icon: 'delete', danger: true, - onPress: this.delete + onPress: () => this.delete(item) } ]) - delete = () => { - const { room } = this.state; + remove = (item) => { + Alert.alert( + I18n.t('Confirmation'), + I18n.t('Delete_Team_Room_Warning'), + [ + { + text: I18n.t('Cancel'), + style: 'cancel' + }, + { + text: I18n.t('Yes_action_it', { action: I18n.t('delete') }), + style: 'destructive', + onPress: () => this.removeRoom(item) + } + ], + { cancelable: false } + ); + } + + removeRoom = async(item) => { + try { + const { data } = this.state; + const result = await RocketChat.removeTeamRoom({ roomId: item.rid, teamId: this.team.teamId }); + if (result.success) { + console.log({ result }); + const newData = data.filter(room => result.room._id !== room.rid); + console.log({ newData }); + this.setState({ loading: true, data: newData }, () => { + this.loadTeam(); + this.load(); + }); + } + } catch (e) { + log(e); + } + } + + delete = (item) => { const { deleteRoom } = this.props; Alert.alert( @@ -333,16 +375,21 @@ class TeamChannelsView extends React.Component { { text: I18n.t('Yes_action_it', { action: I18n.t('delete') }), style: 'destructive', - onPress: () => deleteRoom(room.rid, room.t) + onPress: () => deleteRoom(item.rid, item.t) } ], { cancelable: false } ); } - showChannelActions = (item) => { + showChannelActions = async(item) => { logEvent(events.ROOM_SHOW_BOX_ACTIONS); - const { showActionSheet } = this.props; + const { showActionSheet, removeTeamChannelPermission } = this.props; + + const permissions = await RocketChat.hasPermission([removeTeamChannelPermission], this.team.rid); + if (!permissions[0]) { + return; + } showActionSheet({ options: this.options(item) }); } @@ -426,7 +473,8 @@ const mapStateToProps = state => ({ useRealName: state.settings.UI_Use_Real_Name, isMasterDetail: state.app.isMasterDetail, StoreLastMessage: state.settings.Store_Last_Message, - addTeamChannelPermission: state.permissions['add-team-channel'] + addTeamChannelPermission: state.permissions['add-team-channel'], + removeTeamChannelPermission: state.permissions['remove-team-channel'] }); const mapDispatchToProps = dispatch => ({ From 69ae24732908083925358429a5f4f39d88c520b9 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 5 May 2021 02:37:57 -0400 Subject: [PATCH 11/77] Minor tweaks --- app/sagas/createChannel.js | 3 +-- app/utils/goRoom.js | 2 +- app/views/AddExistingChannelView.js | 2 +- app/views/RoomsListView/index.js | 5 ++++- app/views/TeamChannelsView.js | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index 5cd1c5d0c4..a642cbf890 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -26,7 +26,7 @@ const createTeam = function createTeam(data) { }; const addTeamRoom = function addRoomToTeam(params) { - return RocketChat.addTeamRoom(params); + return RocketChat.addTeamRooms(params); }; const handleRequest = function* handleRequest({ data }) { @@ -78,7 +78,6 @@ const handleRequest = function* handleRequest({ data }) { const channels = yield call(addTeamRoom, { rooms: sub.rid, teamId: data.teamId }); if (channels.success) { sub.teamId = channels.teamId; - sub.isTeamChannel = true; } } } diff --git a/app/utils/goRoom.js b/app/utils/goRoom.js index b2590e5d36..1a421e5549 100644 --- a/app/utils/goRoom.js +++ b/app/utils/goRoom.js @@ -8,7 +8,7 @@ const navigate = ({ item, isMasterDetail, ...props }) => { navigationMethod = Navigation.replace; } - if (item.isTeamChannel) { + if (item.rooms && item.teamId) { // TODO: Refactor Navigation.navigate('TeamChannelsView'); Navigation.push('RoomView', { diff --git a/app/views/AddExistingChannelView.js b/app/views/AddExistingChannelView.js index d8c4da808f..c299930578 100644 --- a/app/views/AddExistingChannelView.js +++ b/app/views/AddExistingChannelView.js @@ -149,7 +149,7 @@ class AddExistingChannelView extends React.Component { const result = await RocketChat.addTeamRooms({ rooms: selected, teamId: this.teamId }); if (result.success) { this.setState({ loading: false }); - goRoom(result, isMasterDetail); + goRoom({ result, isMasterDetail }); } } catch (e) { // TODO: Log error diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 0daf85dc7b..662a82e99f 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -586,7 +586,10 @@ class RoomsListView extends React.Component { } onPressItem = (item = {}) => { - const { isMasterDetail } = this.props; + const { navigation, isMasterDetail } = this.props; + if (!navigation.isFocused()) { + return; + } this.cancelSearch(); this.goRoom({ item, isMasterDetail }); diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 129980881e..b329cacc03 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -109,7 +109,7 @@ class TeamChannelsView extends React.Component { } } - load = async() => { + load = debounce(async() => { const { loadingMore, data, search, isSearching, searchText, end } = this.state; @@ -153,7 +153,7 @@ class TeamChannelsView extends React.Component { log(e); this.setState({ loading: false, loadingMore: false }); } - } + }, 300) setHeader = () => { const { isSearching, showCreate, data } = this.state; From 4761e21de85e8ff56cb6348766449778608977f1 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 5 May 2021 03:46:18 -0400 Subject: [PATCH 12/77] Minor tweaks for removing channels and addExistingChannelView --- app/i18n/locales/en.json | 4 +++- app/lib/methods/loadMessagesForRoom.js | 2 +- app/lib/rocketchat.js | 2 +- app/sagas/createChannel.js | 3 ++- app/utils/goRoom.js | 4 +++- app/views/AddExistingChannelView.js | 2 +- app/views/TeamChannelsView.js | 6 ++---- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 08532be5e1..0ef3e03c49 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -435,6 +435,7 @@ "Review_app_unable_store": "Unable to open {{store}}", "Review_this_app": "Review this app", "Remove": "Remove", + "remove": "remove", "Roles": "Roles", "Room_actions": "Room actions", "Room_changed_announcement": "Room announcement changed to: {{announcement}} by {{userBy}}", @@ -724,5 +725,6 @@ "Remove_from_Team": "Remove from Team", "Auto-join": "Auto-join", "Delete_Team_Room_Warning": "Woud you like to remove this channel from the team? The channel will be moved back to the workspace", - "Confirmation": "Confirmation" + "Confirmation": "Confirmation", + "invalid-room": "Invalid room" } diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js index 9ab5cf215c..9f5aabcab3 100644 --- a/app/lib/methods/loadMessagesForRoom.js +++ b/app/lib/methods/loadMessagesForRoom.js @@ -13,7 +13,7 @@ async function load({ if (team.type) { apiType = this.roomTypeToApiType('p'); } else { - apiType = this.roomTypeToApiType(t); + apiType = this.roomTypeToApiType(t || 'c'); } if (!apiType) { return []; diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index d9cfbc2013..0d68e9628c 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -748,7 +748,7 @@ const RocketChat = { }, addTeamRooms({ rooms, teamId }) { const params = { - rooms: rooms.length ? [...rooms] : [rooms], + rooms: Array.isArray(rooms) ? rooms : [rooms], teamId }; // RC 3.13.0 diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index a642cbf890..e02f59ad89 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -77,7 +77,8 @@ const handleRequest = function* handleRequest({ data }) { // TODO: Log when adding room to team const channels = yield call(addTeamRoom, { rooms: sub.rid, teamId: data.teamId }); if (channels.success) { - sub.teamId = channels.teamId; + sub.teamId = channels.rooms[0].teamId; + sub.isTeamChannel = true; } } } diff --git a/app/utils/goRoom.js b/app/utils/goRoom.js index 1a421e5549..b94acf3fc9 100644 --- a/app/utils/goRoom.js +++ b/app/utils/goRoom.js @@ -8,7 +8,7 @@ const navigate = ({ item, isMasterDetail, ...props }) => { navigationMethod = Navigation.replace; } - if (item.rooms && item.teamId) { + if (item.isTeamChannel) { // TODO: Refactor Navigation.navigate('TeamChannelsView'); Navigation.push('RoomView', { @@ -23,6 +23,8 @@ const navigate = ({ item, isMasterDetail, ...props }) => { teamId: item.teamId, ...props }); + } else if (item.rooms) { + Navigation.navigate('TeamChannelsView'); } else { navigationMethod('RoomView', { rid: item.roomId || item.rid, diff --git a/app/views/AddExistingChannelView.js b/app/views/AddExistingChannelView.js index c299930578..62d2263ec4 100644 --- a/app/views/AddExistingChannelView.js +++ b/app/views/AddExistingChannelView.js @@ -149,7 +149,7 @@ class AddExistingChannelView extends React.Component { const result = await RocketChat.addTeamRooms({ rooms: selected, teamId: this.teamId }); if (result.success) { this.setState({ loading: false }); - goRoom({ result, isMasterDetail }); + goRoom({ item: result, isMasterDetail }); } } catch (e) { // TODO: Log error diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index b329cacc03..70b8c2c443 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -334,7 +334,7 @@ class TeamChannelsView extends React.Component { style: 'cancel' }, { - text: I18n.t('Yes_action_it', { action: I18n.t('delete') }), + text: I18n.t('Yes_action_it', { action: I18n.t('remove') }), style: 'destructive', onPress: () => this.removeRoom(item) } @@ -348,12 +348,10 @@ class TeamChannelsView extends React.Component { const { data } = this.state; const result = await RocketChat.removeTeamRoom({ roomId: item.rid, teamId: this.team.teamId }); if (result.success) { - console.log({ result }); const newData = data.filter(room => result.room._id !== room.rid); - console.log({ newData }); this.setState({ loading: true, data: newData }, () => { - this.loadTeam(); this.load(); + this.loadTeam(); }); } } catch (e) { From 7d2924e2e9c043802323a421fe84d998b156d23c Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 5 May 2021 05:06:45 -0400 Subject: [PATCH 13/77] Added missing events and fixed channels list --- app/presentation/RoomItem/Touchable.js | 2 +- app/sagas/createChannel.js | 5 ++--- app/utils/log/events.js | 4 ++++ app/views/AddExistingChannelView.js | 25 +++++++++++++++++-------- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/app/presentation/RoomItem/Touchable.js b/app/presentation/RoomItem/Touchable.js index 2bfb1aa01a..a78ca4fa17 100644 --- a/app/presentation/RoomItem/Touchable.js +++ b/app/presentation/RoomItem/Touchable.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { Animated } from 'react-native'; import { PanGestureHandler, State } from 'react-native-gesture-handler'; +import Touch from '../../utils/touch'; import { ACTION_WIDTH, SMALL_SWIPE, @@ -10,7 +11,6 @@ import { } from './styles'; import { isRTL } from '../../i18n'; import { LeftActions, RightActions } from './Actions'; -import Touch from '../../utils/touch'; class Touchable extends React.Component { static propTypes = { diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index e02f59ad89..72ffa2e57e 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -44,8 +44,7 @@ const handleRequest = function* handleRequest({ data }) { broadcast, encrypted } = data; - // TODO: Create event CT_CREATE - logEvent(events.CR_CREATE, { + logEvent(events.CT_CREATE, { type, readOnly, broadcast, @@ -74,7 +73,7 @@ const handleRequest = function* handleRequest({ data }) { sub = yield call(createChannel, data); if (data.teamId) { - // TODO: Log when adding room to team + logEvent(events.CT_ADD_ROOM_TO_TEAM); const channels = yield call(addTeamRoom, { rooms: sub.rid, teamId: data.teamId }); if (channels.success) { sub.teamId = channels.rooms[0].teamId; diff --git a/app/utils/log/events.js b/app/utils/log/events.js index 490f0dfd3b..b978d4d0ad 100644 --- a/app/utils/log/events.js +++ b/app/utils/log/events.js @@ -101,12 +101,16 @@ export default { // CREATE CHANNEL VIEW CR_CREATE: 'cr_create', + CT_CREATE: 'ct_create', CR_CREATE_F: 'cr_create_f', + CT_CREATE_F: 'ct_create_f', CR_TOGGLE_TYPE: 'cr_toggle_type', CR_TOGGLE_READ_ONLY: 'cr_toggle_read_only', CR_TOGGLE_BROADCAST: 'cr_toggle_broadcast', CR_TOGGLE_ENCRYPTED: 'cr_toggle_encrypted', CR_REMOVE_USER: 'cr_remove_user', + CT_ADD_ROOM_TO_TEAM: 'ct_add_room_to_team', + CT_ADD_ROOM_TO_TEAM_F: 'ct_add_room_to_team_f', // CREATE DISCUSSION VIEW CD_CREATE: 'cd_create', diff --git a/app/views/AddExistingChannelView.js b/app/views/AddExistingChannelView.js index 62d2263ec4..6f6087fd9a 100644 --- a/app/views/AddExistingChannelView.js +++ b/app/views/AddExistingChannelView.js @@ -14,7 +14,7 @@ import database from '../lib/database'; import RocketChat from '../lib/rocketchat'; import sharedStyles from './Styles'; import I18n from '../i18n'; -import log from '../utils/log'; +import log, { events, logEvent } from '../utils/log'; import SearchBox from '../containers/SearchBox'; import { CustomIcon } from '../lib/Icons'; import * as HeaderButton from '../containers/HeaderButton'; @@ -63,7 +63,8 @@ class AddExistingChannelView extends React.Component { token: PropTypes.string }), theme: PropTypes.string, - isMasterDetail: PropTypes.bool + isMasterDetail: PropTypes.bool, + addTeamChannelPermission: PropTypes.array }; constructor(props) { @@ -107,17 +108,24 @@ class AddExistingChannelView extends React.Component { // eslint-disable-next-line react/sort-comp init = async() => { try { + const { addTeamChannelPermission } = this.props; const db = database.active; const channels = await db.collections .get('subscriptions') .query( - Q.where('t', 'p'), - Q.where('team_id', ''), + Q.and(Q.where('team_id', ''), Q.or(Q.where('t', 'c'), Q.where('t', 'p'))), Q.experimentalTake(QUERY_SIZE), Q.experimentalSortBy('room_updated_at', Q.desc) ) .fetch(); - this.setState({ channels }); + const filteredChannels = channels.filter(async(channel) => { + const permissions = await RocketChat.hasPermission([addTeamChannelPermission], channel.rid); + if (!permissions[0]) { + return; + } + return channel; + }); + this.setState({ channels: filteredChannels }); } catch (e) { log(e); } @@ -145,14 +153,14 @@ class AddExistingChannelView extends React.Component { this.setState({ loading: true }); try { - // TODO: Log request + logEvent(events.CT_ADD_ROOM_TO_TEAM); const result = await RocketChat.addTeamRooms({ rooms: selected, teamId: this.teamId }); if (result.success) { this.setState({ loading: false }); goRoom({ item: result, isMasterDetail }); } } catch (e) { - // TODO: Log error + logEvent(events.CT_ADD_ROOM_TO_TEAM_F); this.setState({ loading: false }); } } @@ -250,7 +258,8 @@ class AddExistingChannelView extends React.Component { } const mapStateToProps = state => ({ - isMasterDetail: state.app.isMasterDetail + isMasterDetail: state.app.isMasterDetail, + addTeamChannelPermission: state.permissions['add-team-channel'] }); export default connect(mapStateToProps, null)(withTheme(AddExistingChannelView)); From 4bac0541058d064624d83c5d090465cb9237aad6 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 5 May 2021 08:20:48 -0400 Subject: [PATCH 14/77] Minor tweaks for refactored touch component --- __tests__/__snapshots__/Storyshots.test.js.snap | 3 +-- app/containers/List/ListItem.js | 4 ++-- app/containers/LoginServices.js | 5 ++--- app/containers/Passcode/Base/Button.js | 2 +- app/presentation/RoomItem/Touchable.js | 2 ++ app/utils/touch.js | 9 ++++----- app/views/AddChannelTeamView.js | 3 +++ app/views/DirectoryView/Options.js | 2 +- app/views/DirectoryView/index.js | 2 +- app/views/NewMessageView.js | 3 +++ app/views/ProfileView/index.js | 2 +- app/views/RoomActionsView/index.js | 2 +- app/views/SidebarView/SidebarItem.js | 2 +- app/views/ThreadMessagesView/Dropdown/DropdownItem.js | 2 +- 14 files changed, 24 insertions(+), 19 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index f99bbe10df..633d5e2abe 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -7439,11 +7439,10 @@ exports[`Storyshots List with custom colors 1`] = ` style={ Array [ Object { - "backgroundColor": "#ffffff", + "backgroundColor": "red", }, ] } - underlayColor="green" > ( onPress(props.title)} - underlayColor={underlayColor} + style={({ pressed }) => [{ backgroundColor: pressed ? underlayColor || themes[props.theme].bannerBackground : backgroundColor || themes[props.theme].backgroundColor }]} enabled={!props.disabled} theme={props.theme} > diff --git a/app/containers/LoginServices.js b/app/containers/LoginServices.js index 4ae647b5ce..d3f889a8a4 100644 --- a/app/containers/LoginServices.js +++ b/app/containers/LoginServices.js @@ -7,6 +7,7 @@ import { connect } from 'react-redux'; import { Base64 } from 'js-base64'; import * as AppleAuthentication from 'expo-apple-authentication'; +import { transparentize } from 'color2k'; import { withTheme } from '../theme'; import sharedStyles from '../views/Styles'; import { themes } from '../constants/colors'; @@ -344,10 +345,8 @@ class LoginServices extends React.PureComponent { [styles.serviceButton, { backgroundColor: pressed ? transparentize(themes[theme].buttonText, 0.5) : backgroundColor }]} theme={theme} - activeOpacity={0.5} - underlayColor={themes[theme].buttonText} > {service.authType === 'oauth' || service.authType === 'apple' ? : null} diff --git a/app/containers/Passcode/Base/Button.js b/app/containers/Passcode/Base/Button.js index 7826ed5fe9..89228cd007 100644 --- a/app/containers/Passcode/Base/Button.js +++ b/app/containers/Passcode/Base/Button.js @@ -14,7 +14,7 @@ const Button = React.memo(({ return ( [styles.buttonView, { backgroundColor: pressed ? 'transparent' : themes[theme].bannerBackground }]} underlayColor={themes[theme].passcodeButtonActive} rippleColor={themes[theme].passcodeButtonActive} enabled={!disabled} diff --git a/app/presentation/RoomItem/Touchable.js b/app/presentation/RoomItem/Touchable.js index a78ca4fa17..f212338d11 100644 --- a/app/presentation/RoomItem/Touchable.js +++ b/app/presentation/RoomItem/Touchable.js @@ -10,6 +10,7 @@ import { LONG_SWIPE } from './styles'; import { isRTL } from '../../i18n'; +import { themes } from '../../constants/colors'; import { LeftActions, RightActions } from './Actions'; class Touchable extends React.Component { @@ -253,6 +254,7 @@ class Touchable extends React.Component { onLongPress={this.onLongPress} theme={theme} testID={testID} + style={({ pressed }) => [{ backgroundColor: pressed ? themes[theme].chatComponentBackground : themes[theme].backgroundColor }]} > {children} diff --git a/app/utils/touch.js b/app/utils/touch.js index f7dc6c8669..a840c16570 100644 --- a/app/utils/touch.js +++ b/app/utils/touch.js @@ -15,7 +15,7 @@ class Touch extends React.Component { render() { const { - children, onPress, onLongPress, theme, ...props + children, onPress, onLongPress, theme, style, ...props } = this.props; return ( @@ -24,9 +24,7 @@ class Touch extends React.Component { onPress={onPress} onLongPress={onLongPress} activeOpacity={1} - style={({ pressed }) => [{ - backgroundColor: pressed ? themes[theme].chatComponentBackground : themes[theme].backgroundColor - }]} + style={style} android_ripple={{ color: themes[theme].bannerBackground }} {...props} > @@ -41,7 +39,8 @@ Touch.propTypes = { onPress: PropTypes.func, onLongPress: PropTypes.func, theme: PropTypes.string, - underlayColor: PropTypes.string + underlayColor: PropTypes.string, + style: PropTypes.object }; export default Touch; diff --git a/app/views/AddChannelTeamView.js b/app/views/AddChannelTeamView.js index 27cf6646ab..768048dff7 100644 --- a/app/views/AddChannelTeamView.js +++ b/app/views/AddChannelTeamView.js @@ -72,6 +72,9 @@ class AddChannelTeamView extends React.Component { return ( [{ + backgroundColor: pressed ? themes[theme].chatComponentBackground : themes[theme].backgroundColor + }]} testID={testID} theme={theme} > diff --git a/app/views/DirectoryView/Options.js b/app/views/DirectoryView/Options.js index ad8de1da18..d7af8776b7 100644 --- a/app/views/DirectoryView/Options.js +++ b/app/views/DirectoryView/Options.js @@ -67,7 +67,7 @@ export default class DirectoryOptions extends PureComponent { return ( changeType(itemType)} - style={styles.dropdownItemButton} + style={({ pressed }) => [{ backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor }, styles.dropdownItemButton]} theme={theme} > diff --git a/app/views/DirectoryView/index.js b/app/views/DirectoryView/index.js index f78e74a21f..06678620b5 100644 --- a/app/views/DirectoryView/index.js +++ b/app/views/DirectoryView/index.js @@ -169,7 +169,7 @@ class DirectoryView extends React.Component { /> [{ backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor }, styles.dropdownItemButton]} testID='directory-view-dropdown' theme={theme} > diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index 66ea00482d..c538a43215 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -148,6 +148,9 @@ class NewMessageView extends React.Component { return ( [{ + backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor + }]} testID={testID} theme={theme} > diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js index 7e97422df2..1adb555baa 100644 --- a/app/views/ProfileView/index.js +++ b/app/views/ProfileView/index.js @@ -309,7 +309,7 @@ class ProfileView extends React.Component { key={key} testID={key} onPress={onPress} - style={[styles.avatarButton, { opacity: disabled ? 0.5 : 1 }, { backgroundColor: themes[theme].borderColor }]} + style={({ pressed }) => [styles.avatarButton, { opacity: disabled ? 0.5 : 1 }, { backgroundColor: pressed ? themes[theme].borderColor : themes[theme].bannerBackground }]} enabled={!disabled} theme={theme} > diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index ea833d7588..2e5788a23b 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -433,7 +433,7 @@ class RoomActionsView extends React.Component { rid, t, room, member } })} - style={{ backgroundColor: themes[theme].backgroundColor }} + style={({ pressed }) => [{ backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor }]} accessibilityLabel={I18n.t('Room_Info')} accessibilityTraits='button' enabled={!isGroupChat} diff --git a/app/views/SidebarView/SidebarItem.js b/app/views/SidebarView/SidebarItem.js index 7959438c28..4315f9cdac 100644 --- a/app/views/SidebarView/SidebarItem.js +++ b/app/views/SidebarView/SidebarItem.js @@ -15,7 +15,7 @@ const Item = React.memo(({ testID={testID} onPress={onPress} theme={theme} - style={[styles.item, current && { backgroundColor: themes[theme].borderColor }]} + style={({ pressed }) => [styles.item, current && { backgroundColor: pressed ? themes[theme].borderColor : themes[theme].bannerBackground }]} > {left} diff --git a/app/views/ThreadMessagesView/Dropdown/DropdownItem.js b/app/views/ThreadMessagesView/Dropdown/DropdownItem.js index 4ebca91688..38b66074aa 100644 --- a/app/views/ThreadMessagesView/Dropdown/DropdownItem.js +++ b/app/views/ThreadMessagesView/Dropdown/DropdownItem.js @@ -26,7 +26,7 @@ const styles = StyleSheet.create({ const DropdownItem = React.memo(({ theme, onPress, iconName, text }) => ( - + [{ backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor }]}> {text} {iconName ? : null} From 4b6e691d8ac9df97f73ea1d0ef7a149bd6544989 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 6 May 2021 05:22:34 -0400 Subject: [PATCH 15/77] Added SelectListView and logic for leaving team --- app/i18n/locales/en.json | 9 +- app/lib/rocketchat.js | 4 + app/stacks/InsideStack.js | 6 + app/views/RoomActionsView/index.js | 53 +++++- app/views/RoomView/index.js | 1 + app/views/RoomsListView/index.js | 1 - app/views/SelectListView.js | 278 +++++++++++++++++++++++++++++ 7 files changed, 348 insertions(+), 4 deletions(-) create mode 100644 app/views/SelectListView.js diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 0ef3e03c49..46e15db186 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -290,6 +290,7 @@ "last_message": "last message", "Leave_channel": "Leave channel", "leaving_room": "leaving room", + "Leave": "Leave", "leave": "leave", "Legal": "Legal", "Light": "Light", @@ -726,5 +727,11 @@ "Auto-join": "Auto-join", "Delete_Team_Room_Warning": "Woud you like to remove this channel from the team? The channel will be moved back to the workspace", "Confirmation": "Confirmation", - "invalid-room": "Invalid room" + "invalid-room": "Invalid room", + "You_are_leaving_the_team": "You are leaving the team '{{team}}'", + "Leave_Team": "Leave Team", + "Select_Teams": "Select the Team's channels you would like to leave.", + "Cannot_leave": "Cannot leave", + "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", + "last-owner-can-not-be-removed": "Last owner cannot be removed" } diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 0d68e9628c..965b5be08a 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -758,6 +758,10 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.removeRoom', { roomId, teamId }); }, + leaveTeam({ teamName }) { + // RC 3.13.0 + return this.post('teams.leave', { teamName }); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/stacks/InsideStack.js b/app/stacks/InsideStack.js index 75758960b1..18517368c7 100644 --- a/app/stacks/InsideStack.js +++ b/app/stacks/InsideStack.js @@ -73,6 +73,7 @@ import CreateDiscussionView from '../views/CreateDiscussionView'; import QueueListView from '../ee/omnichannel/views/QueueListView'; import AddChannelTeamView from '../views/AddChannelTeamView'; import AddExistingChannelView from '../views/AddExistingChannelView'; +import SelectListView from '../views/SelectListView'; // ChatsStackNavigator const ChatsStack = createStackNavigator(); @@ -93,6 +94,11 @@ const ChatsStackNavigator = () => { component={RoomActionsView} options={RoomActionsView.navigationOptions} /> + { + try { + const { navigation } = this.props; + const result = await RocketChat.leaveTeam({ teamName }); + // Add isMasterDetail + if (result.success) { + navigation.navigate('RoomsListView'); + } + } catch (e) { + log(e); + } + } + + leaveTeam = async() => { + const { room } = this.state; + const { navigation } = this.props; + + try { + const db = database.active; + const subCollection = db.get('subscriptions'); + const teamChannels = await subCollection.query( + Q.where('team_id', Q.eq(room.teamId)) + ); + + if (teamChannels) { + navigation.navigate('SelectListView', { title: 'Leave_Team', teamChannels, teamName: room.name }); + } else { + Alert.alert( + I18n.t('Confirmation'), + I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }), + [ + { + text: I18n.t('Cancel'), + style: 'cancel' + }, + { + text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), + style: 'destructive', + onPress: () => this._leave(room.name) + } + ] + ); + } + } catch (e) { + log(e); + } + } + renderRoomInfo = () => { const { room, member } = this.state; const { @@ -568,9 +617,9 @@ class RoomActionsView extends React.Component { this.onPressTouchable({ - event: this.leaveChannel + event: room.teamId && room.teamMain ? this.leaveTeam : this.leaveChannel })} testID='room-actions-leave-channel' left={() => } diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index a410782161..d7bba1017e 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -1033,6 +1033,7 @@ class RoomView extends React.Component { renderActions = () => { const { room, readOnly } = this.state; const { user } = this.props; + console.log({ room }); return ( <> ; } - return ( { + const { navigation, isMasterDetail, theme } = this.props; + + const options = { + headerShown: true, + headerTitleAlign: 'center', + headerTitle: I18n.t(this.title) + }; + + if (isMasterDetail) { + options.headerLeft = () => ; + } else { + options.headerLeft = () => navigation.pop()} tintColor={themes[theme].headerTintColor} />; + } + + options.headerRight = () => ( + + + + ); + + navigation.setOptions(options); + } + + submit = async() => { + const { selected } = this.state; + const { navigation, leaveRoom } = this.props; + + this.setState({ loading: true }); + try { + // logEvent(events.CT_ADD_ROOM_TO_TEAM); + const result = await RocketChat.leaveTeam({ teamName: this.teamName }); + if (selected) { + selected.map(room => leaveRoom(room.rid, room.t)); + } + if (result.success) { + this.setState({ loading: false }); + navigation.navigate('RoomsListView'); + } + } catch (e) { + // logEvent(events.CT_ADD_ROOM_TO_TEAM_F); + this.setState({ loading: false }); + Alert.alert( + I18n.t('Cannot_leave'), + I18n.t(e.data.error), + [ + { + text: 'OK', + style: 'cancel' + } + ] + ); + } + } + + renderHeader = () => { + const { theme } = this.props; + return ( + + {I18n.t('Select_Teams')} + + ); + } + + showAlert = () => { + Alert.alert( + I18n.t('Cannot_leave'), + I18n.t('Last_owner_team_room'), + [ + { + text: 'OK', + style: 'cancel' + } + ] + ); + } + + leaveChannel = () => { + const { room } = this.state; + const { leaveRoom } = this.props; + + Alert.alert( + I18n.t('Are_you_sure_question_mark'), + I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: RocketChat.getRoomTitle(room) }), + [ + { + text: I18n.t('Cancel'), + style: 'cancel' + }, + { + text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), + style: 'destructive', + onPress: () => leaveRoom(room.rid, room.t) + } + ] + ); + } + + renderChannel = ({ + onPress, testID, title, icon, checked, alert + }) => { + const { theme } = this.props; + + return ( + + + + + {title} + { alert + ? ( + this.showAlert()}> + + + ) : null} + + {checked ? : null} + + + ); + } + + isChecked = (rid) => { + const { selected } = this.state; + return selected.includes(rid); + } + + toggleChannel = (rid, roles) => { + const { selected } = this.state; + + if (roles) { + this.showAlert(); + return; + } + + animateNextTransition(); + if (!this.isChecked(rid)) { + this.setState({ selected: [...selected, rid] }, () => this.setHeader()); + } else { + const filterSelected = selected.filter(el => el !== rid); + this.setState({ selected: filterSelected }, () => this.setHeader()); + } + } + + renderItem = ({ item }) => ( + <> + {this.renderChannel({ + onPress: () => this.toggleChannel(item.rid, item.roles), + title: item.name, + icon: item.t === 'p' ? 'channel-private' : 'channel-public', + checked: this.isChecked(item.rid, item.roles) ? 'check' : null, + testID: 'select-list-view-item', + alert: item.roles ? 'info' : null + })} + + ) + + renderList = () => { + const { data } = this.state; + const { theme } = this.props; + + return ( + item._id} + renderItem={this.renderItem} + ListHeaderComponent={this.renderHeader} + ItemSeparatorComponent={List.Separator} + contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} + keyboardShouldPersistTaps='always' + /> + ); + } + + render() { + const { loading } = this.state; + + return ( + + + {this.renderList()} + + + ); + } +} + +const mapStateToProps = state => ({ + isMasterDetail: state.app.isMasterDetail +}); + +const mapDispatchToProps = dispatch => ({ + leaveRoom: (rid, t) => dispatch(leaveRoomAction(rid, t)) +}); + +export default connect(mapStateToProps, mapDispatchToProps)(withTheme(SelectListView)); From b961fa05d97be5849a9a8969f8257005b25a0511 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 6 May 2021 08:57:53 -0400 Subject: [PATCH 16/77] Added addTeamMember and removeTeamMember --- app/i18n/locales/en.json | 6 +- app/lib/methods/getPermissions.js | 2 + app/lib/rocketchat.js | 10 ++ app/views/RoomActionsView/index.js | 46 +++++++- app/views/RoomMembersView/index.js | 166 ++++++++++++++++++++++------- app/views/RoomView/index.js | 2 +- app/views/SelectListView.js | 20 ++++ 7 files changed, 207 insertions(+), 45 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 46e15db186..ea20c91e72 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -733,5 +733,9 @@ "Select_Teams": "Select the Team's channels you would like to leave.", "Cannot_leave": "Cannot leave", "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", - "last-owner-can-not-be-removed": "Last owner cannot be removed" + "last-owner-can-not-be-removed": "Last owner cannot be removed", + "Removing_user_from_this_Team": "You are removing {{user}} from this Team", + "Remove_User_Teams": "Select channels you want the user to be removed from.", + "Remove_Member": "Remove Member", + "Error": "Error" } diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index 1f4bcb9cb1..8a837e4b19 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -13,6 +13,7 @@ const PERMISSIONS = [ 'add-user-to-any-c-room', 'add-user-to-any-p-room', 'add-user-to-joined-room', + 'add-team-member', 'add-team-channel', 'archive-room', 'auto-translate', @@ -22,6 +23,7 @@ const PERMISSIONS = [ 'delete-p', 'edit-message', 'edit-room', + 'edit-team-member', 'edit-team-channel', 'force-delete-message', 'mute-user', diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 965b5be08a..5478c6b22d 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -762,6 +762,16 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.leave', { teamName }); }, + addTeamMember(teamName) { + const { users } = reduxStore.getState().selectedUsers; + const members = users.map(u => ({ userId: u._id, roles: ['member'] })); + // RC 3.13.0 + return this.post('teams.addMembers', { teamName, members }); + }, + removeTeamMember({ teamName, userId }) { + // RC 3.13.0 + return this.post('teams.removeMember', { teamName, userId }); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index c091e88956..b0c12a2bd3 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -61,7 +61,8 @@ class RoomActionsView extends React.Component { editRoomPermission: PropTypes.array, toggleRoomE2EEncryptionPermission: PropTypes.array, viewBroadcastMemberListPermission: PropTypes.array, - transferLivechatGuestPermission: PropTypes.array + transferLivechatGuestPermission: PropTypes.array, + addTeamMemberPermission: PropTypes.array } constructor(props) { @@ -171,12 +172,19 @@ class RoomActionsView extends React.Component { canAddUser = async() => { const { room, joined } = this.state; - const { addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission } = this.props; + const { + addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission, addTeamMemberPermission + } = this.props; const { rid, t } = room; let canAddUser = false; + let permissions; const userInRoom = joined; - const permissions = await RocketChat.hasPermission([addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission], rid); + if (room.teamMain) { + permissions = await RocketChat.hasPermission([addTeamMemberPermission], rid); + } else { + permissions = await RocketChat.hasPermission([addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission], rid); + } if (userInRoom && permissions[0]) { canAddUser = true; @@ -321,6 +329,31 @@ class RoomActionsView extends React.Component { setLoadingInvite(true); await RocketChat.addUsersToRoom(rid); navigation.pop(); + } catch (e) { + log(e); + Alert.alert( + I18n.t('Confirmation'), + I18n.t('Removing_user_from_this_Team'), + [ + { + text: I18n.t('OK'), + style: 'cancel' + } + ], + { cancelable: false } + ); + } finally { + setLoadingInvite(false); + } + } + + addMemberToTeam = async() => { + const { room } = this.state; + const { setLoadingInvite, navigation } = this.props; + try { + setLoadingInvite(true); + await RocketChat.addTeamMember(room.name); + navigation.pop(); } catch (e) { log(e); } finally { @@ -438,7 +471,9 @@ class RoomActionsView extends React.Component { ); if (teamChannels) { - navigation.navigate('SelectListView', { title: 'Leave_Team', teamChannels, teamName: room.name }); + navigation.navigate('SelectListView', { + title: 'Leave_Team', teamChannels, teamName: room.name, subtitle: 'Select_Teams' + }); } else { Alert.alert( I18n.t('Confirmation'), @@ -678,7 +713,7 @@ class RoomActionsView extends React.Component { params: { rid, title: I18n.t('Add_users'), - nextAction: this.addUser + nextAction: room.teamId ? this.addMemberToTeam : this.addUser } })} testID='room-actions-add-user' @@ -930,6 +965,7 @@ const mapStateToProps = state => ({ encryptionEnabled: state.encryption.enabled, serverVersion: state.server.version, addUserToJoinedRoomPermission: state.permissions['add-user-to-joined-room'], + addTeamMemberPermission: state.permissions['add-team-member'], addUserToAnyCRoomPermission: state.permissions['add-user-to-any-c-room'], addUserToAnyPRoomPermission: state.permissions['add-user-to-any-p-room'], createInviteLinksPermission: state.permissions['create-invite-links'], diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 9a47b60f74..c6b74a9f9e 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { FlatList } from 'react-native'; +import { FlatList, Alert } from 'react-native'; import { connect } from 'react-redux'; import { Q } from '@nozbe/watermelondb'; import * as List from '../../containers/List'; @@ -34,6 +34,7 @@ const PERMISSION_SET_LEADER = 'set-leader'; const PERMISSION_SET_OWNER = 'set-owner'; const PERMISSION_SET_MODERATOR = 'set-moderator'; const PERMISSION_REMOVE_USER = 'remove-user'; +const PERMISSION_EDIT_TEAM_MEMBER = 'edit-team-member'; class RoomMembersView extends React.Component { static propTypes = { @@ -55,7 +56,8 @@ class RoomMembersView extends React.Component { setLeaderPermission: PropTypes.array, setOwnerPermission: PropTypes.array, setModeratorPermission: PropTypes.array, - removeUserPermission: PropTypes.array + removeUserPermission: PropTypes.array, + editTeamMemberPermission: PropTypes.array } constructor(props) { @@ -94,18 +96,44 @@ class RoomMembersView extends React.Component { const { room } = this.state; const { - muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, editTeamMemberPermission } = this.props; - const result = await RocketChat.hasPermission([ - muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission - ], room.rid); + let result; + + if (room.teamId) { + result = await RocketChat.hasPermission([ + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, editTeamMemberPermission + ], room.rid); + + this.permissions = { + [PERMISSION_MUTE_USER]: result[0], + [PERMISSION_SET_LEADER]: result[1], + [PERMISSION_SET_OWNER]: result[2], + [PERMISSION_SET_MODERATOR]: result[3], + [PERMISSION_REMOVE_USER]: result[4], + [PERMISSION_EDIT_TEAM_MEMBER]: result[5] + }; + } else { + result = await RocketChat.hasPermission([ + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission + ], room.rid); + + this.permissions = { + [PERMISSION_MUTE_USER]: result[0], + [PERMISSION_SET_LEADER]: result[1], + [PERMISSION_SET_OWNER]: result[2], + [PERMISSION_SET_MODERATOR]: result[3], + [PERMISSION_REMOVE_USER]: result[4] + }; + } this.permissions = { [PERMISSION_MUTE_USER]: result[0], [PERMISSION_SET_LEADER]: result[1], [PERMISSION_SET_OWNER]: result[2], [PERMISSION_SET_MODERATOR]: result[3], - [PERMISSION_REMOVE_USER]: result[4] + [PERMISSION_REMOVE_USER]: result[4], + [PERMISSION_EDIT_TEAM_MEMBER]: result[5] }; const hasSinglePermission = Object.values(this.permissions).some(p => !!p); @@ -163,6 +191,56 @@ class RoomMembersView extends React.Component { } } + handleRemoveFromTeam = async(selectedUser) => { + const { navigation } = this.props; + const { room } = this.state; + const db = database.active; + const subCollection = db.get('subscriptions'); + const teamChannels = await subCollection.query( + Q.where('team_id', Q.eq(room.teamId)) + ); + if (teamChannels) { + navigation.navigate('SelectListView', { + title: 'Remove_Member', subtitle: 'Remove_User_Teams', teamChannels, selectedUser + }); + } else { + Alert.alert( + I18n.t('Confirmation'), + I18n.t('Removing_user_from_this_Team', { user: selectedUser.username }), + [ + { + text: I18n.t('Cancel'), + style: 'cancel' + }, + { + text: I18n.t('Yes_action_it', { action: I18n.t('remove') }), + style: 'destructive', + onPress: () => this.removeFromTeam(selectedUser) + } + ], + { cancelable: false } + ); + } + } + + removeFromTeam = async(selectedUser) => { + try { + const { members, membersFiltered, room } = this.state; + const userId = selectedUser._id; + const result = await RocketChat.removeTeamMember({ teamName: room.name, userId }); + if (result.success) { + const message = I18n.t('User_has_been_removed_from_s', { s: RocketChat.getRoomTitle(room) }); + EventEmitter.emit(LISTENER, { message }); + this.setState({ + members: members.filter(member => member._id !== userId), + membersFiltered: membersFiltered.filter(member => member._id !== userId) + }); + } + } catch (e) { + log(e); + } + } + onPressUser = (selectedUser) => { const { room } = this.state; const { showActionSheet, user } = this.props; @@ -173,6 +251,46 @@ class RoomMembersView extends React.Component { onPress: () => this.navToDirectMessage(selectedUser) }]; + // Ignore + if (selectedUser._id !== user.id) { + const { ignored } = room; + const isIgnored = ignored?.includes?.(selectedUser._id); + options.push({ + icon: 'ignore', + title: I18n.t(isIgnored ? 'Unignore' : 'Ignore'), + onPress: () => this.handleIgnore(selectedUser, !isIgnored) + }); + } + + if (this.permissions['mute-user']) { + const { muted = [] } = room; + const userIsMuted = muted.find?.(m => m === selectedUser.username); + selectedUser.muted = !!userIsMuted; + options.push({ + icon: userIsMuted ? 'audio' : 'audio-disabled', + title: I18n.t(userIsMuted ? 'Unmute' : 'Mute'), + onPress: () => { + showConfirmationAlert({ + message: I18n.t(`The_user_${ userIsMuted ? 'will' : 'wont' }_be_able_to_type_in_roomName`, { + roomName: RocketChat.getRoomTitle(room) + }), + confirmationText: I18n.t(userIsMuted ? 'Unmute' : 'Mute'), + onPress: () => this.handleMute(selectedUser) + }); + } + }); + } + + // Remove from team + if (this.permissions['edit-team-member']) { + options.push({ + icon: 'close', + danger: true, + title: I18n.t('Remove_from_Team'), + onPress: () => this.handleRemoveFromTeam(selectedUser) + }); + } + // Owner if (this.permissions['set-owner']) { const userRoleResult = this.roomRoles.find(r => r.u._id === selectedUser._id); @@ -206,36 +324,6 @@ class RoomMembersView extends React.Component { }); } - // Ignore - if (selectedUser._id !== user.id) { - const { ignored } = room; - const isIgnored = ignored?.includes?.(selectedUser._id); - options.push({ - icon: 'ignore', - title: I18n.t(isIgnored ? 'Unignore' : 'Ignore'), - onPress: () => this.handleIgnore(selectedUser, !isIgnored) - }); - } - - if (this.permissions['mute-user']) { - const { muted = [] } = room; - const userIsMuted = muted.find?.(m => m === selectedUser.username); - selectedUser.muted = !!userIsMuted; - options.push({ - icon: userIsMuted ? 'audio' : 'audio-disabled', - title: I18n.t(userIsMuted ? 'Unmute' : 'Mute'), - onPress: () => { - showConfirmationAlert({ - message: I18n.t(`The_user_${ userIsMuted ? 'will' : 'wont' }_be_able_to_type_in_roomName`, { - roomName: RocketChat.getRoomTitle(room) - }), - confirmationText: I18n.t(userIsMuted ? 'Unmute' : 'Mute'), - onPress: () => this.handleMute(selectedUser) - }); - } - }); - } - // Remove from room if (this.permissions['remove-user']) { options.push({ @@ -292,6 +380,7 @@ class RoomMembersView extends React.Component { this.setState({ isLoading: true }); try { const membersResult = await RocketChat.getRoomMembers(rid, allUsers, members.length, PAGE_SIZE); + console.log({ membersResult }); const newMembers = membersResult.records; this.setState({ members: members.concat(newMembers || []), @@ -477,7 +566,8 @@ const mapStateToProps = state => ({ setLeaderPermission: state.permissions[PERMISSION_SET_LEADER], setOwnerPermission: state.permissions[PERMISSION_SET_OWNER], setModeratorPermission: state.permissions[PERMISSION_SET_MODERATOR], - removeUserPermission: state.permissions[PERMISSION_REMOVE_USER] + removeUserPermission: state.permissions[PERMISSION_REMOVE_USER], + editTeamMemberPermission: state.permissions['edit-team-member'] }); export default connect(mapStateToProps)(withActionSheet(withTheme(RoomMembersView))); diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index d7bba1017e..6ffc07e7f3 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -1033,7 +1033,7 @@ class RoomView extends React.Component { renderActions = () => { const { room, readOnly } = this.state; const { user } = this.props; - console.log({ room }); + return ( <> { + try { + const { data, room } = this.state; + const userId = selectedUser._id; + const result = await RocketChat.removeTeamMember({ teamName: room.name, userId }); + if (result.success) { + const message = I18n.t('User_has_been_removed_from_s', { s: RocketChat.getRoomTitle(room) }); + EventEmitter.emit(LISTENER, { message }); + this.setState({ data: data.filter(member => member._id !== userId) }); + } + } catch (e) { + log(e); + } + } + renderChannel = ({ onPress, testID, title, icon, checked, alert }) => { From 04ea01b3248a5bb9ad079457e8bddb767a81ebbd Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 6 May 2021 09:05:11 -0400 Subject: [PATCH 17/77] Minor tweak --- app/views/RoomActionsView/index.js | 4 +++- app/views/SelectListView.js | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index c091e88956..34542bb2e8 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -438,7 +438,9 @@ class RoomActionsView extends React.Component { ); if (teamChannels) { - navigation.navigate('SelectListView', { title: 'Leave_Team', teamChannels, teamName: room.name }); + navigation.navigate('SelectListView', { + title: 'Leave_Team', room, teamChannels, teamName: room.name + }); } else { Alert.alert( I18n.t('Confirmation'), diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 236412446e..4e5768e65f 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -66,6 +66,7 @@ class SelectListView extends React.Component { const teamChannels = props.route?.params?.teamChannels; this.title = props.route?.params?.title; this.teamName = props.route?.params?.teamName; + this.room = props.route?.params?.room; this.state = { data: teamChannels, selected: [], From a305676fd6587076fb8be9d4cb3c907ea51245ab Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 7 May 2021 08:01:27 -0400 Subject: [PATCH 18/77] Added deleteTeam function --- app/i18n/locales/en.json | 4 +- app/lib/rocketchat.js | 4 ++ app/views/RoomInfoEditView/index.js | 106 +++++++++++++++++++++------- app/views/SelectListView.js | 3 +- 4 files changed, 90 insertions(+), 27 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index ea20c91e72..e6138f8ecc 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -737,5 +737,7 @@ "Removing_user_from_this_Team": "You are removing {{user}} from this Team", "Remove_User_Teams": "Select channels you want the user to be removed from.", "Remove_Member": "Remove Member", - "Error": "Error" + "Error": "Error", + "Delete_Team": "Delete Team", + "Delete_Team_Warning": "You are deleting this team." } diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 5478c6b22d..fad815a2b5 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -772,6 +772,10 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.removeMember', { teamName, userId }); }, + deleteTeam({ teamName }) { + // RC 3.13.0 + return this.post('teams.delete', { teamName }); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index 7552b093ad..1986e2725f 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -8,6 +8,7 @@ import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit'; import ImagePicker from 'react-native-image-crop-picker'; import { dequal } from 'dequal'; import isEmpty from 'lodash/isEmpty'; +import { Q } from '@nozbe/watermelondb'; import { compareServerVersion, methods } from '../../lib/utils'; import database from '../../lib/database'; @@ -41,6 +42,7 @@ const PERMISSION_ARCHIVE = 'archive-room'; const PERMISSION_UNARCHIVE = 'unarchive-room'; const PERMISSION_DELETE_C = 'delete-c'; const PERMISSION_DELETE_P = 'delete-p'; +const PERMISSION_EDIT_TEAM_CHANNEL = 'edit-team-channel'; class RoomInfoEditView extends React.Component { static navigationOptions = () => ({ @@ -48,6 +50,7 @@ class RoomInfoEditView extends React.Component { }) static propTypes = { + navigation: PropTypes.object, route: PropTypes.object, deleteRoom: PropTypes.func, serverVersion: PropTypes.string, @@ -58,7 +61,8 @@ class RoomInfoEditView extends React.Component { archiveRoomPermission: PropTypes.array, unarchiveRoomPermission: PropTypes.array, deleteCPermission: PropTypes.array, - deletePPermission: PropTypes.array + deletePPermission: PropTypes.array, + editTeamChannelPermission: PropTypes.array }; constructor(props) { @@ -100,7 +104,8 @@ class RoomInfoEditView extends React.Component { archiveRoomPermission, unarchiveRoomPermission, deleteCPermission, - deletePPermission + deletePPermission, + editTeamChannelPermission } = this.props; const rid = route.params?.rid; if (!rid) { @@ -116,25 +121,51 @@ class RoomInfoEditView extends React.Component { this.init(this.room); }); - const result = await RocketChat.hasPermission([ - setReadOnlyPermission, - setReactWhenReadOnlyPermission, - archiveRoomPermission, - unarchiveRoomPermission, - deleteCPermission, - deletePPermission - ], rid); - - this.setState({ - permissions: { - [PERMISSION_SET_READONLY]: result[0], - [PERMISSION_SET_REACT_WHEN_READONLY]: result[1], - [PERMISSION_ARCHIVE]: result[2], - [PERMISSION_UNARCHIVE]: result[3], - [PERMISSION_DELETE_C]: result[4], - [PERMISSION_DELETE_P]: result[5] - } - }); + let result; + + if (this.room.teamId) { + result = await RocketChat.hasPermission([ + setReadOnlyPermission, + setReactWhenReadOnlyPermission, + archiveRoomPermission, + unarchiveRoomPermission, + deleteCPermission, + deletePPermission, + editTeamChannelPermission + ], rid); + + this.setState({ + permissions: { + [PERMISSION_SET_READONLY]: result[0], + [PERMISSION_SET_REACT_WHEN_READONLY]: result[1], + [PERMISSION_ARCHIVE]: result[2], + [PERMISSION_UNARCHIVE]: result[3], + [PERMISSION_DELETE_C]: result[4], + [PERMISSION_DELETE_P]: result[5], + [PERMISSION_EDIT_TEAM_CHANNEL]: result[6] + } + }); + } else { + result = await RocketChat.hasPermission([ + setReadOnlyPermission, + setReactWhenReadOnlyPermission, + archiveRoomPermission, + unarchiveRoomPermission, + deleteCPermission, + deletePPermission + ], rid); + + this.setState({ + permissions: { + [PERMISSION_SET_READONLY]: result[0], + [PERMISSION_SET_REACT_WHEN_READONLY]: result[1], + [PERMISSION_ARCHIVE]: result[2], + [PERMISSION_UNARCHIVE]: result[3], + [PERMISSION_DELETE_C]: result[4], + [PERMISSION_DELETE_P]: result[5] + } + }); + } } catch (e) { log(e); } @@ -284,13 +315,37 @@ class RoomInfoEditView extends React.Component { }, 100); } + deleteTeam = async(teamName) => { + const { navigation } = this.props; + const { room } = this.state; + try { + const result = await RocketChat.deleteTeam({ teamName }); + if (result.success) { + const db = database.active; + const subCollection = db.get('subscriptions'); + const teamChannels = await subCollection.query( + Q.and(Q.where('team_id', Q.eq(this.room.teamId), Q.where('name', Q.notEq(this.room.name)))) + ); + if (teamChannels.length) { + navigation.navigate('SelectListView', { + title: 'Delete_Team', teamChannels: this.teamChannels, teamName: room.name, subtitle: 'Select_Teams', delete: this.delete + }); + } else { + navigation.navigate('RoomsListView'); + } + } + } catch (e) { + log(e); + } + } + delete = () => { const { room } = this.state; const { deleteRoom } = this.props; Alert.alert( - I18n.t('Are_you_sure_question_mark'), - I18n.t('Delete_Room_Warning'), + I18n.t('Confirmation'), + I18n.t('Delete_Team_Warning'), [ { text: I18n.t('Cancel'), @@ -299,7 +354,7 @@ class RoomInfoEditView extends React.Component { { text: I18n.t('Yes_action_it', { action: I18n.t('delete') }), style: 'destructive', - onPress: () => deleteRoom(room.rid, room.t) + onPress: () => (this.room.teamId ? this.deleteTeam(room.name) : deleteRoom(room.rid, room.t)) } ], { cancelable: false } @@ -678,7 +733,8 @@ const mapStateToProps = state => ({ archiveRoomPermission: state.permissions[PERMISSION_ARCHIVE], unarchiveRoomPermission: state.permissions[PERMISSION_UNARCHIVE], deleteCPermission: state.permissions[PERMISSION_DELETE_C], - deletePPermission: state.permissions[PERMISSION_DELETE_P] + deletePPermission: state.permissions[PERMISSION_DELETE_P], + editTeamChannelPermission: state.permissions[PERMISSION_EDIT_TEAM_CHANNEL] }); const mapDispatchToProps = dispatch => ({ diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 5f21f2aec0..4db265084f 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -71,6 +71,7 @@ class SelectListView extends React.Component { this.subtitle = props.route?.params?.subtitle; this.teamName = props.route?.params?.teamName; this.room = props.route?.params?.room; + this.delete = props.route?.params?.delete; this.state = { data: teamChannels, selected: [], @@ -96,7 +97,7 @@ class SelectListView extends React.Component { options.headerRight = () => ( - + ); From 7ecc76f9b13cceeb5327c51640770c72215245c0 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 7 May 2021 08:08:30 -0400 Subject: [PATCH 19/77] Minor tweak --- app/views/RoomActionsView/index.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 34542bb2e8..9e896ffb39 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -423,6 +423,16 @@ class RoomActionsView extends React.Component { } } catch (e) { log(e); + Alert.alert( + I18n.t('Cannot_leave'), + I18n.t(e.data.error), + [ + { + text: 'OK', + style: 'cancel' + } + ] + ); } } @@ -434,12 +444,12 @@ class RoomActionsView extends React.Component { const db = database.active; const subCollection = db.get('subscriptions'); const teamChannels = await subCollection.query( - Q.where('team_id', Q.eq(room.teamId)) + Q.and(Q.where('team_id', Q.eq(room.teamId)), Q.where('name', Q.notEq(room.name))) ); - if (teamChannels) { + if (teamChannels.length) { navigation.navigate('SelectListView', { - title: 'Leave_Team', room, teamChannels, teamName: room.name + title: 'Leave_Team', room, teamChannels, teamName: room.name, subtitle: 'Select_Teams' }); } else { Alert.alert( From 7e6a277ede4230a10dbca1a195de7f66f2c4084a Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 11 May 2021 07:39:05 -0400 Subject: [PATCH 20/77] 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 9ab5cf215c..df04aa3676 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 f8e96aeb19..eabe218dff 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 45736e337a..d157cc0b60 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 54d70d80b5..2e66869ded 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 6e06b69f05..4dfe17ca3a 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 be3517f97b53368b3c961caaf902ca66b3144d85 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 11 May 2021 07:55:46 -0400 Subject: [PATCH 21/77] Remove unnecesary changes, update TeamChannelsView, AddExistingChannelView, AddChannelTeamView, createChannel, goRoom and Touchable --- .../__snapshots__/Storyshots.test.js.snap | 15445 +++++++--------- app/containers/List/ListItem.js | 3 +- app/containers/LoginServices.js | 5 +- app/containers/Passcode/Base/Button.js | 2 +- app/lib/rocketchat.js | 15 +- app/presentation/RoomItem/RoomItem.js | 3 + app/presentation/RoomItem/Touchable.js | 99 +- app/presentation/RoomItem/index.js | 4 + app/sagas/createChannel.js | 9 +- app/utils/touch.js | 16 +- app/views/AddChannelTeamView.js | 114 +- app/views/AddExistingChannelView.js | 49 +- app/views/DirectoryView/Options.js | 2 +- app/views/DirectoryView/index.js | 2 +- app/views/NewMessageView.js | 4 +- app/views/ProfileView/index.js | 2 +- app/views/RoomActionsView/index.js | 2 +- app/views/SidebarView/SidebarItem.js | 2 +- app/views/TeamChannelsView.js | 2 +- .../Dropdown/DropdownItem.js | 2 +- 20 files changed, 7303 insertions(+), 8479 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 633d5e2abe..f241661f18 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -4154,72 +4154,49 @@ exports[`Storyshots List pressable 1`] = ` } /> - - - Press me - - + Press me + - - - I'm disabled - - + I'm disabled + - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -5749,172 +5680,149 @@ exports[`Storyshots List with bigger font 1`] = ` } /> - - -  - - +  + + + + + Chats + + + All + + + - Chats +  - - All - - - - - -  - - @@ -6008,170 +5916,147 @@ exports[`Storyshots List with bigger font 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -6189,172 +6074,149 @@ exports[`Storyshots List with bigger font 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -6489,170 +6351,147 @@ exports[`Storyshots List with black theme 1`] = ` } /> - - -  - - +  + - + + - - Chats - - - All - - + Chats + + + All + + + - - -  - - +  + @@ -6670,172 +6509,149 @@ exports[`Storyshots List with black theme 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -6929,170 +6745,147 @@ exports[`Storyshots List with black theme 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -7110,172 +6903,149 @@ exports[`Storyshots List with black theme 1`] = ` } /> - - - -  - - - + style={ + Object { + "paddingRight": 12, + } + } + > - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -7423,72 +7193,49 @@ exports[`Storyshots List with custom colors 1`] = ` } /> - - - Press me! - - + Press me! + - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -7774,172 +7498,149 @@ exports[`Storyshots List with dark theme 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -8033,170 +7734,147 @@ exports[`Storyshots List with dark theme 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -8214,172 +7892,149 @@ exports[`Storyshots List with dark theme 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -9806,170 +9461,147 @@ exports[`Storyshots List with small font 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -9987,172 +9619,149 @@ exports[`Storyshots List with small font 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -10246,170 +9855,147 @@ exports[`Storyshots List with small font 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -10427,172 +10013,149 @@ exports[`Storyshots List with small font 1`] = ` } /> - - -  - - - - - Chats - - - All +  + + + + Chats + + + All + + + - - -  - - +  + @@ -44559,46 +44122,119 @@ exports[`Storyshots Room Item Alerts 1`] = ` > - + + + + + +  + + + Read + + + + @@ -44607,7 +44243,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -44620,7 +44256,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -45017,7 +44633,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -45030,7 +44646,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - - - - + + + + + + + + +  + + + Read + + + + @@ -45468,7 +45064,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -45481,7 +45077,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -45919,7 +45495,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -45932,7 +45508,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -46370,7 +45926,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -46383,7 +45939,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - - - - + + + + + + + + +  + + + Read + + + + @@ -46821,7 +46357,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -46834,7 +46370,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -47272,7 +46788,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -47285,7 +46801,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -47723,7 +47219,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -47736,7 +47232,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -48174,7 +47650,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -48187,7 +47663,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - - - - -  - - - Hide - + +  + + + Hide + + - - - + + + + + +  + + + Read + + + + @@ -48625,7 +48081,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -48638,7 +48094,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -49076,7 +48512,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -49089,7 +48525,7 @@ exports[`Storyshots Room Item Alerts 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -49540,7 +48956,7 @@ exports[`Storyshots Room Item Basic 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -49553,7 +48969,7 @@ exports[`Storyshots Room Item Basic 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -49958,7 +49354,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -49971,7 +49367,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -50422,7 +49798,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -50435,7 +49811,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + + + +  + + + Favorite + + @@ -50886,7 +50299,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -50899,7 +50312,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` ] } > -  +  - Read + Hide - - - - -  - - - Favorite - - - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -51350,7 +50686,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -51363,7 +50699,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - - + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + + + + + + + + + + + +  + + + Read + - - - - @@ -51814,7 +51130,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -51827,7 +51143,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -52334,7 +51630,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -52347,7 +51643,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -52854,7 +52130,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -52867,7 +52143,7 @@ exports[`Storyshots Room Item Last Message 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - - - - -`; - -exports[`Storyshots Room Item Type 1`] = ` - - - - + + + + +`; + +exports[`Storyshots Room Item Type 1`] = ` + + + + + + + + +  + + + Read + + + + @@ -53387,7 +52643,7 @@ exports[`Storyshots Room Item Type 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -53400,7 +52656,7 @@ exports[`Storyshots Room Item Type 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -53792,7 +53028,7 @@ exports[`Storyshots Room Item Type 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -53805,7 +53041,7 @@ exports[`Storyshots Room Item Type 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - - - - -  - - - Hide - + +  + + + Hide + + - - - + + + + + +  + + + Read + + + + @@ -54185,7 +53401,7 @@ exports[`Storyshots Room Item Type 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -54198,7 +53414,7 @@ exports[`Storyshots Room Item Type 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -54578,7 +53774,7 @@ exports[`Storyshots Room Item Type 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -54591,7 +53787,7 @@ exports[`Storyshots Room Item Type 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -54971,7 +54147,7 @@ exports[`Storyshots Room Item Type 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -54984,7 +54160,7 @@ exports[`Storyshots Room Item Type 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -55364,7 +54520,7 @@ exports[`Storyshots Room Item Type 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -55377,7 +54533,7 @@ exports[`Storyshots Room Item Type 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -55757,7 +54893,7 @@ exports[`Storyshots Room Item Type 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -55770,7 +54906,7 @@ exports[`Storyshots Room Item Type 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + + + +  + + + Favorite + + @@ -56163,7 +55336,7 @@ exports[`Storyshots Room Item User 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -56176,7 +55349,7 @@ exports[`Storyshots Room Item User 1`] = ` ] } > -  +  - Read + Hide - - - - -  - - - Favorite - - - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -56568,7 +55664,7 @@ exports[`Storyshots Room Item User 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -56581,7 +55677,7 @@ exports[`Storyshots Room Item User 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + + + +  + + + Favorite + + @@ -56986,7 +56119,7 @@ exports[`Storyshots Room Item User status 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -56999,7 +56132,7 @@ exports[`Storyshots Room Item User status 1`] = ` ] } > -  +  - Read + Hide - - - - -  - - - Favorite - - - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -57391,7 +56447,7 @@ exports[`Storyshots Room Item User status 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -57404,7 +56460,7 @@ exports[`Storyshots Room Item User status 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - - - - + + + + + + + + +  + + + Read + + + + @@ -57796,7 +56832,7 @@ exports[`Storyshots Room Item User status 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -57809,7 +56845,7 @@ exports[`Storyshots Room Item User status 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -58201,7 +57217,7 @@ exports[`Storyshots Room Item User status 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -58214,7 +57230,7 @@ exports[`Storyshots Room Item User status 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - - - - + + + + + + + + +  + + + Read + + + + @@ -58606,7 +57602,7 @@ exports[`Storyshots Room Item User status 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -58619,7 +57615,7 @@ exports[`Storyshots Room Item User status 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - - + + + + + +  + + + Read + + + + @@ -59011,7 +57987,7 @@ exports[`Storyshots Room Item User status 1`] = ` style={ Array [ Object { - "color": "white", + "color": "#ffffff", "fontSize": 20, }, undefined, @@ -59024,7 +58000,7 @@ exports[`Storyshots Room Item User status 1`] = ` ] } > -  +  - Read + Favorite - - - - - -  - - - Favorite - + +  + + + Hide + + - -  - - - Hide - - - - - ( onPress(props.title)} - style={({ pressed }) => [{ backgroundColor: pressed ? underlayColor || themes[props.theme].bannerBackground : backgroundColor || themes[props.theme].backgroundColor }]} + style={{ backgroundColor: backgroundColor || themes[props.theme].backgroundColor }} + underlayColor={underlayColor} enabled={!props.disabled} theme={props.theme} > diff --git a/app/containers/LoginServices.js b/app/containers/LoginServices.js index d3f889a8a4..4ae647b5ce 100644 --- a/app/containers/LoginServices.js +++ b/app/containers/LoginServices.js @@ -7,7 +7,6 @@ import { connect } from 'react-redux'; import { Base64 } from 'js-base64'; import * as AppleAuthentication from 'expo-apple-authentication'; -import { transparentize } from 'color2k'; import { withTheme } from '../theme'; import sharedStyles from '../views/Styles'; import { themes } from '../constants/colors'; @@ -345,8 +344,10 @@ class LoginServices extends React.PureComponent { [styles.serviceButton, { backgroundColor: pressed ? transparentize(themes[theme].buttonText, 0.5) : backgroundColor }]} + style={[styles.serviceButton, { backgroundColor }]} theme={theme} + activeOpacity={0.5} + underlayColor={themes[theme].buttonText} > {service.authType === 'oauth' || service.authType === 'apple' ? : null} diff --git a/app/containers/Passcode/Base/Button.js b/app/containers/Passcode/Base/Button.js index 89228cd007..7826ed5fe9 100644 --- a/app/containers/Passcode/Base/Button.js +++ b/app/containers/Passcode/Base/Button.js @@ -14,7 +14,7 @@ const Button = React.memo(({ return ( [styles.buttonView, { backgroundColor: pressed ? 'transparent' : themes[theme].bannerBackground }]} + style={[styles.buttonView, { backgroundColor: 'transparent' }]} underlayColor={themes[theme].passcodeButtonActive} rippleColor={themes[theme].passcodeButtonActive} enabled={!disabled} diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 8697ad59a6..d6b10c540d 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -94,10 +94,19 @@ const RocketChat = { }, canOpenRoom, createChannel({ - name, users, type, readOnly, broadcast, encrypted + name, users, type, readOnly, broadcast, encrypted, teamId }) { - // RC 0.51.0 - return this.methodCallWrapper(type ? 'createPrivateGroup' : 'createChannel', name, users, readOnly, {}, { broadcast, encrypted }); + const params = { + name, + members: users, + readOnly, + extraData: { + broadcast, + encrypted, + ...(teamId && { teamId }) + } + }; + return this.post(type ? 'groups.create' : 'channels.create', params); }, async getWebsocketInfo({ server }) { const sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: useSsl(server) }); diff --git a/app/presentation/RoomItem/RoomItem.js b/app/presentation/RoomItem/RoomItem.js index bfbce938e8..6d8c31c202 100644 --- a/app/presentation/RoomItem/RoomItem.js +++ b/app/presentation/RoomItem/RoomItem.js @@ -24,6 +24,7 @@ const RoomItem = ({ status, useRealName, theme, + isFocused, isGroupChat, isRead, date, @@ -60,6 +61,7 @@ const RoomItem = ({ testID={testID} type={type} theme={theme} + isFocused={isFocused} swipeEnabled={swipeEnabled} > { + if (nativeEvent.state === State.ACTIVE) { + this.onLongPress(); + } + } + _handleRelease = (nativeEvent) => { const { translationX } = nativeEvent; @@ -209,59 +216,65 @@ class Touchable extends React.Component { this.close(); return; } - const { onLongPress } = this.props; - if (onLongPress) { - onLongPress(); + const { onLongPress, onPress } = this.props; + if (!onLongPress) { + onPress(); } + + onLongPress(); }; render() { const { - testID, isRead, width, favorite, children, theme, swipeEnabled + testID, isRead, width, favorite, children, theme, isFocused, swipeEnabled } = this.props; return ( - - + - - - - [{ backgroundColor: pressed ? themes[theme].chatComponentBackground : themes[theme].backgroundColor }]} - > - {children} - - - + + + + + + {children} + + + - + + + ); } } diff --git a/app/presentation/RoomItem/index.js b/app/presentation/RoomItem/index.js index 2815db35d4..fdf74904d4 100644 --- a/app/presentation/RoomItem/index.js +++ b/app/presentation/RoomItem/index.js @@ -14,6 +14,7 @@ const attrs = [ 'status', 'connected', 'theme', + 'isFocused', 'forceUpdate', 'showLastMessage' ]; @@ -36,6 +37,7 @@ class RoomItemContainer extends React.Component { getUserPresence: PropTypes.func, connected: PropTypes.bool, theme: PropTypes.string, + isFocused: PropTypes.bool, getRoomTitle: PropTypes.func, getRoomAvatar: PropTypes.func, getIsGroupChat: PropTypes.func, @@ -127,6 +129,7 @@ class RoomItemContainer extends React.Component { toggleRead, hideChannel, theme, + isFocused, avatarSize, status, showLastMessage, @@ -176,6 +179,7 @@ class RoomItemContainer extends React.Component { type={item.t} theme={theme} size={avatarSize} + isFocused={isFocused} prid={item.prid} status={status} hideUnreadStatus={item.hideUnreadStatus} diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index 795d8fee89..3083c1d7c2 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -71,14 +71,9 @@ const handleRequest = function* handleRequest({ data }) { encrypted }); sub = yield call(createChannel, data); - - if (data.teamId) { + if (sub.teamId) { logEvent(events.CT_ADD_ROOM_TO_TEAM); - const channels = yield call(addTeamRoom, { rooms: sub.rid, teamId: data.teamId }); - if (channels.success) { - sub.teamId = channels.rooms[0].teamId; - sub.isTeamChannel = true; - } + yield call(addTeamRoom, { rooms: sub.rid, teamId: sub.teamId }); } } try { diff --git a/app/utils/touch.js b/app/utils/touch.js index a840c16570..776d2d20ff 100644 --- a/app/utils/touch.js +++ b/app/utils/touch.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { RectButton } from 'react-native-gesture-handler'; -import { Pressable } from 'react-native'; import { themes } from '../constants/colors'; class Touch extends React.Component { @@ -15,21 +15,21 @@ class Touch extends React.Component { render() { const { - children, onPress, onLongPress, theme, style, ...props + children, onPress, theme, underlayColor, ...props } = this.props; return ( - {children} - + ); } } @@ -37,10 +37,8 @@ class Touch extends React.Component { Touch.propTypes = { children: PropTypes.node, onPress: PropTypes.func, - onLongPress: PropTypes.func, theme: PropTypes.string, - underlayColor: PropTypes.string, - style: PropTypes.object + underlayColor: PropTypes.string }; export default Touch; diff --git a/app/views/AddChannelTeamView.js b/app/views/AddChannelTeamView.js index 768048dff7..4e93368963 100644 --- a/app/views/AddChannelTeamView.js +++ b/app/views/AddChannelTeamView.js @@ -1,11 +1,8 @@ -import React from 'react'; -import { View, Text, StyleSheet } from 'react-native'; +import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { HeaderBackButton } from '@react-navigation/stack'; -import sharedStyles from './Styles'; -import { CustomIcon } from '../lib/Icons'; -import Touch from '../utils/touch'; +import * as List from '../containers/List'; import StatusBar from '../containers/StatusBar'; import { withTheme } from '../theme'; import * as HeaderButton from '../containers/HeaderButton'; @@ -14,35 +11,12 @@ import { withDimensions } from '../dimensions'; import { themes } from '../constants/colors'; import I18n from '../i18n'; -const styles = StyleSheet.create({ - button: { - height: 46, - flexDirection: 'row', - alignItems: 'center' - }, - buttonIcon: { - marginLeft: 18, - marginRight: 16 - }, - buttonText: { - fontSize: 17, - ...sharedStyles.textRegular - }, - buttonContainer: { - paddingVertical: 25 - } -}); - -class AddChannelTeamView extends React.Component { - constructor(props) { - super(props); - this.teamId = props.route.params?.teamId; - this.setHeader(); - } - - setHeader = () => { - const { navigation, isMasterDetail, theme } = this.props; +const AddChannelTeamView = ({ + navigation, route, isMasterDetail, theme +}) => { + const { teamId, teamChannels } = route.params; + const setHeader = () => { const options = { headerShown: true, headerTitleAlign: 'center', @@ -62,56 +36,34 @@ class AddChannelTeamView extends React.Component { } navigation.setOptions(options); - } - - renderButton = ({ - onPress, testID, title, icon, first - }) => { - const { theme } = this.props; - - return ( - [{ - backgroundColor: pressed ? themes[theme].chatComponentBackground : themes[theme].backgroundColor - }]} - testID={testID} - theme={theme} - > - - - {title} - - - ); - } + }; - render() { - const { navigation, route } = this.props; - const { teamChannels } = route?.params; + useEffect(() => { + setHeader(); + }, []); - return ( - - - - {this.renderButton({ - onPress: () => navigation.navigate('NewMessageStackNavigator', { screen: 'SelectedUsersViewCreateChannel', params: { nextAction: () => navigation.navigate('CreateChannelView', { teamId: this.teamId }) } }), - title: I18n.t('Create_New'), - icon: 'channel-public', - testID: 'add-channel-team-view-create-channel', - first: true - })} - {this.renderButton({ - onPress: () => navigation.navigate('AddExistingChannelView', { teamId: this.teamId, teamChannels }), - title: I18n.t('Add_Existing'), - icon: 'team', - testID: 'add-channel-team-view-create-channel' - })} - - - ); - } -} + return ( + + + + navigation.navigate('NewMessageStackNavigator', { screen: 'SelectedUsersViewCreateChannel', params: { nextAction: () => navigation.navigate('CreateChannelView', { teamId }) } })} + testID='add-channel-team-view-create-channel' + left={() => } + theme={theme} + /> + navigation.navigate('AddExistingChannelView', { teamId, teamChannels })} + testID='add-channel-team-view-create-channel' + left={() => } + theme={theme} + /> + + + ); +}; AddChannelTeamView.propTypes = { route: PropTypes.object, diff --git a/app/views/AddExistingChannelView.js b/app/views/AddExistingChannelView.js index 6f6087fd9a..527fd57180 100644 --- a/app/views/AddExistingChannelView.js +++ b/app/views/AddExistingChannelView.js @@ -2,21 +2,18 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - View, StyleSheet, FlatList, Text + View, FlatList } from 'react-native'; import { connect } from 'react-redux'; import { Q } from '@nozbe/watermelondb'; import { HeaderBackButton } from '@react-navigation/stack'; import * as List from '../containers/List'; -import Touch from '../utils/touch'; import database from '../lib/database'; import RocketChat from '../lib/rocketchat'; -import sharedStyles from './Styles'; import I18n from '../i18n'; import log, { events, logEvent } from '../utils/log'; import SearchBox from '../containers/SearchBox'; -import { CustomIcon } from '../lib/Icons'; import * as HeaderButton from '../containers/HeaderButton'; import StatusBar from '../containers/StatusBar'; import { themes } from '../constants/colors'; @@ -28,32 +25,6 @@ import Loading from '../containers/Loading'; const QUERY_SIZE = 15; -const styles = StyleSheet.create({ - button: { - height: 46, - flexDirection: 'row', - alignItems: 'center' - }, - buttonIcon: { - marginLeft: 18, - marginRight: 16 - }, - buttonText: { - fontSize: 17, - ...sharedStyles.textRegular - }, - textContainer: { - flex: 1, - flexDirection: 'column', - justifyContent: 'center', - marginRight: 15 - }, - icon: { - marginHorizontal: 15, - alignSelf: 'center' - } -}); - class AddExistingChannelView extends React.Component { static propTypes = { navigation: PropTypes.object, @@ -170,20 +141,16 @@ class AddExistingChannelView extends React.Component { }) => { const { theme } = this.props; return ( - } + right={() => (checked ? : null)} theme={theme} - > - - - - {title} - - {checked ? : null} - - + /> + ); } diff --git a/app/views/DirectoryView/Options.js b/app/views/DirectoryView/Options.js index d7af8776b7..ad8de1da18 100644 --- a/app/views/DirectoryView/Options.js +++ b/app/views/DirectoryView/Options.js @@ -67,7 +67,7 @@ export default class DirectoryOptions extends PureComponent { return ( changeType(itemType)} - style={({ pressed }) => [{ backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor }, styles.dropdownItemButton]} + style={styles.dropdownItemButton} theme={theme} > diff --git a/app/views/DirectoryView/index.js b/app/views/DirectoryView/index.js index 06678620b5..f78e74a21f 100644 --- a/app/views/DirectoryView/index.js +++ b/app/views/DirectoryView/index.js @@ -169,7 +169,7 @@ class DirectoryView extends React.Component { /> [{ backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor }, styles.dropdownItemButton]} + style={styles.dropdownItemButton} testID='directory-view-dropdown' theme={theme} > diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index c538a43215..5e4ef1c99e 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -148,9 +148,7 @@ class NewMessageView extends React.Component { return ( [{ - backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor - }]} + style={{ backgroundColor: themes[theme].backgroundColor }} testID={testID} theme={theme} > diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js index 1adb555baa..7e97422df2 100644 --- a/app/views/ProfileView/index.js +++ b/app/views/ProfileView/index.js @@ -309,7 +309,7 @@ class ProfileView extends React.Component { key={key} testID={key} onPress={onPress} - style={({ pressed }) => [styles.avatarButton, { opacity: disabled ? 0.5 : 1 }, { backgroundColor: pressed ? themes[theme].borderColor : themes[theme].bannerBackground }]} + style={[styles.avatarButton, { opacity: disabled ? 0.5 : 1 }, { backgroundColor: themes[theme].borderColor }]} enabled={!disabled} theme={theme} > diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 2e5788a23b..ea833d7588 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -433,7 +433,7 @@ class RoomActionsView extends React.Component { rid, t, room, member } })} - style={({ pressed }) => [{ backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor }]} + style={{ backgroundColor: themes[theme].backgroundColor }} accessibilityLabel={I18n.t('Room_Info')} accessibilityTraits='button' enabled={!isGroupChat} diff --git a/app/views/SidebarView/SidebarItem.js b/app/views/SidebarView/SidebarItem.js index 4315f9cdac..7959438c28 100644 --- a/app/views/SidebarView/SidebarItem.js +++ b/app/views/SidebarView/SidebarItem.js @@ -15,7 +15,7 @@ const Item = React.memo(({ testID={testID} onPress={onPress} theme={theme} - style={({ pressed }) => [styles.item, current && { backgroundColor: pressed ? themes[theme].borderColor : themes[theme].bannerBackground }]} + style={[styles.item, current && { backgroundColor: themes[theme].borderColor }]} > {left} diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 70b8c2c443..f644a8ef35 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -220,10 +220,10 @@ class TeamChannelsView extends React.Component { options.headerRight = () => ( - { showCreate ? navigation.navigate('AddChannelTeamView', { teamId: this.teamId, teamChannels: data })} /> : null} + ); navigation.setOptions(options); diff --git a/app/views/ThreadMessagesView/Dropdown/DropdownItem.js b/app/views/ThreadMessagesView/Dropdown/DropdownItem.js index 38b66074aa..4ebca91688 100644 --- a/app/views/ThreadMessagesView/Dropdown/DropdownItem.js +++ b/app/views/ThreadMessagesView/Dropdown/DropdownItem.js @@ -26,7 +26,7 @@ const styles = StyleSheet.create({ const DropdownItem = React.memo(({ theme, onPress, iconName, text }) => ( - [{ backgroundColor: pressed ? themes[theme].bannerBackground : themes[theme].backgroundColor }]}> + {text} {iconName ? : null} From d0f95603cca382e395c3c9d6e3956f2015d685be Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 11 May 2021 08:59:03 -0400 Subject: [PATCH 22/77] Remove unnecesary prop --- app/views/SelectListView.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 4e5768e65f..236412446e 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -66,7 +66,6 @@ class SelectListView extends React.Component { const teamChannels = props.route?.params?.teamChannels; this.title = props.route?.params?.title; this.teamName = props.route?.params?.teamName; - this.room = props.route?.params?.room; this.state = { data: teamChannels, selected: [], From 2d50417fe04466d1505136f62ca10cfd4a9247dc Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 13 May 2021 09:25:56 -0400 Subject: [PATCH 23/77] Add screens to ModalStack, events, autoJoin, update createChannel, addRoomsToTeam and Touchable --- app/lib/rocketchat.js | 8 +++-- app/presentation/RoomItem/Chip.js | 27 ++++++++++++++++ app/presentation/RoomItem/RoomItem.js | 10 ++++-- app/presentation/RoomItem/Touchable.js | 23 +++++++++----- app/presentation/RoomItem/index.js | 7 ++-- app/sagas/createChannel.js | 6 ++-- app/stacks/MasterDetailStack/index.js | 12 +++++++ app/utils/log/events.js | 4 +++ app/views/AddExistingChannelView.js | 7 ++-- app/views/TeamChannelsView.js | 44 +++++++++++++++++++++++--- 10 files changed, 123 insertions(+), 25 deletions(-) create mode 100644 app/presentation/RoomItem/Chip.js diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 26e8c11b6a..98bf4de401 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -760,9 +760,9 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.create', params); }, - addTeamRooms({ rooms, teamId }) { + addRoomsToTeam({ rooms, teamId }) { const params = { - rooms: Array.isArray(rooms) ? rooms : [rooms], + rooms, teamId }; // RC 3.13.0 @@ -772,6 +772,10 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.removeRoom', { roomId, teamId }); }, + updateTeamRoom({ roomId, isDefault }) { + // RC 3.13.0 + return this.post('teams.updateRoom', { roomId, isDefault }); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/presentation/RoomItem/Chip.js b/app/presentation/RoomItem/Chip.js new file mode 100644 index 0000000000..289f6909de --- /dev/null +++ b/app/presentation/RoomItem/Chip.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { Text, View } from 'react-native'; +import PropTypes from 'prop-types'; + +import styles from './styles'; +import { themes } from '../../constants/colors'; + +const Chip = React.memo(({ name, theme }) => ( + + + {name} + + +)); + +Chip.propTypes = { + name: PropTypes.string, + theme: PropTypes.string +}; + +export default Chip; diff --git a/app/presentation/RoomItem/RoomItem.js b/app/presentation/RoomItem/RoomItem.js index 6d8c31c202..0ac7496c05 100644 --- a/app/presentation/RoomItem/RoomItem.js +++ b/app/presentation/RoomItem/RoomItem.js @@ -10,6 +10,7 @@ import LastMessage from './LastMessage'; import Title from './Title'; import UpdatedAt from './UpdatedAt'; import Touchable from './Touchable'; +import Chip from './Chip'; const RoomItem = ({ rid, @@ -46,7 +47,8 @@ const RoomItem = ({ toggleFav, toggleRead, hideChannel, - teamMain + teamMain, + autoJoin }) => ( + { + autoJoin ? : null + } { @@ -61,6 +64,10 @@ class Touchable extends React.Component { } onLongPressHandlerStateChange = ({ nativeEvent }) => { + const { onLongPress } = this.props; + if (!onLongPress) { + return null; + } if (nativeEvent.state === State.ACTIVE) { this.onLongPress(); } @@ -212,16 +219,15 @@ class Touchable extends React.Component { onLongPress = () => { const { rowState } = this.state; - if (rowState !== 0) { + const { onLongPress } = this.props; + if (rowState !== 0 || !onLongPress) { this.close(); return; } - const { onLongPress, onPress } = this.props; - if (!onLongPress) { - onPress(); - } - onLongPress(); + if (onLongPress) { + onLongPress(); + } }; render() { @@ -230,9 +236,10 @@ class Touchable extends React.Component { } = this.props; return ( - + ); } diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index cc396bf078..ba7bd4e66b 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -25,8 +25,8 @@ const createTeam = function createTeam(data) { return RocketChat.createTeam(data); }; -const addTeamRoom = function addRoomToTeam(params) { - return RocketChat.addTeamRooms(params); +const addRoomsToTeam = function addRoomsToTeam(params) { + return RocketChat.addRoomsToTeam(params); }; const handleRequest = function* handleRequest({ data }) { @@ -73,7 +73,7 @@ const handleRequest = function* handleRequest({ data }) { sub = yield call(createChannel, data); if (sub.teamId) { logEvent(events.CT_ADD_ROOM_TO_TEAM); - yield call(addTeamRoom, { rooms: sub.rid, teamId: sub.teamId }); + yield call(addRoomsToTeam, { rooms: sub.rid, teamId: sub.teamId }); } } try { diff --git a/app/stacks/MasterDetailStack/index.js b/app/stacks/MasterDetailStack/index.js index 7307ba6cae..3ce0130a3d 100644 --- a/app/stacks/MasterDetailStack/index.js +++ b/app/stacks/MasterDetailStack/index.js @@ -61,6 +61,8 @@ import { setKeyCommands, deleteKeyCommands } from '../../commands'; import ShareView from '../../views/ShareView'; import QueueListView from '../../ee/omnichannel/views/QueueListView'; +import AddChannelTeamView from '../../views/AddChannelTeamView'; +import AddExistingChannelView from '../../views/AddExistingChannelView'; // ChatsStackNavigator const ChatsStack = createStackNavigator(); @@ -141,6 +143,16 @@ const ModalStackNavigator = React.memo(({ navigation }) => { component={InviteUsersView} options={InviteUsersView.navigationOptions} /> + + { try { const { addTeamChannelPermission } = this.props; @@ -84,7 +83,7 @@ class AddExistingChannelView extends React.Component { const channels = await db.collections .get('subscriptions') .query( - Q.and(Q.where('team_id', ''), Q.or(Q.where('t', 'c'), Q.where('t', 'p'))), + Q.and(Q.where('team_id', null), Q.or(Q.where('t', 'c'), Q.where('t', 'p'))), Q.experimentalTake(QUERY_SIZE), Q.experimentalSortBy('room_updated_at', Q.desc) ) @@ -173,10 +172,10 @@ class AddExistingChannelView extends React.Component { animateNextTransition(); if (!this.isChecked(rid)) { - // logEvent(events.SELECTED_USERS_ADD_USER); + logEvent(events.EXISTING_CHANNEL_ADD_CHANNEL); this.setState({ selected: [...selected, rid] }, () => this.setHeader()); } else { - // logEvent(events.SELECTED_USERS_REMOVE_USER); + logEvent(events.EXISTING_CHANNEL_REMOVE_CHANNEL); const filterSelected = selected.filter(el => el !== rid); this.setState({ selected: filterSelected }, () => this.setHeader()); } diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index f644a8ef35..8cf367bc53 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -68,7 +68,8 @@ class TeamChannelsView extends React.Component { searchText: '', search: [], end: false, - showCreate: false + showCreate: false, + autoJoin: [] }; this.loadTeam(); this.setHeader(); @@ -88,7 +89,9 @@ class TeamChannelsView extends React.Component { this.teamChannels = await subCollection.query( Q.where('team_id', Q.eq(this.teamId)) ); - this.team = this.teamChannels?.find(channel => channel.teamMain); + this.team = this.teamChannels?.find(channel => channel.teamMain && channel.rid === this.rid); + const filterAutoJoin = this.teamChannels.filter(channel => channel.teamMain); + this.setState({ autoJoin: filterAutoJoin }); this.setHeader(); if (!this.team) { @@ -307,8 +310,8 @@ class TeamChannelsView extends React.Component { options = item => ([ { title: I18n.t('Auto-join'), - icon: item.t === 'p' ? 'channel-private' : 'channel-public' - // onPress: this.autoJoin + icon: item.t === 'p' ? 'channel-private' : 'channel-public', + onPress: () => this.autoJoin(item) }, { title: I18n.t('Remove_from_Team'), @@ -324,6 +327,37 @@ class TeamChannelsView extends React.Component { } ]) + autoJoin = async(item) => { + try { + const result = await RocketChat.updateTeamRoom({ roomId: item.rid, isDefault: !item.teamMain }); + if (result.success) { + this.toggleAutoJoin(item); + this.setState({ loading: true }, () => { + this.load(); + this.loadTeam(); + }); + } + } catch (e) { + log(e); + } + } + + isAutoJoin = (item) => { + const { autoJoin } = this.state; + return autoJoin.includes(item); + } + + toggleAutoJoin = (item) => { + const { autoJoin } = this.state; + + if (!this.isChecked(item)) { + this.setState({ autoJoin: [...autoJoin, item] }); + } else { + const filterSelected = autoJoin.filter(el => el.rid !== item.rid); + this.setState({ autoJoin: filterSelected }); + } + } + remove = (item) => { Alert.alert( I18n.t('Confirmation'), @@ -398,6 +432,7 @@ class TeamChannelsView extends React.Component { theme, width } = this.props; + const { autoJoin } = this.state; return ( ); }; From 79b1123631ec838a4fcfedb74c70648ba186b727 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 13 May 2021 09:43:29 -0400 Subject: [PATCH 24/77] Minor tweak --- app/presentation/RoomItem/Touchable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/presentation/RoomItem/Touchable.js b/app/presentation/RoomItem/Touchable.js index d283319d5e..96c6cac6e6 100644 --- a/app/presentation/RoomItem/Touchable.js +++ b/app/presentation/RoomItem/Touchable.js @@ -220,7 +220,7 @@ class Touchable extends React.Component { onLongPress = () => { const { rowState } = this.state; const { onLongPress } = this.props; - if (rowState !== 0 || !onLongPress) { + if (rowState !== 0) { this.close(); return; } From 70e503ac8e731e48c193f4941bf93ea689ecd4f5 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 13 May 2021 10:04:40 -0400 Subject: [PATCH 25/77] Update loadMessagesForRoom.js --- app/lib/methods/loadMessagesForRoom.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js index df04aa3676..2e6c0e2e6c 100644 --- a/app/lib/methods/loadMessagesForRoom.js +++ b/app/lib/methods/loadMessagesForRoom.js @@ -1,17 +1,14 @@ 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 []; From f42988a511de369d616059312c7133c6b9384f01 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 14 May 2021 01:09:43 -0400 Subject: [PATCH 26/77] Updated schema, tag component, touch, AddChannelTeamView, AddExistingChannelView, ActionSheet Item --- .../__snapshots__/Storyshots.test.js.snap | 385 ++++++++++++++++++ app/containers/ActionSheet/Item.js | 24 +- app/lib/database/model/Subscription.js | 2 + app/lib/database/model/migrations.js | 11 + app/lib/database/schema/app.js | 5 +- .../helpers/mergeSubscriptionsRooms.js | 1 + app/lib/methods/loadMessagesForRoom.js | 2 - app/presentation/RoomItem/Chip.js | 27 -- app/presentation/RoomItem/RoomItem.js | 4 +- app/presentation/RoomItem/Tag.js | 35 ++ app/presentation/RoomItem/Touchable.js | 8 +- app/sagas/createChannel.js | 2 +- app/utils/goRoom.js | 4 +- app/utils/touch.js | 1 - app/views/AddChannelTeamView.js | 66 +-- app/views/AddExistingChannelView.js | 6 +- app/views/TeamChannelsView.js | 49 +-- storybook/stories/RoomItem.js | 3 +- 18 files changed, 510 insertions(+), 125 deletions(-) delete mode 100644 app/presentation/RoomItem/Chip.js create mode 100644 app/presentation/RoomItem/Tag.js diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index f241661f18..ff3d8e24b5 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -55927,6 +55927,391 @@ exports[`Storyshots Room Item User 1`] = ` + + + + + + +  + + + Read + + + + + + + +  + + + Favorite + + + + +  + + + Hide + + + + + + + + + + + + + +  + + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + + + + + `; diff --git a/app/containers/ActionSheet/Item.js b/app/containers/ActionSheet/Item.js index 7cd5e7b4d8..cf4299aff3 100644 --- a/app/containers/ActionSheet/Item.js +++ b/app/containers/ActionSheet/Item.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Text } from 'react-native'; +import { Text, View } from 'react-native'; import { themes } from '../../constants/colors'; import { CustomIcon } from '../../lib/Icons'; @@ -20,12 +20,19 @@ export const Item = React.memo(({ item, hide, theme }) => { theme={theme} > - - {item.title} - + + + {item.title} + + + { item.right ? ( + + {item.right ? item.right() : null} + + ) : null } ); }); @@ -34,7 +41,8 @@ Item.propTypes = { title: PropTypes.string, icon: PropTypes.string, danger: PropTypes.bool, - onPress: PropTypes.func + onPress: PropTypes.func, + right: PropTypes.func }), hide: PropTypes.func, theme: PropTypes.string diff --git a/app/lib/database/model/Subscription.js b/app/lib/database/model/Subscription.js index 5b1ebd1411..5a332fa1a1 100644 --- a/app/lib/database/model/Subscription.js +++ b/app/lib/database/model/Subscription.js @@ -129,4 +129,6 @@ export default class Subscription extends Model { @field('team_id') teamId; @field('team_main') teamMain; + + @field('team_default') teamDefault; } diff --git a/app/lib/database/model/migrations.js b/app/lib/database/model/migrations.js index cdc65ef0f7..17a8aa894c 100644 --- a/app/lib/database/model/migrations.js +++ b/app/lib/database/model/migrations.js @@ -224,6 +224,17 @@ export default schemaMigrations({ ] }) ] + }, + { + toVersion: 14, + steps: [ + addColumns({ + table: 'subscriptions', + columns: [ + { name: 'team_default', type: 'boolean', isOptional: true } + ] + }) + ] } ] }); diff --git a/app/lib/database/schema/app.js b/app/lib/database/schema/app.js index 883e6dfd96..0a51951b0f 100644 --- a/app/lib/database/schema/app.js +++ b/app/lib/database/schema/app.js @@ -1,7 +1,7 @@ import { appSchema, tableSchema } from '@nozbe/watermelondb'; export default appSchema({ - version: 13, + version: 14, tables: [ tableSchema({ name: 'subscriptions', @@ -59,7 +59,8 @@ export default appSchema({ { name: 'e2e_key_id', type: 'string', isOptional: true }, { name: 'avatar_etag', type: 'string', isOptional: true }, { name: 'team_id', type: 'string', isIndexed: true }, - { name: 'team_main', type: 'boolean', isOptional: true } + { name: 'team_main', type: 'boolean', isOptional: true }, + { name: 'team_default', type: 'boolean', isOptional: true } ] }), tableSchema({ diff --git a/app/lib/methods/helpers/mergeSubscriptionsRooms.js b/app/lib/methods/helpers/mergeSubscriptionsRooms.js index 82dfc4c68d..b8e5fdf983 100644 --- a/app/lib/methods/helpers/mergeSubscriptionsRooms.js +++ b/app/lib/methods/helpers/mergeSubscriptionsRooms.js @@ -44,6 +44,7 @@ export const merge = (subscription, room) => { subscription.avatarETag = room.avatarETag; subscription.teamId = room.teamId; subscription.teamMain = room.teamMain; + subscription.teamDefault = room.teamDefault; if (!subscription.roles || !subscription.roles.length) { subscription.roles = []; } diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js index 2e6c0e2e6c..012e1ea327 100644 --- a/app/lib/methods/loadMessagesForRoom.js +++ b/app/lib/methods/loadMessagesForRoom.js @@ -3,13 +3,11 @@ import updateMessages from './updateMessages'; async function load({ rid: roomId, latest, t }) { let params = { roomId, count: 50 }; - if (latest) { params = { ...params, latest: new Date(latest).toISOString() }; } const apiType = this.roomTypeToApiType(t); - if (!apiType) { return []; } diff --git a/app/presentation/RoomItem/Chip.js b/app/presentation/RoomItem/Chip.js deleted file mode 100644 index 289f6909de..0000000000 --- a/app/presentation/RoomItem/Chip.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { Text, View } from 'react-native'; -import PropTypes from 'prop-types'; - -import styles from './styles'; -import { themes } from '../../constants/colors'; - -const Chip = React.memo(({ name, theme }) => ( - - - {name} - - -)); - -Chip.propTypes = { - name: PropTypes.string, - theme: PropTypes.string -}; - -export default Chip; diff --git a/app/presentation/RoomItem/RoomItem.js b/app/presentation/RoomItem/RoomItem.js index 0ac7496c05..885980dae5 100644 --- a/app/presentation/RoomItem/RoomItem.js +++ b/app/presentation/RoomItem/RoomItem.js @@ -10,7 +10,7 @@ import LastMessage from './LastMessage'; import Title from './Title'; import UpdatedAt from './UpdatedAt'; import Touchable from './Touchable'; -import Chip from './Chip'; +import Tag from './Tag'; const RoomItem = ({ rid, @@ -93,7 +93,7 @@ const RoomItem = ({ alert={alert} /> { - autoJoin ? : null + autoJoin ? : null } { + const { theme } = useTheme(); + + return ( + + + {name} + + + ); +}); + +Tag.propTypes = { + name: PropTypes.string +}; + +export default Tag; diff --git a/app/presentation/RoomItem/Touchable.js b/app/presentation/RoomItem/Touchable.js index 96c6cac6e6..bbf7cbf860 100644 --- a/app/presentation/RoomItem/Touchable.js +++ b/app/presentation/RoomItem/Touchable.js @@ -54,7 +54,6 @@ class Touchable extends React.Component { [{ nativeEvent: { translationX: this.dragX } }], { useNativeDriver: true } ); this._value = 0; - this.panRef = React.createRef(); } _onHandlerStateChange = ({ nativeEvent }) => { @@ -64,10 +63,6 @@ class Touchable extends React.Component { } onLongPressHandlerStateChange = ({ nativeEvent }) => { - const { onLongPress } = this.props; - if (!onLongPress) { - return null; - } if (nativeEvent.state === State.ACTIVE) { this.onLongPress(); } @@ -236,10 +231,9 @@ class Touchable extends React.Component { } = this.props; return ( - + { } 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, diff --git a/app/utils/touch.js b/app/utils/touch.js index 776d2d20ff..d5c22d4df1 100644 --- a/app/utils/touch.js +++ b/app/utils/touch.js @@ -23,7 +23,6 @@ class Touch extends React.Component { ref={this.getRef} onPress={onPress} activeOpacity={1} - android_ripple={{ color: themes[theme].bannerBackground }} underlayColor={underlayColor || themes[theme].bannerBackground} rippleColor={themes[theme].bannerBackground} {...props} diff --git a/app/views/AddChannelTeamView.js b/app/views/AddChannelTeamView.js index 4e93368963..b57e198e3c 100644 --- a/app/views/AddChannelTeamView.js +++ b/app/views/AddChannelTeamView.js @@ -1,65 +1,69 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { HeaderBackButton } from '@react-navigation/stack'; +import { connect } from 'react-redux'; import * as List from '../containers/List'; import StatusBar from '../containers/StatusBar'; -import { withTheme } from '../theme'; +import { useTheme } from '../theme'; import * as HeaderButton from '../containers/HeaderButton'; import SafeAreaView from '../containers/SafeAreaView'; -import { withDimensions } from '../dimensions'; import { themes } from '../constants/colors'; import I18n from '../i18n'; -const AddChannelTeamView = ({ - navigation, route, isMasterDetail, theme -}) => { - const { teamId, teamChannels } = route.params; +const setHeader = (navigation, isMasterDetail, theme) => { + const options = { + headerTitle: I18n.t('Add_Channel_to_Team') + }; - const setHeader = () => { - const options = { - headerShown: true, - headerTitleAlign: 'center', - headerTitle: I18n.t('Add_Channel_to_Team') - }; + if (isMasterDetail) { + options.headerLeft = () => ; + } else { + options.headerLeft = () => ( + navigation.pop()} + tintColor={themes[theme].headerTintColor} + /> + ); + } - if (isMasterDetail) { - options.headerLeft = () => ; - } else { - options.headerLeft = () => ( - navigation.pop()} - tintColor={themes[theme].headerTintColor} - /> - ); - } + navigation.setOptions(options); +}; - navigation.setOptions(options); - }; +const AddChannelTeamView = ({ + navigation, route, isMasterDetail +}) => { + const { teamId, teamChannels } = route.params; + const { theme } = useTheme(); useEffect(() => { - setHeader(); + setHeader(navigation, isMasterDetail, theme); }, []); return ( + navigation.navigate('NewMessageStackNavigator', { screen: 'SelectedUsersViewCreateChannel', params: { nextAction: () => navigation.navigate('CreateChannelView', { teamId }) } })} testID='add-channel-team-view-create-channel' left={() => } + right={() => } theme={theme} /> + navigation.navigate('AddExistingChannelView', { teamId, teamChannels })} testID='add-channel-team-view-create-channel' left={() => } + right={() => } theme={theme} /> + ); @@ -68,8 +72,12 @@ const AddChannelTeamView = ({ AddChannelTeamView.propTypes = { route: PropTypes.object, navigation: PropTypes.object, - isMasterDetail: PropTypes.bool, - theme: PropTypes.string + isMasterDetail: PropTypes.bool }; -export default withDimensions(withTheme(AddChannelTeamView)); +const mapStateToProps = state => ({ + isMasterDetail: state.app.isMasterDetail +}); + + +export default connect(mapStateToProps)(AddChannelTeamView); diff --git a/app/views/AddExistingChannelView.js b/app/views/AddExistingChannelView.js index d70febf4d0..d230607572 100644 --- a/app/views/AddExistingChannelView.js +++ b/app/views/AddExistingChannelView.js @@ -7,8 +7,8 @@ import { import { connect } from 'react-redux'; import { Q } from '@nozbe/watermelondb'; import { HeaderBackButton } from '@react-navigation/stack'; -import * as List from '../containers/List'; +import * as List from '../containers/List'; import database from '../lib/database'; import RocketChat from '../lib/rocketchat'; import I18n from '../i18n'; @@ -23,7 +23,7 @@ import { animateNextTransition } from '../utils/layoutAnimation'; import { goRoom } from '../utils/goRoom'; import Loading from '../containers/Loading'; -const QUERY_SIZE = 15; +const QUERY_SIZE = 50; class AddExistingChannelView extends React.Component { static propTypes = { @@ -83,7 +83,7 @@ class AddExistingChannelView extends React.Component { const channels = await db.collections .get('subscriptions') .query( - Q.and(Q.where('team_id', null), Q.or(Q.where('t', 'c'), Q.where('t', 'p'))), + Q.and(Q.where('team_id', ''), Q.or(Q.where('t', 'c'), Q.where('t', 'p'))), Q.experimentalTake(QUERY_SIZE), Q.experimentalSortBy('room_updated_at', Q.desc) ) diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 8cf367bc53..2a95476188 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -5,7 +5,6 @@ import { Q } from '@nozbe/watermelondb'; import { withSafeAreaInsets } from 'react-native-safe-area-context'; import { connect } from 'react-redux'; import { FlatList } from 'react-native-gesture-handler'; -import { HeaderBackButton } from '@react-navigation/stack'; import StatusBar from '../containers/StatusBar'; import RoomHeader from '../containers/RoomHeader'; @@ -23,13 +22,13 @@ import RoomItem, { ROW_HEIGHT } from '../presentation/RoomItem'; import RocketChat from '../lib/rocketchat'; import { withDimensions } from '../dimensions'; import { isIOS } from '../utils/deviceInfo'; -import { themes } from '../constants/colors'; import debounce from '../utils/debounce'; import { showErrorAlert } from '../utils/info'; import { goRoom } from '../utils/goRoom'; import I18n from '../i18n'; import { withActionSheet } from '../containers/ActionSheet'; import { deleteRoom as deleteRoomAction } from '../actions/room'; +import { CustomIcon } from '../lib/Icons'; const API_FETCH_COUNT = 25; @@ -68,8 +67,7 @@ class TeamChannelsView extends React.Component { searchText: '', search: [], end: false, - showCreate: false, - autoJoin: [] + showCreate: false }; this.loadTeam(); this.setHeader(); @@ -89,9 +87,7 @@ class TeamChannelsView extends React.Component { this.teamChannels = await subCollection.query( Q.where('team_id', Q.eq(this.teamId)) ); - this.team = this.teamChannels?.find(channel => channel.teamMain && channel.rid === this.rid); - const filterAutoJoin = this.teamChannels.filter(channel => channel.teamMain); - this.setState({ autoJoin: filterAutoJoin }); + this.team = this.teamChannels?.find(channel => channel.teamMain); this.setHeader(); if (!this.team) { @@ -160,9 +156,7 @@ class TeamChannelsView extends React.Component { setHeader = () => { const { isSearching, showCreate, data } = this.state; - const { - navigation, isMasterDetail, insets, theme - } = this.props; + const { navigation, isMasterDetail, insets } = this.props; const { team } = this; if (!team) { @@ -211,14 +205,6 @@ class TeamChannelsView extends React.Component { if (isMasterDetail) { options.headerLeft = () => ; - } else { - options.headerLeft = () => ( - navigation.pop()} - tintColor={themes[theme].headerTintColor} - /> - ); } options.headerRight = () => ( @@ -311,7 +297,8 @@ class TeamChannelsView extends React.Component { { title: I18n.t('Auto-join'), icon: item.t === 'p' ? 'channel-private' : 'channel-public', - onPress: () => this.autoJoin(item) + onPress: () => this.autoJoin(item), + right: () => (item.teamDefault ? : null) }, { title: I18n.t('Remove_from_Team'), @@ -329,9 +316,9 @@ class TeamChannelsView extends React.Component { autoJoin = async(item) => { try { - const result = await RocketChat.updateTeamRoom({ roomId: item.rid, isDefault: !item.teamMain }); + const result = await RocketChat.updateTeamRoom({ roomId: item.rid, isDefault: !item.teamDefault }); + if (result.success) { - this.toggleAutoJoin(item); this.setState({ loading: true }, () => { this.load(); this.loadTeam(); @@ -342,22 +329,6 @@ class TeamChannelsView extends React.Component { } } - isAutoJoin = (item) => { - const { autoJoin } = this.state; - return autoJoin.includes(item); - } - - toggleAutoJoin = (item) => { - const { autoJoin } = this.state; - - if (!this.isChecked(item)) { - this.setState({ autoJoin: [...autoJoin, item] }); - } else { - const filterSelected = autoJoin.filter(el => el.rid !== item.rid); - this.setState({ autoJoin: filterSelected }); - } - } - remove = (item) => { Alert.alert( I18n.t('Confirmation'), @@ -432,7 +403,7 @@ class TeamChannelsView extends React.Component { theme, width } = this.props; - const { autoJoin } = this.state; + return ( ); }; diff --git a/storybook/stories/RoomItem.js b/storybook/stories/RoomItem.js index d39e92082f..eb053cdf92 100644 --- a/storybook/stories/RoomItem.js +++ b/storybook/stories/RoomItem.js @@ -3,7 +3,6 @@ import React from 'react'; import { ScrollView, Dimensions } from 'react-native'; import { storiesOf } from '@storybook/react-native'; import { Provider } from 'react-redux'; -// import moment from 'moment'; import { themes } from '../../app/constants/colors'; import RoomItemComponent from '../../app/presentation/RoomItem/RoomItem'; @@ -45,13 +44,13 @@ stories.add('Basic', () => ( )); - stories.add('User', () => ( <> + )); From 9820e6e6d19c4c6995e279d0d8f0f9ebc27b2042 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 14 May 2021 08:59:36 -0400 Subject: [PATCH 27/77] Fix unnecessary changes --- app/presentation/RoomItem/index.js | 2 +- app/views/RoomsListView/index.js | 2 ++ app/views/TeamChannelsView.js | 1 - storybook/stories/RoomItem.js | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/presentation/RoomItem/index.js b/app/presentation/RoomItem/index.js index aca966cedc..4818cb2edb 100644 --- a/app/presentation/RoomItem/index.js +++ b/app/presentation/RoomItem/index.js @@ -180,8 +180,8 @@ class RoomItemContainer extends React.Component { testID={testID} type={item.t} theme={theme} - size={avatarSize} isFocused={isFocused} + size={avatarSize} prid={item.prid} status={status} hideUnreadStatus={item.hideUnreadStatus} diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 662a82e99f..19df2c3b0f 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -894,6 +894,7 @@ class RoomsListView extends React.Component { return this.renderSectionHeader(item.rid); } + const { item: currentItem } = this.state; const { user: { username }, StoreLastMessage, @@ -924,6 +925,7 @@ class RoomsListView extends React.Component { getIsGroupChat={this.isGroupChat} getIsRead={this.isRead} visitor={item.visitor} + isFocused={currentItem?.rid === item.rid} /> ); }; diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 2a95476188..139081bf10 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -403,7 +403,6 @@ class TeamChannelsView extends React.Component { theme, width } = this.props; - return ( ( )); + stories.add('User', () => ( <> From 682dd21f092fd1a1cc10bd8484aaf1d1ed12b5d7 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 14 May 2021 13:18:58 -0400 Subject: [PATCH 28/77] Add i18n, update createChannel, AddExistingChannelTeamView, AddChannelTeamView, RightButton and TeamChannelsView --- app/presentation/RoomItem/RoomItem.js | 3 ++- app/sagas/createChannel.js | 19 +++++++++---------- app/views/AddChannelTeamView.js | 13 +------------ app/views/AddExistingChannelView.js | 13 +++---------- app/views/RoomView/RightButtons.js | 4 ++-- app/views/TeamChannelsView.js | 6 +++--- 6 files changed, 20 insertions(+), 38 deletions(-) diff --git a/app/presentation/RoomItem/RoomItem.js b/app/presentation/RoomItem/RoomItem.js index 885980dae5..f934a811dc 100644 --- a/app/presentation/RoomItem/RoomItem.js +++ b/app/presentation/RoomItem/RoomItem.js @@ -11,6 +11,7 @@ import Title from './Title'; import UpdatedAt from './UpdatedAt'; import Touchable from './Touchable'; import Tag from './Tag'; +import I18n from '../../i18n'; const RoomItem = ({ rid, @@ -93,7 +94,7 @@ const RoomItem = ({ alert={alert} /> { - autoJoin ? : null + autoJoin ? : null } state.login.isAuthenticated); @@ -71,17 +67,14 @@ const handleRequest = function* handleRequest({ data }) { encrypted }); sub = yield call(createChannel, data); - if (sub.teamId) { - logEvent(events.CT_ADD_ROOM_TO_TEAM); - yield call(addRoomsToTeam, { rooms: sub.rid, teamId: sub.teamId }); - } } try { const db = database.active; const subCollection = db.get('subscriptions'); yield db.action(async() => { await subCollection.create((s) => { - s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.rid, team_id: sub.teamId }, subCollection.schema); + // eslint-disable-next-line no-nested-ternary + s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.channel ? sub.channel._id : sub.group._id }, subCollection.schema); Object.assign(s, sub); }); }); @@ -97,7 +90,13 @@ const handleRequest = function* handleRequest({ data }) { t: sub.team.type ? 'p' : 'c' }; } else { - successParams = data; + successParams = sub.channel ? { + ...sub.channel, + rid: sub.channel._id + } : { + ...sub.group, + rid: sub.group._id + }; } yield put(createChannelSuccess(successParams)); } catch (err) { diff --git a/app/views/AddChannelTeamView.js b/app/views/AddChannelTeamView.js index b57e198e3c..60c7398a6e 100644 --- a/app/views/AddChannelTeamView.js +++ b/app/views/AddChannelTeamView.js @@ -1,6 +1,5 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; -import { HeaderBackButton } from '@react-navigation/stack'; import { connect } from 'react-redux'; import * as List from '../containers/List'; @@ -8,24 +7,15 @@ import StatusBar from '../containers/StatusBar'; import { useTheme } from '../theme'; import * as HeaderButton from '../containers/HeaderButton'; import SafeAreaView from '../containers/SafeAreaView'; -import { themes } from '../constants/colors'; import I18n from '../i18n'; -const setHeader = (navigation, isMasterDetail, theme) => { +const setHeader = (navigation, isMasterDetail) => { const options = { headerTitle: I18n.t('Add_Channel_to_Team') }; if (isMasterDetail) { options.headerLeft = () => ; - } else { - options.headerLeft = () => ( - navigation.pop()} - tintColor={themes[theme].headerTintColor} - /> - ); } navigation.setOptions(options); @@ -79,5 +69,4 @@ const mapStateToProps = state => ({ isMasterDetail: state.app.isMasterDetail }); - export default connect(mapStateToProps)(AddChannelTeamView); diff --git a/app/views/AddExistingChannelView.js b/app/views/AddExistingChannelView.js index d230607572..c62db5f1ce 100644 --- a/app/views/AddExistingChannelView.js +++ b/app/views/AddExistingChannelView.js @@ -1,4 +1,3 @@ -/* eslint-disable no-mixed-spaces-and-tabs */ import React from 'react'; import PropTypes from 'prop-types'; import { @@ -29,10 +28,6 @@ class AddExistingChannelView extends React.Component { static propTypes = { navigation: PropTypes.object, route: PropTypes.object, - user: PropTypes.shape({ - id: PropTypes.string, - token: PropTypes.string - }), theme: PropTypes.string, isMasterDetail: PropTypes.bool, addTeamChannelPermission: PropTypes.array @@ -56,8 +51,6 @@ class AddExistingChannelView extends React.Component { const { selected } = this.state; const options = { - headerShown: true, - headerTitleAlign: 'center', headerTitle: I18n.t('Add_Existing_Channel') }; @@ -94,7 +87,7 @@ class AddExistingChannelView extends React.Component { return; } return channel; - }); + }); this.setState({ channels: filteredChannels }); } catch (e) { log(e); @@ -214,7 +207,7 @@ class AddExistingChannelView extends React.Component { const { loading } = this.state; return ( - + {this.renderList()} @@ -228,4 +221,4 @@ const mapStateToProps = state => ({ addTeamChannelPermission: state.permissions['add-team-channel'] }); -export default connect(mapStateToProps, null)(withTheme(AddExistingChannelView)); +export default connect(mapStateToProps)(withTheme(AddExistingChannelView)); diff --git a/app/views/RoomView/RightButtons.js b/app/views/RoomView/RightButtons.js index 4577973f7a..81b8f153b0 100644 --- a/app/views/RoomView/RightButtons.js +++ b/app/views/RoomView/RightButtons.js @@ -115,7 +115,7 @@ class RightButtonsContainer extends Component { goTeamChannels = () => { logEvent(events.ROOM_GO_TEAM_CHANNELS); const { - navigation, isMasterDetail, teamId, rid + navigation, isMasterDetail, teamId } = this.props; if (isMasterDetail) { navigation.navigate('ModalStackNavigator', { @@ -123,7 +123,7 @@ class RightButtonsContainer extends Component { params: { teamId } }); } else { - navigation.navigate('TeamChannelsView', { teamId, rid }); + navigation.navigate('TeamChannelsView', { teamId }); } } diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 139081bf10..9a916ae7f8 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -58,7 +58,6 @@ class TeamChannelsView extends React.Component { constructor(props) { super(props); this.teamId = props.route.params?.teamId; - this.rid = props.route.params?.rid; this.state = { loading: true, loadingMore: false, @@ -79,7 +78,7 @@ class TeamChannelsView extends React.Component { loadTeam = async() => { const { addTeamChannelPermission } = this.props; - const { loading } = this.state; + const { loading, data } = this.state; const db = database.active; try { @@ -98,7 +97,8 @@ class TeamChannelsView extends React.Component { if (permissions[0]) { this.setState({ showCreate: true }, () => this.setHeader()); } - if (loading) { + + if (loading && data.length) { this.setState({ loading: false }); } } catch { From d3fb7893c07b2ff2a08e9c52ce9e1e068f53cc79 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 14 May 2021 16:32:58 -0400 Subject: [PATCH 29/77] Updated styles, added tag story --- .../__snapshots__/Storyshots.test.js.snap | 117 ++++++++++++++++++ app/containers/ActionSheet/Item.js | 4 +- app/containers/ActionSheet/styles.js | 6 + app/presentation/RoomItem/Tag.js | 11 +- app/presentation/RoomItem/styles.js | 10 ++ app/views/AddChannelTeamView.js | 2 +- app/views/AddExistingChannelView.js | 5 +- storybook/stories/Tag.js | 20 +++ storybook/stories/index.js | 1 + 9 files changed, 161 insertions(+), 15 deletions(-) create mode 100644 storybook/stories/Tag.js diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index ff3d8e24b5..26aa937bf1 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -63956,6 +63956,123 @@ Array [ ] `; +exports[`Storyshots Tag usage 1`] = ` + + + + Short + + + + + A bit much longer tag + + + + + This is a looooooooooooooooooooooooooong text in order to test the tag + + + +`; + exports[`Storyshots Thread Messages.Item badge 1`] = ` diff --git a/app/containers/ActionSheet/Item.js b/app/containers/ActionSheet/Item.js index cf4299aff3..aa76da8bb5 100644 --- a/app/containers/ActionSheet/Item.js +++ b/app/containers/ActionSheet/Item.js @@ -20,7 +20,7 @@ export const Item = React.memo(({ item, hide, theme }) => { theme={theme} > - + { { item.right ? ( - + {item.right ? item.right() : null} ) : null } diff --git a/app/containers/ActionSheet/styles.js b/app/containers/ActionSheet/styles.js index 57fe0bc829..1b9397dc99 100644 --- a/app/containers/ActionSheet/styles.js +++ b/app/containers/ActionSheet/styles.js @@ -22,6 +22,9 @@ export default StyleSheet.create({ content: { paddingTop: 16 }, + titleContainer: { + flex: 1 + }, title: { fontSize: 16, marginLeft: 16, @@ -58,5 +61,8 @@ export default StyleSheet.create({ fontSize: 16, ...sharedStyles.textMedium, ...sharedStyles.textAlignCenter + }, + rightContainer: { + paddingLeft: 12 } }); diff --git a/app/presentation/RoomItem/Tag.js b/app/presentation/RoomItem/Tag.js index dab148a636..131541fe6d 100644 --- a/app/presentation/RoomItem/Tag.js +++ b/app/presentation/RoomItem/Tag.js @@ -4,21 +4,16 @@ import PropTypes from 'prop-types'; import { themes } from '../../constants/colors'; import { useTheme } from '../../theme'; -import sharedStyles from '../../views/Styles'; +import styles from './styles'; const Tag = React.memo(({ name }) => { const { theme } = useTheme(); return ( - + diff --git a/app/presentation/RoomItem/styles.js b/app/presentation/RoomItem/styles.js index 80bf0c90b3..d7941ce1de 100644 --- a/app/presentation/RoomItem/styles.js +++ b/app/presentation/RoomItem/styles.js @@ -96,5 +96,15 @@ export default StyleSheet.create({ height: '100%', alignItems: 'center', justifyContent: 'center' + }, + tagContainer: { + alignSelf: 'center', + alignItems: 'center', + borderRadius: 4 + }, + tagText: { + fontSize: 13, + paddingHorizontal: 4, + ...sharedStyles.textSemibold } }); diff --git a/app/views/AddChannelTeamView.js b/app/views/AddChannelTeamView.js index 60c7398a6e..229e004572 100644 --- a/app/views/AddChannelTeamView.js +++ b/app/views/AddChannelTeamView.js @@ -28,7 +28,7 @@ const AddChannelTeamView = ({ const { theme } = useTheme(); useEffect(() => { - setHeader(navigation, isMasterDetail, theme); + setHeader(navigation, isMasterDetail); }, []); return ( diff --git a/app/views/AddExistingChannelView.js b/app/views/AddExistingChannelView.js index c62db5f1ce..187685bf37 100644 --- a/app/views/AddExistingChannelView.js +++ b/app/views/AddExistingChannelView.js @@ -5,7 +5,6 @@ import { } from 'react-native'; import { connect } from 'react-redux'; import { Q } from '@nozbe/watermelondb'; -import { HeaderBackButton } from '@react-navigation/stack'; import * as List from '../containers/List'; import database from '../lib/database'; @@ -47,7 +46,7 @@ class AddExistingChannelView extends React.Component { } setHeader = () => { - const { navigation, isMasterDetail, theme } = this.props; + const { navigation, isMasterDetail } = this.props; const { selected } = this.state; const options = { @@ -56,8 +55,6 @@ class AddExistingChannelView extends React.Component { if (isMasterDetail) { options.headerLeft = () => ; - } else { - options.headerLeft = () => navigation.pop()} tintColor={themes[theme].headerTintColor} />; } options.headerRight = () => selected.length > 0 && ( diff --git a/storybook/stories/Tag.js b/storybook/stories/Tag.js new file mode 100644 index 0000000000..f794c5289e --- /dev/null +++ b/storybook/stories/Tag.js @@ -0,0 +1,20 @@ +/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, react/prop-types */ +import React from 'react'; +import { View } from 'react-native'; +import { storiesOf } from '@storybook/react-native'; + +import Tag from '../../app/presentation/RoomItem/Tag'; + +const stories = storiesOf('Tag', module); + +const shortText = 'Short'; +const midText = 'A bit much longer tag'; +const longText = 'This is a looooooooooooooooooooooooooong text in order to test the tag'; + +stories.add('usage', () => ( + + + + + +)); diff --git a/storybook/stories/index.js b/storybook/stories/index.js index 20bfc4f259..ce10098b76 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -10,6 +10,7 @@ import './UiKitModal'; import './Markdown'; import './HeaderButtons'; import './UnreadBadge'; +import './Tag'; import '../../app/views/ThreadMessagesView/Item.stories.js'; import './Avatar'; import '../../app/containers/BackgroundContainer/index.stories.js'; From 79334af8c7496f4998ff957e4fb37d882443ba41 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 17 May 2021 10:52:14 -0400 Subject: [PATCH 30/77] Minor tweak --- app/views/TeamChannelsView.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 9a916ae7f8..26d33cd685 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -134,14 +134,11 @@ class TeamChannelsView extends React.Component { loadingMore: false, end: result.rooms.length < API_FETCH_COUNT }; - const rooms = result.rooms.map((room) => { - const record = this.teamChannels?.find(c => c.rid === room._id); - return record ?? room; - }); + if (isSearching) { - newState.search = [...search, ...rooms]; + newState.search = [...search, ...result.rooms]; } else { - newState.data = [...data, ...rooms]; + newState.data = [...data, ...result.rooms]; } this.setState(newState); @@ -316,8 +313,7 @@ class TeamChannelsView extends React.Component { autoJoin = async(item) => { try { - const result = await RocketChat.updateTeamRoom({ roomId: item.rid, isDefault: !item.teamDefault }); - + const result = await RocketChat.updateTeamRoom({ roomId: item._id, isDefault: !item.teamDefault }); if (result.success) { this.setState({ loading: true }, () => { this.load(); From 09d63072b6f86ff0c39f04dd0f891cd6ce7e3a84 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 17 May 2021 12:50:18 -0400 Subject: [PATCH 31/77] Minor tweaks --- app/views/TeamChannelsView.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 26d33cd685..eda14ba05f 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -313,12 +313,11 @@ class TeamChannelsView extends React.Component { autoJoin = async(item) => { try { + const { data } = this.state; const result = await RocketChat.updateTeamRoom({ roomId: item._id, isDefault: !item.teamDefault }); if (result.success) { - this.setState({ loading: true }, () => { - this.load(); - this.loadTeam(); - }); + const newData = data.map(el => (el._id === result.room._id ? result.room : el)); + this.setState({ loading: true, data: newData }, this.loadTeam); } } catch (e) { log(e); @@ -347,9 +346,9 @@ class TeamChannelsView extends React.Component { removeRoom = async(item) => { try { const { data } = this.state; - const result = await RocketChat.removeTeamRoom({ roomId: item.rid, teamId: this.team.teamId }); + const result = await RocketChat.removeTeamRoom({ roomId: item._id, teamId: this.team.teamId }); if (result.success) { - const newData = data.filter(room => result.room._id !== room.rid); + const newData = data.filter(room => result.room._id !== room._id); this.setState({ loading: true, data: newData }, () => { this.load(); this.loadTeam(); @@ -374,7 +373,7 @@ class TeamChannelsView extends React.Component { { text: I18n.t('Yes_action_it', { action: I18n.t('delete') }), style: 'destructive', - onPress: () => deleteRoom(item.rid, item.t) + onPress: () => deleteRoom(item._id, item.t) } ], { cancelable: false } From 48590146940eb5e3d6642842b467f93c48455ceb Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 17 May 2021 14:29:37 -0300 Subject: [PATCH 32/77] Auto-join tweak --- app/presentation/RoomItem/index.js | 3 ++- app/views/TeamChannelsView.js | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/presentation/RoomItem/index.js b/app/presentation/RoomItem/index.js index 4818cb2edb..d56194f8bd 100644 --- a/app/presentation/RoomItem/index.js +++ b/app/presentation/RoomItem/index.js @@ -16,7 +16,8 @@ const attrs = [ 'theme', 'isFocused', 'forceUpdate', - 'showLastMessage' + 'showLastMessage', + 'autoJoin' ]; class RoomItemContainer extends React.Component { diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index eda14ba05f..1cc093ed31 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -316,8 +316,13 @@ class TeamChannelsView extends React.Component { const { data } = this.state; const result = await RocketChat.updateTeamRoom({ roomId: item._id, isDefault: !item.teamDefault }); if (result.success) { - const newData = data.map(el => (el._id === result.room._id ? result.room : el)); - this.setState({ loading: true, data: newData }, this.loadTeam); + const newData = data.map((i) => { + if (i._id === item._id) { + i.teamDefault = !i.teamDefault; + } + return i; + }); + this.setState({ data: newData }); } } catch (e) { log(e); From 2fa4ebecd708d49438169f929aaef327b7eb39cd Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 18 May 2021 11:45:35 -0400 Subject: [PATCH 33/77] Minor tweaks --- .../__snapshots__/Storyshots.test.js.snap | 666 +++++++++++++++--- app/lib/database/model/Subscription.js | 2 - app/lib/database/model/migrations.js | 11 - app/lib/database/schema/app.js | 5 +- .../helpers/mergeSubscriptionsRooms.js | 1 - app/presentation/RoomItem/styles.js | 3 +- app/views/TeamChannelsView.js | 51 +- storybook/stories/RoomItem.js | 11 + storybook/stories/Tag.js | 20 - storybook/stories/index.js | 1 - 10 files changed, 590 insertions(+), 181 deletions(-) delete mode 100644 storybook/stories/Tag.js diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 26aa937bf1..46865b4549 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -52512,6 +52512,555 @@ exports[`Storyshots Room Item Last Message 1`] = ` `; +exports[`Storyshots Room Item Tag 1`] = ` + + + + + + + + +  + + + Read + + + + + + + +  + + + Favorite + + + + +  + + + Hide + + + + + + + + + + + + + +  + + + rocket.cat + + + + Auto-join + + + + 10:00 + + + + + No Message + + + + 1 + + + + + + + + + + +`; + exports[`Storyshots Room Item Type 1`] = ` - - - Short - - - - - A bit much longer tag - - - - - This is a looooooooooooooooooooooooooong text in order to test the tag - - - -`; - exports[`Storyshots Thread Messages.Item badge 1`] = ` diff --git a/app/lib/database/model/Subscription.js b/app/lib/database/model/Subscription.js index 5a332fa1a1..5b1ebd1411 100644 --- a/app/lib/database/model/Subscription.js +++ b/app/lib/database/model/Subscription.js @@ -129,6 +129,4 @@ export default class Subscription extends Model { @field('team_id') teamId; @field('team_main') teamMain; - - @field('team_default') teamDefault; } diff --git a/app/lib/database/model/migrations.js b/app/lib/database/model/migrations.js index 17a8aa894c..cdc65ef0f7 100644 --- a/app/lib/database/model/migrations.js +++ b/app/lib/database/model/migrations.js @@ -224,17 +224,6 @@ export default schemaMigrations({ ] }) ] - }, - { - toVersion: 14, - steps: [ - addColumns({ - table: 'subscriptions', - columns: [ - { name: 'team_default', type: 'boolean', isOptional: true } - ] - }) - ] } ] }); diff --git a/app/lib/database/schema/app.js b/app/lib/database/schema/app.js index 0a51951b0f..883e6dfd96 100644 --- a/app/lib/database/schema/app.js +++ b/app/lib/database/schema/app.js @@ -1,7 +1,7 @@ import { appSchema, tableSchema } from '@nozbe/watermelondb'; export default appSchema({ - version: 14, + version: 13, tables: [ tableSchema({ name: 'subscriptions', @@ -59,8 +59,7 @@ export default appSchema({ { name: 'e2e_key_id', type: 'string', isOptional: true }, { name: 'avatar_etag', type: 'string', isOptional: true }, { name: 'team_id', type: 'string', isIndexed: true }, - { name: 'team_main', type: 'boolean', isOptional: true }, - { name: 'team_default', type: 'boolean', isOptional: true } + { name: 'team_main', type: 'boolean', isOptional: true } ] }), tableSchema({ diff --git a/app/lib/methods/helpers/mergeSubscriptionsRooms.js b/app/lib/methods/helpers/mergeSubscriptionsRooms.js index b8e5fdf983..82dfc4c68d 100644 --- a/app/lib/methods/helpers/mergeSubscriptionsRooms.js +++ b/app/lib/methods/helpers/mergeSubscriptionsRooms.js @@ -44,7 +44,6 @@ export const merge = (subscription, room) => { subscription.avatarETag = room.avatarETag; subscription.teamId = room.teamId; subscription.teamMain = room.teamMain; - subscription.teamDefault = room.teamDefault; if (!subscription.roles || !subscription.roles.length) { subscription.roles = []; } diff --git a/app/presentation/RoomItem/styles.js b/app/presentation/RoomItem/styles.js index d7941ce1de..787546c76c 100644 --- a/app/presentation/RoomItem/styles.js +++ b/app/presentation/RoomItem/styles.js @@ -100,7 +100,8 @@ export default StyleSheet.create({ tagContainer: { alignSelf: 'center', alignItems: 'center', - borderRadius: 4 + borderRadius: 4, + marginHorizontal: 4 }, tagText: { fontSize: 13, diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 1cc093ed31..7e3a73318d 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -29,6 +29,7 @@ import I18n from '../i18n'; import { withActionSheet } from '../containers/ActionSheet'; import { deleteRoom as deleteRoomAction } from '../actions/room'; import { CustomIcon } from '../lib/Icons'; +import { themes } from '../constants/colors'; const API_FETCH_COUNT = 25; @@ -290,28 +291,31 @@ class TeamChannelsView extends React.Component { } }, 1000, true); - options = item => ([ - { - title: I18n.t('Auto-join'), - icon: item.t === 'p' ? 'channel-private' : 'channel-public', - onPress: () => this.autoJoin(item), - right: () => (item.teamDefault ? : null) - }, - { - title: I18n.t('Remove_from_Team'), - icon: 'close', - danger: true, - onPress: () => this.remove(item) - }, - { - title: I18n.t('Delete'), - icon: 'delete', - danger: true, - onPress: () => this.delete(item) - } - ]) + options = (item) => { + const { theme } = this.props; + return ([ + { + title: I18n.t('Auto-join'), + icon: item.t === 'p' ? 'channel-private' : 'channel-public', + onPress: () => this.toggleAutoJoin(item), + right: () => + }, + { + title: I18n.t('Remove_from_Team'), + icon: 'close', + danger: true, + onPress: () => this.remove(item) + }, + { + title: I18n.t('Delete'), + icon: 'delete', + danger: true, + onPress: () => this.delete(item) + } + ]); + } - autoJoin = async(item) => { + toggleAutoJoin = async(item) => { try { const { data } = this.state; const result = await RocketChat.updateTeamRoom({ roomId: item._id, isDefault: !item.teamDefault }); @@ -354,10 +358,7 @@ class TeamChannelsView extends React.Component { const result = await RocketChat.removeTeamRoom({ roomId: item._id, teamId: this.team.teamId }); if (result.success) { const newData = data.filter(room => result.room._id !== room._id); - this.setState({ loading: true, data: newData }, () => { - this.load(); - this.loadTeam(); - }); + this.setState({ data: newData }); } } catch (e) { log(e); diff --git a/storybook/stories/RoomItem.js b/storybook/stories/RoomItem.js index f31dac663d..b01cd18169 100644 --- a/storybook/stories/RoomItem.js +++ b/storybook/stories/RoomItem.js @@ -94,6 +94,17 @@ stories.add('Alerts', () => ( )); +stories.add('Tag', () => ( + <> + + +)); + stories.add('Last Message', () => ( <> ( - - - - - -)); diff --git a/storybook/stories/index.js b/storybook/stories/index.js index ce10098b76..20bfc4f259 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -10,7 +10,6 @@ import './UiKitModal'; import './Markdown'; import './HeaderButtons'; import './UnreadBadge'; -import './Tag'; import '../../app/views/ThreadMessagesView/Item.stories.js'; import './Avatar'; import '../../app/containers/BackgroundContainer/index.stories.js'; From 30caba12d9a2dd249d52fc66a369db8439c4b20d Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 18 May 2021 15:31:14 -0400 Subject: [PATCH 34/77] Minor tweak on search --- app/lib/rocketchat.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 98bf4de401..105c24d0e2 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -657,7 +657,8 @@ const RocketChat = { avatarETag: sub.avatarETag, t: sub.t, encrypted: sub.encrypted, - lastMessage: sub.lastMessage + lastMessage: sub.lastMessage, + ...(sub.teamId && { teamId: sub.teamId }) })); return data; From 43c31b3c04e1a2ebb9a2fc41e910e4e660857dbe Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 21 May 2021 13:41:32 -0400 Subject: [PATCH 35/77] Minor refactor to ListItem, add SelectListView to ModalStack, update handleLeaveTeam --- .../__snapshots__/Storyshots.test.js.snap | 1883 ++++++++++------- app/containers/List/ListItem.js | 22 +- app/i18n/locales/en.json | 5 +- app/stacks/MasterDetailStack/index.js | 6 + app/views/RoomActionsView/index.js | 31 +- app/views/RoomView/index.js | 2 +- app/views/SelectListView.js | 88 +- storybook/stories/RoomItem.js | 1 - 8 files changed, 1218 insertions(+), 820 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 68b171855c..82647c22ae 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -4178,25 +4178,34 @@ exports[`Storyshots List pressable 1`] = ` } } > - - Press me - + + Press me + + - - I'm disabled - + + I'm disabled + + - - Chats - + + Chats + + @@ -4440,25 +4467,34 @@ exports[`Storyshots List title and subtitle 1`] = ` } } > - - Chats - + + Chats + + - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + - - 0 - + + 0 + + @@ -4796,25 +4850,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 1 - + + 1 + + @@ -4868,25 +4931,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 2 - + + 2 + + @@ -4940,25 +5012,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 3 - + + 3 + + @@ -5012,25 +5093,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 4 - + + 4 + + @@ -5084,25 +5174,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 5 - + + 5 + + @@ -5156,25 +5255,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 6 - + + 6 + + @@ -5228,25 +5336,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 7 - + + 7 + + @@ -5300,25 +5417,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 8 - + + 8 + + @@ -5372,25 +5498,34 @@ exports[`Storyshots List with FlatList 1`] = ` } } > - - 9 - + + 9 + + @@ -5586,25 +5721,34 @@ exports[`Storyshots List with bigger font 1`] = ` } } > - - Chats - + + Chats + + - - Chats - + + Chats + + - - Chats - + + Chats + + - - Chats - + + Chats + + +  + + + + + + -  + Chats - - - - Chats - - - Chats - + + Chats + + - - Chats - + + Chats + + - - Chats - + + Chats + + - - Chats - + + Chats + + @@ -7217,25 +7433,34 @@ exports[`Storyshots List with custom colors 1`] = ` } } > - - Press me! - + + Press me! + + - - Chats - + + Chats + + - - Chats - + + Chats + + - - Chats - + + Chats + + - - Chats - + + Chats + + - - Icon Left - + + Icon Left + + @@ -8253,25 +8523,34 @@ exports[`Storyshots List with icon 1`] = ` } } > - - Icon Right - + + Icon Right + + - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + - - Show Action Indicator - + + Show Action Indicator + + - - Section Item - + + Section Item + + @@ -8760,25 +9066,34 @@ exports[`Storyshots List with section and info 1`] = ` } } > - - Section Item - + + Section Item + + @@ -8848,25 +9163,34 @@ exports[`Storyshots List with section and info 1`] = ` } } > - - Section Item - + + Section Item + + @@ -8915,25 +9239,34 @@ exports[`Storyshots List with section and info 1`] = ` } } > - - Section Item - + + Section Item + + @@ -9031,25 +9364,34 @@ exports[`Storyshots List with section and info 1`] = ` } } > - - Section Item - + + Section Item + + @@ -9098,25 +9440,34 @@ exports[`Storyshots List with section and info 1`] = ` } } > - - Section Item - + + Section Item + + @@ -9241,25 +9592,34 @@ exports[`Storyshots List with section and info 1`] = ` } } > - - Section Item - + + Section Item + + @@ -9308,25 +9668,34 @@ exports[`Storyshots List with section and info 1`] = ` } } > - - Section Item - + + Section Item + + @@ -9525,25 +9894,34 @@ exports[`Storyshots List with small font 1`] = ` } } > - - Chats - + + Chats + + - - Chats - + + Chats + + - - Chats - + + Chats + + - - Chats - + + Chats + + ( {left @@ -61,7 +71,12 @@ const Content = React.memo(({ ) : null} - {translateTitle ? I18n.t(title) : title} + + {translateTitle ? I18n.t(title) : title} + {alert ? ( + + ) : null} + {subtitle ? {translateSubtitle ? I18n.t(subtitle) : subtitle} : null @@ -123,7 +138,8 @@ Content.propTypes = { translateTitle: PropTypes.bool, translateSubtitle: PropTypes.bool, showActionIndicator: PropTypes.bool, - fontScale: PropTypes.number + fontScale: PropTypes.number, + alert: PropTypes.string }; Content.defaultProps = { diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 79559abd09..2f3109c5a4 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -717,7 +717,7 @@ "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", "Add_Channel_to_Team": "Add Channel to Team", "Create_New": "Create New", @@ -733,5 +733,6 @@ "Select_Teams": "Select the Team's channels you would like to leave.", "Cannot_leave": "Cannot leave", "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", - "last-owner-can-not-be-removed": "Last owner cannot be removed" + "last-owner-can-not-be-removed": "Last owner cannot be removed", + "leaving_team": "leaving team" } diff --git a/app/stacks/MasterDetailStack/index.js b/app/stacks/MasterDetailStack/index.js index 3ce0130a3d..ea7c038f28 100644 --- a/app/stacks/MasterDetailStack/index.js +++ b/app/stacks/MasterDetailStack/index.js @@ -63,6 +63,7 @@ import ShareView from '../../views/ShareView'; import QueueListView from '../../ee/omnichannel/views/QueueListView'; import AddChannelTeamView from '../../views/AddChannelTeamView'; import AddExistingChannelView from '../../views/AddExistingChannelView'; +import SelectListView from '../../views/SelectListView'; // ChatsStackNavigator const ChatsStack = createStackNavigator(); @@ -119,6 +120,11 @@ const ModalStackNavigator = React.memo(({ navigation }) => { component={RoomInfoView} options={RoomInfoView.navigationOptions} /> + { + handleLeaveTeam = async(selected) => { try { - const { navigation } = this.props; - const result = await RocketChat.leaveTeam({ teamName }); - // Add isMasterDetail + const { navigation, isMasterDetail } = this.props; + const result = await RocketChat.leaveTeam({ teamName: this.teamName }); + if (selected) { + try { + selected.map(room => RocketChat.leaveRoom(room.rid, room.t)); + } catch (e) { + log(e); + } + } if (result.success) { - navigation.navigate('RoomsListView'); + if (isMasterDetail) { + navigation.popToTop(); + } else { + navigation.navigate('RoomsListView'); + } } } catch (e) { log(e); Alert.alert( I18n.t('Cannot_leave'), - I18n.t(e.data.error), + e.data.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), [ { text: 'OK', @@ -444,12 +455,13 @@ class RoomActionsView extends React.Component { const db = database.active; const subCollection = db.get('subscriptions'); const teamChannels = await subCollection.query( - Q.and(Q.where('team_id', Q.eq(room.teamId)), Q.where('name', Q.notEq(room.name))) + Q.where('team_id', room.teamId), + Q.where('team_main', null) ); if (teamChannels.length) { navigation.navigate('SelectListView', { - title: 'Leave_Team', room, teamChannels, teamName: room.name, subtitle: 'Select_Teams' + title: 'Leave_Team', room, data: teamChannels, subtitle: 'Select_Teams', nextAction: data => this.handleLeaveTeam(data) }); } else { Alert.alert( @@ -463,7 +475,7 @@ class RoomActionsView extends React.Component { { text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), style: 'destructive', - onPress: () => this._leave(room.name) + onPress: () => this.handleLeaveTeam(room.name) } ] ); @@ -941,6 +953,7 @@ const mapStateToProps = state => ({ jitsiEnabled: state.settings.Jitsi_Enabled || false, encryptionEnabled: state.encryption.enabled, serverVersion: state.server.version, + isMasterDetail: state.app.isMasterDetail, addUserToJoinedRoomPermission: state.permissions['add-user-to-joined-room'], addUserToAnyCRoomPermission: state.permissions['add-user-to-any-c-room'], addUserToAnyPRoomPermission: state.permissions['add-user-to-any-p-room'], diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index c98607d511..1c608b16dc 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -1036,7 +1036,7 @@ class RoomView extends React.Component { renderActions = () => { const { room, readOnly } = this.state; const { user } = this.props; - console.log({ room }); + return ( <> { - const { theme } = this.props; - - return ( - - - - - {title} - { alert - ? ( - this.showAlert()}> - - - ) : null} - - {checked ? : null} - - - ); - } - isChecked = (rid) => { const { selected } = this.state; return selected.includes(rid); @@ -223,18 +173,26 @@ class SelectListView extends React.Component { } } - renderItem = ({ item }) => ( - <> - {this.renderChannel({ - onPress: () => this.toggleChannel(item.rid, item.roles), - title: item.name, - icon: item.t === 'p' ? 'channel-private' : 'channel-public', - checked: this.isChecked(item.rid, item.roles) ? 'check' : null, - testID: 'select-list-view-item', - alert: item.roles ? 'info' : null - })} - - ) + renderItem = ({ item }) => { + const { theme } = this.props; + const alert = item.roles ? 'info' : null; + const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; + const checked = this.isChecked(item.rid, item.roles) ? 'check' : null; + + return ( + <> + (alert ? this.showAlert() : this.toggleChannel(item.rid, item.roles))} + alert={alert} + left={() => } + right={() => (checked ? : null)} + /> + + ); + } renderList = () => { const { data } = this.state; diff --git a/storybook/stories/RoomItem.js b/storybook/stories/RoomItem.js index d191b2f9cb..025fbf7f53 100644 --- a/storybook/stories/RoomItem.js +++ b/storybook/stories/RoomItem.js @@ -51,7 +51,6 @@ stories.add('User', () => ( - )); From 38c263708e95bc4ce899e1c4a29082a1946a22da Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 21 May 2021 13:46:31 -0400 Subject: [PATCH 36/77] Minor tweaks --- app/views/RoomActionsView/index.js | 4 ++-- app/views/RoomView/index.js | 1 - app/views/RoomsListView/index.js | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 921aac6363..474d443054 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -641,9 +641,9 @@ class RoomActionsView extends React.Component { this.onPressTouchable({ - event: room.teamId && room.teamMain ? this.leaveTeam : this.leaveChannel + event: room.teamMain ? this.leaveTeam : this.leaveChannel })} testID='room-actions-leave-channel' left={() => } diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 1c608b16dc..b6b700db35 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -1036,7 +1036,6 @@ class RoomView extends React.Component { renderActions = () => { const { room, readOnly } = this.state; const { user } = this.props; - return ( <> ; } + return ( Date: Fri, 21 May 2021 13:51:21 -0400 Subject: [PATCH 37/77] Update SelectListView --- app/views/SelectListView.js | 38 +++++-------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index de2b19b025..2a2eaa5204 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -23,6 +23,7 @@ import Loading from '../containers/Loading'; const styles = StyleSheet.create({ buttonText: { fontSize: 17, + margin: 16, ...sharedStyles.textRegular } }); @@ -45,6 +46,7 @@ class SelectListView extends React.Component { const data = props.route?.params?.data; this.title = props.route?.params?.title; this.teamName = props.route?.params?.teamName; + this.nextAction = props.route?.params?.nextAction; this.state = { data, selected: [], @@ -55,6 +57,7 @@ class SelectListView extends React.Component { setHeader = () => { const { navigation, isMasterDetail, theme } = this.props; + const { selected } = this.state; const options = { headerShown: true, @@ -70,49 +73,18 @@ class SelectListView extends React.Component { options.headerRight = () => ( - + this.nextAction(selected)} testID='select-list-view-submit' /> ); navigation.setOptions(options); } - submit = async() => { - const { selected } = this.state; - const { navigation, leaveRoom } = this.props; - - this.setState({ loading: true }); - try { - // logEvent(events.CT_ADD_ROOM_TO_TEAM); - const result = await RocketChat.leaveTeam({ teamName: this.teamName }); - if (selected) { - selected.map(room => leaveRoom(room.rid, room.t)); - } - if (result.success) { - this.setState({ loading: false }); - navigation.navigate('RoomsListView'); - } - } catch (e) { - // logEvent(events.CT_ADD_ROOM_TO_TEAM_F); - this.setState({ loading: false }); - Alert.alert( - I18n.t('Cannot_leave'), - I18n.t(e.data.error), - [ - { - text: 'OK', - style: 'cancel' - } - ] - ); - } - } - renderHeader = () => { const { theme } = this.props; return ( - {I18n.t('Select_Teams')} + {I18n.t('Select_Teams')} ); } From 28e46b73e4807cc794ba20ac9f52d6aae533fc94 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 21 May 2021 16:23:34 -0400 Subject: [PATCH 38/77] Update handleLeaveTeam, remove unnecessary method, add story --- .../__snapshots__/Storyshots.test.js.snap | 169 ++++++++++++++++++ app/containers/List/ListItem.js | 7 +- app/i18n/locales/en.json | 3 +- app/views/RoomActionsView/index.js | 8 +- app/views/SelectListView.js | 25 +-- storybook/stories/List.js | 2 + 6 files changed, 182 insertions(+), 32 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 82647c22ae..5a6cc1e1d6 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -4183,6 +4183,7 @@ exports[`Storyshots List pressable 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -4253,6 +4254,7 @@ exports[`Storyshots List pressable 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -4396,6 +4398,7 @@ exports[`Storyshots List title and subtitle 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -4472,6 +4475,7 @@ exports[`Storyshots List title and subtitle 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -4568,6 +4572,104 @@ exports[`Storyshots List title and subtitle 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, + } + } + > + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + + + + + + + @@ -4590,6 +4692,33 @@ exports[`Storyshots List title and subtitle 1`] = ` > Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + +  + @@ -4855,6 +4985,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -4936,6 +5067,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5017,6 +5149,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5098,6 +5231,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5179,6 +5313,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5260,6 +5395,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5341,6 +5477,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5422,6 +5559,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5503,6 +5641,7 @@ exports[`Storyshots List with FlatList 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5726,6 +5865,7 @@ exports[`Storyshots List with bigger font 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -5895,6 +6035,7 @@ exports[`Storyshots List with bigger font 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -6138,6 +6279,7 @@ exports[`Storyshots List with bigger font 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -6307,6 +6449,7 @@ exports[`Storyshots List with bigger font 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -6591,6 +6734,7 @@ exports[`Storyshots List with black theme 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -6760,6 +6904,7 @@ exports[`Storyshots List with black theme 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -7003,6 +7148,7 @@ exports[`Storyshots List with black theme 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -7172,6 +7318,7 @@ exports[`Storyshots List with black theme 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -7369,6 +7516,7 @@ exports[`Storyshots List with custom colors 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -7438,6 +7586,7 @@ exports[`Storyshots List with custom colors 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -7634,6 +7783,7 @@ exports[`Storyshots List with dark theme 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -7803,6 +7953,7 @@ exports[`Storyshots List with dark theme 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -8046,6 +8197,7 @@ exports[`Storyshots List with dark theme 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -8215,6 +8367,7 @@ exports[`Storyshots List with dark theme 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -8452,6 +8605,7 @@ exports[`Storyshots List with icon 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -8528,6 +8682,7 @@ exports[`Storyshots List with icon 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -8684,6 +8839,7 @@ exports[`Storyshots List with icon 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -8819,6 +8975,7 @@ exports[`Storyshots List with icon 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -8995,6 +9152,7 @@ exports[`Storyshots List with section and info 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -9071,6 +9229,7 @@ exports[`Storyshots List with section and info 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -9168,6 +9327,7 @@ exports[`Storyshots List with section and info 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -9244,6 +9404,7 @@ exports[`Storyshots List with section and info 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -9369,6 +9530,7 @@ exports[`Storyshots List with section and info 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -9445,6 +9607,7 @@ exports[`Storyshots List with section and info 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -9597,6 +9760,7 @@ exports[`Storyshots List with section and info 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -9673,6 +9837,7 @@ exports[`Storyshots List with section and info 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -9899,6 +10064,7 @@ exports[`Storyshots List with small font 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -10068,6 +10234,7 @@ exports[`Storyshots List with small font 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -10311,6 +10478,7 @@ exports[`Storyshots List with small font 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > @@ -10480,6 +10648,7 @@ exports[`Storyshots List with small font 1`] = ` Object { "alignItems": "center", "flexDirection": "row", + "marginRight": 14, } } > diff --git a/app/containers/List/ListItem.js b/app/containers/List/ListItem.js index 4dd165e750..0b44499a5a 100644 --- a/app/containers/List/ListItem.js +++ b/app/containers/List/ListItem.js @@ -37,12 +37,11 @@ const styles = StyleSheet.create({ }, textAlertContainer: { flexDirection: 'row', - alignItems: 'center' + alignItems: 'center', + marginRight: 14 }, alertIcon: { - transform: [{ rotateY: '180deg' }], - marginLeft: 16, - marginRight: 18 + marginLeft: 2 }, title: { fontSize: 16, diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 2f3109c5a4..b7b5dc73e8 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -734,5 +734,6 @@ "Cannot_leave": "Cannot leave", "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", "last-owner-can-not-be-removed": "Last owner cannot be removed", - "leaving_team": "leaving team" + "leaving_team": "leaving team", + "member-does-not-exist": "Member does not exist" } diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 474d443054..8e548831fb 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -415,12 +415,14 @@ class RoomActionsView extends React.Component { } handleLeaveTeam = async(selected) => { + const { room } = this.state; try { const { navigation, isMasterDetail } = this.props; - const result = await RocketChat.leaveTeam({ teamName: this.teamName }); + const result = await RocketChat.leaveTeam({ teamName: room.name }); + if (selected) { try { - selected.map(room => RocketChat.leaveRoom(room.rid, room.t)); + selected.map(item => RocketChat.leaveRoom(item.rid, item.t)); } catch (e) { log(e); } @@ -436,7 +438,7 @@ class RoomActionsView extends React.Component { log(e); Alert.alert( I18n.t('Cannot_leave'), - e.data.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), + e.data?.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), [ { text: 'OK', diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 2a2eaa5204..75d6d0f0f6 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -9,7 +9,6 @@ import { HeaderBackButton } from '@react-navigation/stack'; import * as List from '../containers/List'; import { leaveRoom as leaveRoomAction } from '../actions/room'; -import RocketChat from '../lib/rocketchat'; import sharedStyles from './Styles'; import I18n from '../i18n'; import * as HeaderButton from '../containers/HeaderButton'; @@ -37,8 +36,7 @@ class SelectListView extends React.Component { token: PropTypes.string }), theme: PropTypes.string, - isMasterDetail: PropTypes.bool, - leaveRoom: PropTypes.func + isMasterDetail: PropTypes.bool }; constructor(props) { @@ -102,27 +100,6 @@ class SelectListView extends React.Component { ); } - leaveChannel = () => { - const { room } = this.state; - const { leaveRoom } = this.props; - - Alert.alert( - I18n.t('Are_you_sure_question_mark'), - I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: RocketChat.getRoomTitle(room) }), - [ - { - text: I18n.t('Cancel'), - style: 'cancel' - }, - { - text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), - style: 'destructive', - onPress: () => leaveRoom(room.rid, room.t) - } - ] - ); - } - isChecked = (rid) => { const { selected } = this.state; return selected.includes(rid); diff --git a/storybook/stories/List.js b/storybook/stories/List.js index 632018054b..06f49ac730 100644 --- a/storybook/stories/List.js +++ b/storybook/stories/List.js @@ -20,6 +20,8 @@ stories.add('title and subtitle', () => ( + + )); From 3d4370f65c626d751da2beb3ac313f4fb7c071ad Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 21 May 2021 16:36:53 -0400 Subject: [PATCH 39/77] Minor tweak --- .../__snapshots__/Storyshots.test.js.snap | 164 ++++++++++++++++++ app/containers/List/ListItem.js | 2 +- app/views/SelectListView.js | 2 +- storybook/stories/List.js | 2 + 4 files changed, 168 insertions(+), 2 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 5a6cc1e1d6..2baf1b5e88 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -4755,6 +4755,170 @@ exports[`Storyshots List title and subtitle 1`] = ` ] } /> + + + + + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + +  + + + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + + + + +  + + + + + + `; diff --git a/app/containers/List/ListItem.js b/app/containers/List/ListItem.js index 0b44499a5a..d38b97c9a5 100644 --- a/app/containers/List/ListItem.js +++ b/app/containers/List/ListItem.js @@ -73,7 +73,7 @@ const Content = React.memo(({ {translateTitle ? I18n.t(title) : title} {alert ? ( - + ) : null} {subtitle diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 75d6d0f0f6..bd3ff16258 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -124,7 +124,7 @@ class SelectListView extends React.Component { renderItem = ({ item }) => { const { theme } = this.props; - const alert = item.roles ? 'info' : null; + const alert = !!item.roles; const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; const checked = this.isChecked(item.rid, item.roles) ? 'check' : null; diff --git a/storybook/stories/List.js b/storybook/stories/List.js index 06f49ac730..5ebde0a59f 100644 --- a/storybook/stories/List.js +++ b/storybook/stories/List.js @@ -22,6 +22,8 @@ stories.add('title and subtitle', () => ( + } /> + )); From 003a2725f5bca40028c4009199c7fdb467e34f63 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 24 May 2021 11:17:51 -0300 Subject: [PATCH 40/77] Minor visual tweaks --- .../__snapshots__/Storyshots.test.js.snap | 1101 +++++++++++------ app/containers/List/ListIcon.js | 3 +- app/containers/List/ListItem.js | 13 +- app/containers/List/constants.js | 1 + storybook/stories/List.js | 14 +- 5 files changed, 718 insertions(+), 414 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 2baf1b5e88..21c95c78e2 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -3993,6 +3993,540 @@ Array [ ] `; +exports[`Storyshots List alert 1`] = ` + + + + + + + + + Chats + + +  + + + + + + + + + + + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + +  + + + + + + + + + + + + Chats + + +  + + + + + + +  + + + + + + + + + + + + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + + +  + + + + + + +  + + + + + + + + +`; + exports[`Storyshots List header 1`] = ` @@ -4193,6 +4727,7 @@ exports[`Storyshots List pressable 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -4253,8 +4788,8 @@ exports[`Storyshots List pressable 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -4264,6 +4799,7 @@ exports[`Storyshots List pressable 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -4275,248 +4811,7 @@ exports[`Storyshots List pressable 1`] = ` ] } > - I'm disabled - - - - - - - -`; - -exports[`Storyshots List separator 1`] = ` - - - - - -`; - -exports[`Storyshots List title and subtitle 1`] = ` - - - - - - - - - Chats - - - - - - - - - - - - Chats - - - - All + I'm disabled @@ -4534,6 +4829,74 @@ exports[`Storyshots List title and subtitle 1`] = ` ] } /> + + +`; + +exports[`Storyshots List separator 1`] = ` + + + + + +`; + +exports[`Storyshots List title and subtitle 1`] = ` + + + @@ -4582,6 +4944,7 @@ exports[`Storyshots List title and subtitle 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -4593,28 +4956,9 @@ exports[`Storyshots List title and subtitle 1`] = ` ] } > - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + Chats - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - @@ -4654,7 +4998,6 @@ exports[`Storyshots List title and subtitle 1`] = ` }, ] } - testID="test-id" > @@ -4679,6 +5022,7 @@ exports[`Storyshots List title and subtitle 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -4690,34 +5034,7 @@ exports[`Storyshots List title and subtitle 1`] = ` ] } > - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - - -  + Chats - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + All @@ -4792,8 +5109,8 @@ exports[`Storyshots List title and subtitle 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -4803,6 +5120,7 @@ exports[`Storyshots List title and subtitle 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -4816,33 +5134,6 @@ exports[`Storyshots List title and subtitle 1`] = ` > Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries - -  - - - - -  - - - @@ -5077,6 +5328,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5148,8 +5400,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5159,6 +5411,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5230,8 +5483,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5241,6 +5494,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5312,8 +5566,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5323,6 +5577,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5394,8 +5649,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5405,6 +5660,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5476,8 +5732,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5487,6 +5743,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5558,8 +5815,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5569,6 +5826,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5640,8 +5898,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5651,6 +5909,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5722,8 +5981,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5733,6 +5992,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -5804,8 +6064,8 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -5815,6 +6075,7 @@ exports[`Storyshots List with FlatList 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -6028,8 +6289,8 @@ exports[`Storyshots List with bigger font 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -6039,6 +6300,7 @@ exports[`Storyshots List with bigger font 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -6198,8 +6460,8 @@ exports[`Storyshots List with bigger font 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -6209,6 +6471,7 @@ exports[`Storyshots List with bigger font 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -6442,8 +6705,8 @@ exports[`Storyshots List with bigger font 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -6453,6 +6716,7 @@ exports[`Storyshots List with bigger font 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -6612,8 +6876,8 @@ exports[`Storyshots List with bigger font 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -6623,6 +6887,7 @@ exports[`Storyshots List with bigger font 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -6897,8 +7162,8 @@ exports[`Storyshots List with black theme 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -6908,6 +7173,7 @@ exports[`Storyshots List with black theme 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -7067,8 +7333,8 @@ exports[`Storyshots List with black theme 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -7078,6 +7344,7 @@ exports[`Storyshots List with black theme 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -7311,8 +7578,8 @@ exports[`Storyshots List with black theme 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -7322,6 +7589,7 @@ exports[`Storyshots List with black theme 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -7481,8 +7749,8 @@ exports[`Storyshots List with black theme 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -7492,6 +7760,7 @@ exports[`Storyshots List with black theme 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -7679,8 +7948,8 @@ exports[`Storyshots List with custom colors 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -7690,6 +7959,7 @@ exports[`Storyshots List with custom colors 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -7749,8 +8019,8 @@ exports[`Storyshots List with custom colors 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -7760,6 +8030,7 @@ exports[`Storyshots List with custom colors 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -7946,8 +8217,8 @@ exports[`Storyshots List with dark theme 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -7957,6 +8228,7 @@ exports[`Storyshots List with dark theme 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -8116,8 +8388,8 @@ exports[`Storyshots List with dark theme 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -8127,6 +8399,7 @@ exports[`Storyshots List with dark theme 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -8360,8 +8633,8 @@ exports[`Storyshots List with dark theme 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -8371,6 +8644,7 @@ exports[`Storyshots List with dark theme 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -8530,8 +8804,8 @@ exports[`Storyshots List with dark theme 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -8541,6 +8815,7 @@ exports[`Storyshots List with dark theme 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -8768,8 +9043,8 @@ exports[`Storyshots List with icon 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -8779,6 +9054,7 @@ exports[`Storyshots List with icon 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -8845,8 +9121,8 @@ exports[`Storyshots List with icon 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -8856,6 +9132,7 @@ exports[`Storyshots List with icon 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9002,8 +9279,8 @@ exports[`Storyshots List with icon 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9013,6 +9290,7 @@ exports[`Storyshots List with icon 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9138,8 +9416,8 @@ exports[`Storyshots List with icon 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9149,6 +9427,7 @@ exports[`Storyshots List with icon 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9315,8 +9594,8 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9326,6 +9605,7 @@ exports[`Storyshots List with section and info 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9392,8 +9672,8 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9403,6 +9683,7 @@ exports[`Storyshots List with section and info 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9490,8 +9771,8 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9501,6 +9782,7 @@ exports[`Storyshots List with section and info 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9567,8 +9849,8 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9578,6 +9860,7 @@ exports[`Storyshots List with section and info 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9693,8 +9976,8 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9704,6 +9987,7 @@ exports[`Storyshots List with section and info 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9770,8 +10054,8 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9781,6 +10065,7 @@ exports[`Storyshots List with section and info 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -9923,8 +10208,8 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -9934,6 +10219,7 @@ exports[`Storyshots List with section and info 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -10000,8 +10286,8 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -10011,6 +10297,7 @@ exports[`Storyshots List with section and info 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -10227,8 +10514,8 @@ exports[`Storyshots List with small font 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -10238,6 +10525,7 @@ exports[`Storyshots List with small font 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -10397,8 +10685,8 @@ exports[`Storyshots List with small font 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -10408,6 +10696,7 @@ exports[`Storyshots List with small font 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -10641,8 +10930,8 @@ exports[`Storyshots List with small font 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -10652,6 +10941,7 @@ exports[`Storyshots List with small font 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", @@ -10811,8 +11101,8 @@ exports[`Storyshots List with small font 1`] = ` style={ Object { "alignItems": "center", + "flex": 1, "flexDirection": "row", - "marginRight": 14, } } > @@ -10822,6 +11112,7 @@ exports[`Storyshots List with small font 1`] = ` Array [ Object { "backgroundColor": "transparent", + "flexShrink": 1, "fontFamily": "System", "fontSize": 16, "fontWeight": "400", diff --git a/app/containers/List/ListIcon.js b/app/containers/List/ListIcon.js index 2414c669ac..5ab6c3bc9a 100644 --- a/app/containers/List/ListIcon.js +++ b/app/containers/List/ListIcon.js @@ -5,6 +5,7 @@ import PropTypes from 'prop-types'; import { themes } from '../../constants/colors'; import { CustomIcon } from '../../lib/Icons'; import { withTheme } from '../../theme'; +import { ICON_SIZE } from './constants'; const styles = StyleSheet.create({ icon: { @@ -23,7 +24,7 @@ const ListIcon = React.memo(({ )); diff --git a/app/containers/List/ListItem.js b/app/containers/List/ListItem.js index d38b97c9a5..96dc6032c9 100644 --- a/app/containers/List/ListItem.js +++ b/app/containers/List/ListItem.js @@ -10,7 +10,7 @@ import sharedStyles from '../../views/Styles'; import { withTheme } from '../../theme'; import I18n from '../../i18n'; import { Icon } from '.'; -import { BASE_HEIGHT, PADDING_HORIZONTAL } from './constants'; +import { BASE_HEIGHT, ICON_SIZE, PADDING_HORIZONTAL } from './constants'; import { withDimensions } from '../../dimensions'; import { CustomIcon } from '../../lib/Icons'; @@ -36,14 +36,15 @@ const styles = StyleSheet.create({ justifyContent: 'center' }, textAlertContainer: { + flex: 1, flexDirection: 'row', - alignItems: 'center', - marginRight: 14 + alignItems: 'center' }, alertIcon: { - marginLeft: 2 + paddingLeft: 4 }, title: { + flexShrink: 1, fontSize: 16, ...sharedStyles.textRegular }, @@ -73,7 +74,7 @@ const Content = React.memo(({ {translateTitle ? I18n.t(title) : title} {alert ? ( - + ) : null} {subtitle @@ -138,7 +139,7 @@ Content.propTypes = { translateSubtitle: PropTypes.bool, showActionIndicator: PropTypes.bool, fontScale: PropTypes.number, - alert: PropTypes.string + alert: PropTypes.bool }; Content.defaultProps = { diff --git a/app/containers/List/constants.js b/app/containers/List/constants.js index b69a04f95c..8144096d39 100644 --- a/app/containers/List/constants.js +++ b/app/containers/List/constants.js @@ -1,2 +1,3 @@ export const PADDING_HORIZONTAL = 12; export const BASE_HEIGHT = 46; +export const ICON_SIZE = 20; diff --git a/storybook/stories/List.js b/storybook/stories/List.js index 5ebde0a59f..b445a1972a 100644 --- a/storybook/stories/List.js +++ b/storybook/stories/List.js @@ -20,9 +20,19 @@ stories.add('title and subtitle', () => ( - + +)); + +stories.add('alert', () => ( + + + + + + + } alert /> - } /> + } alert /> )); From 4deffca198bf05739a66c673bbad879236c5b8ce Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 10:54:33 -0400 Subject: [PATCH 41/77] Update SelectListView.js --- app/views/SelectListView.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index c305c25104..6b131414b1 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -17,9 +17,6 @@ import { withTheme } from '../theme'; import SafeAreaView from '../containers/SafeAreaView'; import { animateNextTransition } from '../utils/layoutAnimation'; import Loading from '../containers/Loading'; -import { LISTENER } from '../containers/Toast'; -import EventEmitter from '../utils/events'; -import log from '../utils/log'; const styles = StyleSheet.create({ buttonText: { From 517d15eb3a04016092d53b4c3bef48d98e3f95f1 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 11:21:40 -0400 Subject: [PATCH 42/77] Update index.js --- app/views/RoomMembersView/index.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index c6b74a9f9e..7988a05aaa 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -127,15 +127,6 @@ class RoomMembersView extends React.Component { }; } - this.permissions = { - [PERMISSION_MUTE_USER]: result[0], - [PERMISSION_SET_LEADER]: result[1], - [PERMISSION_SET_OWNER]: result[2], - [PERMISSION_SET_MODERATOR]: result[3], - [PERMISSION_REMOVE_USER]: result[4], - [PERMISSION_EDIT_TEAM_MEMBER]: result[5] - }; - const hasSinglePermission = Object.values(this.permissions).some(p => !!p); if (hasSinglePermission) { this.fetchRoomMembersRoles(); @@ -231,9 +222,11 @@ class RoomMembersView extends React.Component { if (result.success) { const message = I18n.t('User_has_been_removed_from_s', { s: RocketChat.getRoomTitle(room) }); EventEmitter.emit(LISTENER, { message }); + const newMembers = members.filter(member => member._id !== userId); + const newMembersFiltered = membersFiltered.filter(member => member._id !== userId); this.setState({ - members: members.filter(member => member._id !== userId), - membersFiltered: membersFiltered.filter(member => member._id !== userId) + members: newMembers, + membersFiltered: newMembersFiltered }); } } catch (e) { From 29122cb29c6db8def2944f6a506286971892d25a Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 11:51:37 -0400 Subject: [PATCH 43/77] Update RoomMembersView --- app/views/RoomMembersView/index.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index c6b74a9f9e..7988a05aaa 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -127,15 +127,6 @@ class RoomMembersView extends React.Component { }; } - this.permissions = { - [PERMISSION_MUTE_USER]: result[0], - [PERMISSION_SET_LEADER]: result[1], - [PERMISSION_SET_OWNER]: result[2], - [PERMISSION_SET_MODERATOR]: result[3], - [PERMISSION_REMOVE_USER]: result[4], - [PERMISSION_EDIT_TEAM_MEMBER]: result[5] - }; - const hasSinglePermission = Object.values(this.permissions).some(p => !!p); if (hasSinglePermission) { this.fetchRoomMembersRoles(); @@ -231,9 +222,11 @@ class RoomMembersView extends React.Component { if (result.success) { const message = I18n.t('User_has_been_removed_from_s', { s: RocketChat.getRoomTitle(room) }); EventEmitter.emit(LISTENER, { message }); + const newMembers = members.filter(member => member._id !== userId); + const newMembersFiltered = membersFiltered.filter(member => member._id !== userId); this.setState({ - members: members.filter(member => member._id !== userId), - membersFiltered: membersFiltered.filter(member => member._id !== userId) + members: newMembers, + membersFiltered: newMembersFiltered }); } } catch (e) { From 3f8a64722efe9e03d4f537c124fec60507761034 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 12:52:58 -0400 Subject: [PATCH 44/77] Updated SelectListView, RoomActionsView, leaveTeam method and string translations --- app/i18n/locales/en.json | 2 +- app/lib/rocketchat.js | 4 +- app/views/RoomActionsView/index.js | 26 +++++++---- app/views/SelectListView.js | 74 +++++++++--------------------- 4 files changed, 41 insertions(+), 65 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index b7b5dc73e8..2e83919564 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -730,7 +730,7 @@ "invalid-room": "Invalid room", "You_are_leaving_the_team": "You are leaving the team '{{team}}'", "Leave_Team": "Leave Team", - "Select_Teams": "Select the Team's channels you would like to leave.", + "Select_Team_Channels": "Select the Team's channels you would like to leave.", "Cannot_leave": "Cannot leave", "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", "last-owner-can-not-be-removed": "Last owner cannot be removed", diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 50da06a8c7..3891d88cb5 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -769,9 +769,9 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.removeRoom', { roomId, teamId }); }, - leaveTeam({ teamName }) { + leaveTeam({ teamName, rooms }) { // RC 3.13.0 - return this.post('teams.leave', { teamName }); + return this.post('teams.leave', { teamName, rooms }); }, updateTeamRoom({ roomId, isDefault }) { // RC 3.13.0 diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 8e548831fb..084e94a37c 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -418,15 +418,8 @@ class RoomActionsView extends React.Component { const { room } = this.state; try { const { navigation, isMasterDetail } = this.props; - const result = await RocketChat.leaveTeam({ teamName: room.name }); + const result = await RocketChat.leaveTeam({ teamName: room.name, ...(selected && { rooms: selected }) }); - if (selected) { - try { - selected.map(item => RocketChat.leaveRoom(item.rid, item.t)); - } catch (e) { - log(e); - } - } if (result.success) { if (isMasterDetail) { navigation.popToTop(); @@ -449,6 +442,19 @@ class RoomActionsView extends React.Component { } } + showNoLeaveTeamAlert = () => { + Alert.alert( + I18n.t('Cannot_leave'), + I18n.t('Last_owner_team_room'), + [ + { + text: 'OK', + style: 'cancel' + } + ] + ); + } + leaveTeam = async() => { const { room } = this.state; const { navigation } = this.props; @@ -463,7 +469,7 @@ class RoomActionsView extends React.Component { if (teamChannels.length) { navigation.navigate('SelectListView', { - title: 'Leave_Team', room, data: teamChannels, subtitle: 'Select_Teams', nextAction: data => this.handleLeaveTeam(data) + title: 'Leave_Team', room, data: teamChannels, infoText: 'Select_Team_Channels', nextAction: data => this.handleLeaveTeam(data), showAlert: () => this.showNoLeaveTeamAlert() }); } else { Alert.alert( @@ -477,7 +483,7 @@ class RoomActionsView extends React.Component { { text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), style: 'destructive', - onPress: () => this.handleLeaveTeam(room.name) + onPress: () => this.handleLeaveTeam() } ] ); diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index bd3ff16258..c4023d1186 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -1,11 +1,9 @@ -/* eslint-disable no-mixed-spaces-and-tabs */ import React from 'react'; import PropTypes from 'prop-types'; import { - View, StyleSheet, FlatList, Text, Alert + View, StyleSheet, FlatList, Text } from 'react-native'; import { connect } from 'react-redux'; -import { HeaderBackButton } from '@react-navigation/stack'; import * as List from '../containers/List'; import { leaveRoom as leaveRoomAction } from '../actions/room'; @@ -21,7 +19,7 @@ import Loading from '../containers/Loading'; const styles = StyleSheet.create({ buttonText: { - fontSize: 17, + fontSize: 16, margin: 16, ...sharedStyles.textRegular } @@ -31,10 +29,6 @@ class SelectListView extends React.Component { static propTypes = { navigation: PropTypes.object, route: PropTypes.object, - user: PropTypes.shape({ - id: PropTypes.string, - token: PropTypes.string - }), theme: PropTypes.string, isMasterDetail: PropTypes.bool }; @@ -43,8 +37,9 @@ class SelectListView extends React.Component { super(props); const data = props.route?.params?.data; this.title = props.route?.params?.title; - this.teamName = props.route?.params?.teamName; + this.infoText = props.route?.params?.infoText; this.nextAction = props.route?.params?.nextAction; + this.showAlert = props.route?.params?.showAlert; this.state = { data, selected: [], @@ -54,19 +49,15 @@ class SelectListView extends React.Component { } setHeader = () => { - const { navigation, isMasterDetail, theme } = this.props; + const { navigation, isMasterDetail } = this.props; const { selected } = this.state; const options = { - headerShown: true, - headerTitleAlign: 'center', headerTitle: I18n.t(this.title) }; if (isMasterDetail) { options.headerLeft = () => ; - } else { - options.headerLeft = () => navigation.pop()} tintColor={themes[theme].headerTintColor} />; } options.headerRight = () => ( @@ -78,34 +69,21 @@ class SelectListView extends React.Component { navigation.setOptions(options); } - renderHeader = () => { + renderInfoText = () => { const { theme } = this.props; return ( - {I18n.t('Select_Teams')} + {I18n.t(this.infoText)} ); } - showAlert = () => { - Alert.alert( - I18n.t('Cannot_leave'), - I18n.t('Last_owner_team_room'), - [ - { - text: 'OK', - style: 'cancel' - } - ] - ); - } - isChecked = (rid) => { const { selected } = this.state; return selected.includes(rid); } - toggleChannel = (rid, roles) => { + toggleItem = (rid, roles) => { const { selected } = this.state; if (roles) { @@ -130,11 +108,12 @@ class SelectListView extends React.Component { return ( <> + (alert ? this.showAlert() : this.toggleChannel(item.rid, item.roles))} + onPress={() => (alert ? this.showAlert() : this.toggleItem(item.rid, item.roles))} alert={alert} left={() => } right={() => (checked ? : null)} @@ -143,31 +122,22 @@ class SelectListView extends React.Component { ); } - renderList = () => { - const { data } = this.state; - const { theme } = this.props; - - return ( - item._id} - renderItem={this.renderItem} - ListHeaderComponent={this.renderHeader} - ItemSeparatorComponent={List.Separator} - contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} - keyboardShouldPersistTaps='always' - /> - ); - } - render() { - const { loading } = this.state; + const { loading, data } = this.state; + const { theme } = this.props; return ( - + - {this.renderList()} + item.rid} + renderItem={this.renderItem} + ListHeaderComponent={this.renderInfoText} + contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} + keyboardShouldPersistTaps='always' + /> ); From a70c699b1ae726c07764b31a3fd86c59ba11024d Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 13:05:19 -0400 Subject: [PATCH 45/77] Update SelectListVIew --- app/views/SelectListView.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index c4023d1186..66baaa69f4 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -4,9 +4,8 @@ import { View, StyleSheet, FlatList, Text } from 'react-native'; import { connect } from 'react-redux'; -import * as List from '../containers/List'; -import { leaveRoom as leaveRoomAction } from '../actions/room'; +import * as List from '../containers/List'; import sharedStyles from './Styles'; import I18n from '../i18n'; import * as HeaderButton from '../containers/HeaderButton'; @@ -148,8 +147,4 @@ const mapStateToProps = state => ({ isMasterDetail: state.app.isMasterDetail }); -const mapDispatchToProps = dispatch => ({ - leaveRoom: (rid, t) => dispatch(leaveRoomAction(rid, t)) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(withTheme(SelectListView)); +export default connect(mapStateToProps)(withTheme(SelectListView)); From 5fd651467f8b6113ec054a837088b145cf6752ec Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 13:09:26 -0400 Subject: [PATCH 46/77] Minor tweak --- app/views/RoomActionsView/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 084e94a37c..2290c4604b 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -415,8 +415,8 @@ class RoomActionsView extends React.Component { } handleLeaveTeam = async(selected) => { - const { room } = this.state; try { + const { room } = this.state; const { navigation, isMasterDetail } = this.props; const result = await RocketChat.leaveTeam({ teamName: room.name, ...(selected && { rooms: selected }) }); From d5912d3930ec97c11c5314f3aa846f1fcc502252 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 13:30:58 -0400 Subject: [PATCH 47/77] Update SelectListView --- app/views/SelectListView.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 66baaa69f4..ad20f54eb4 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -82,14 +82,9 @@ class SelectListView extends React.Component { return selected.includes(rid); } - toggleItem = (rid, roles) => { + toggleItem = (rid) => { const { selected } = this.state; - if (roles) { - this.showAlert(); - return; - } - animateNextTransition(); if (!this.isChecked(rid)) { this.setState({ selected: [...selected, rid] }, () => this.setHeader()); @@ -101,7 +96,8 @@ class SelectListView extends React.Component { renderItem = ({ item }) => { const { theme } = this.props; - const alert = !!item.roles; + const alert = item.roles.length; + const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; const checked = this.isChecked(item.rid, item.roles) ? 'check' : null; From ec5bdb1df8942fc33c89b5dfe112c68830eb52bb Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 13:37:43 -0400 Subject: [PATCH 48/77] Minor tweak --- app/views/SelectListView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index ad20f54eb4..9c886da804 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -108,7 +108,7 @@ class SelectListView extends React.Component { title={item.name} translateTitle={false} testID={`select-list-view-item-${ item.name }`} - onPress={() => (alert ? this.showAlert() : this.toggleItem(item.rid, item.roles))} + onPress={() => (alert ? this.showAlert() : this.toggleItem(item.rid))} alert={alert} left={() => } right={() => (checked ? : null)} From 919ef3414a52c3e7c30ae74514569d5ec7c5eafc Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 24 May 2021 16:07:43 -0400 Subject: [PATCH 49/77] Minor tweaks --- app/views/RoomActionsView/index.js | 11 -------- app/views/RoomMembersView/index.js | 43 ++++++++++-------------------- 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index fa954b6276..9efa35ddbf 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -332,17 +332,6 @@ class RoomActionsView extends React.Component { navigation.pop(); } catch (e) { log(e); - Alert.alert( - I18n.t('Confirmation'), - I18n.t('Removing_user_from_this_Team'), - [ - { - text: I18n.t('OK'), - style: 'cancel' - } - ], - { cancelable: false } - ); } finally { setLoadingInvite(false); } diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 7988a05aaa..8dadbb4f68 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -98,34 +98,19 @@ class RoomMembersView extends React.Component { const { muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, editTeamMemberPermission } = this.props; - let result; - - if (room.teamId) { - result = await RocketChat.hasPermission([ - muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, editTeamMemberPermission - ], room.rid); - - this.permissions = { - [PERMISSION_MUTE_USER]: result[0], - [PERMISSION_SET_LEADER]: result[1], - [PERMISSION_SET_OWNER]: result[2], - [PERMISSION_SET_MODERATOR]: result[3], - [PERMISSION_REMOVE_USER]: result[4], - [PERMISSION_EDIT_TEAM_MEMBER]: result[5] - }; - } else { - result = await RocketChat.hasPermission([ - muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission - ], room.rid); - - this.permissions = { - [PERMISSION_MUTE_USER]: result[0], - [PERMISSION_SET_LEADER]: result[1], - [PERMISSION_SET_OWNER]: result[2], - [PERMISSION_SET_MODERATOR]: result[3], - [PERMISSION_REMOVE_USER]: result[4] - }; - } + + const result = await RocketChat.hasPermission([ + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, ...(room.TeamId && [editTeamMemberPermission]) + ], room.rid); + + this.permissions = { + [PERMISSION_MUTE_USER]: result[0], + [PERMISSION_SET_LEADER]: result[1], + [PERMISSION_SET_OWNER]: result[2], + [PERMISSION_SET_MODERATOR]: result[3], + [PERMISSION_REMOVE_USER]: result[4], + ...(room.teamId && { [PERMISSION_EDIT_TEAM_MEMBER]: result[5] }) + }; const hasSinglePermission = Object.values(this.permissions).some(p => !!p); if (hasSinglePermission) { @@ -373,7 +358,7 @@ class RoomMembersView extends React.Component { this.setState({ isLoading: true }); try { const membersResult = await RocketChat.getRoomMembers(rid, allUsers, members.length, PAGE_SIZE); - console.log({ membersResult }); + const newMembers = membersResult.records; this.setState({ members: members.concat(newMembers || []), From cbea5fbe5efa29813aab2a53f2133793be456ae8 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Tue, 25 May 2021 13:51:12 -0300 Subject: [PATCH 50/77] Fix for List.Item subtitles being pushed down by title's flex --- .../__snapshots__/Storyshots.test.js.snap | 49 ------------------- app/containers/List/ListItem.js | 1 - 2 files changed, 50 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 21c95c78e2..36433392c2 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -4059,7 +4059,6 @@ exports[`Storyshots List alert 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -4164,7 +4163,6 @@ exports[`Storyshots List alert 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -4269,7 +4267,6 @@ exports[`Storyshots List alert 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -4414,7 +4411,6 @@ exports[`Storyshots List alert 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -4716,7 +4712,6 @@ exports[`Storyshots List pressable 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -4788,7 +4783,6 @@ exports[`Storyshots List pressable 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -4933,7 +4927,6 @@ exports[`Storyshots List title and subtitle 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5011,7 +5004,6 @@ exports[`Storyshots List title and subtitle 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5109,7 +5101,6 @@ exports[`Storyshots List title and subtitle 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5317,7 +5308,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5400,7 +5390,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5483,7 +5472,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5566,7 +5554,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5649,7 +5636,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5732,7 +5718,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5815,7 +5800,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5898,7 +5882,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -5981,7 +5964,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -6064,7 +6046,6 @@ exports[`Storyshots List with FlatList 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -6289,7 +6270,6 @@ exports[`Storyshots List with bigger font 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -6460,7 +6440,6 @@ exports[`Storyshots List with bigger font 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -6705,7 +6684,6 @@ exports[`Storyshots List with bigger font 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -6876,7 +6854,6 @@ exports[`Storyshots List with bigger font 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -7162,7 +7139,6 @@ exports[`Storyshots List with black theme 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -7333,7 +7309,6 @@ exports[`Storyshots List with black theme 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -7578,7 +7553,6 @@ exports[`Storyshots List with black theme 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -7749,7 +7723,6 @@ exports[`Storyshots List with black theme 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -7948,7 +7921,6 @@ exports[`Storyshots List with custom colors 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -8019,7 +7991,6 @@ exports[`Storyshots List with custom colors 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -8217,7 +8188,6 @@ exports[`Storyshots List with dark theme 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -8388,7 +8358,6 @@ exports[`Storyshots List with dark theme 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -8633,7 +8602,6 @@ exports[`Storyshots List with dark theme 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -8804,7 +8772,6 @@ exports[`Storyshots List with dark theme 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9043,7 +9010,6 @@ exports[`Storyshots List with icon 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9121,7 +9087,6 @@ exports[`Storyshots List with icon 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9279,7 +9244,6 @@ exports[`Storyshots List with icon 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9416,7 +9380,6 @@ exports[`Storyshots List with icon 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9594,7 +9557,6 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9672,7 +9634,6 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9771,7 +9732,6 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9849,7 +9809,6 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -9976,7 +9935,6 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -10054,7 +10012,6 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -10208,7 +10165,6 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -10286,7 +10242,6 @@ exports[`Storyshots List with section and info 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -10514,7 +10469,6 @@ exports[`Storyshots List with small font 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -10685,7 +10639,6 @@ exports[`Storyshots List with small font 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -10930,7 +10883,6 @@ exports[`Storyshots List with small font 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } @@ -11101,7 +11053,6 @@ exports[`Storyshots List with small font 1`] = ` style={ Object { "alignItems": "center", - "flex": 1, "flexDirection": "row", } } diff --git a/app/containers/List/ListItem.js b/app/containers/List/ListItem.js index 96dc6032c9..aa3ecbdf01 100644 --- a/app/containers/List/ListItem.js +++ b/app/containers/List/ListItem.js @@ -36,7 +36,6 @@ const styles = StyleSheet.create({ justifyContent: 'center' }, textAlertContainer: { - flex: 1, flexDirection: 'row', alignItems: 'center' }, From f0e573a74149dca3498de02f20ea0cd997a42679 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 25 May 2021 12:56:31 -0400 Subject: [PATCH 51/77] Minor tweaks --- app/views/RoomActionsView/index.js | 45 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 2290c4604b..7e1606fdd2 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -422,7 +422,7 @@ class RoomActionsView extends React.Component { if (result.success) { if (isMasterDetail) { - navigation.popToTop(); + navigation.navigate('DrawerNavigator'); } else { navigation.navigate('RoomsListView'); } @@ -431,7 +431,7 @@ class RoomActionsView extends React.Component { log(e); Alert.alert( I18n.t('Cannot_leave'), - e.data?.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), + e.data.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), [ { text: 'OK', @@ -442,7 +442,7 @@ class RoomActionsView extends React.Component { } } - showNoLeaveTeamAlert = () => { + showErrorAlert = () => { Alert.alert( I18n.t('Cannot_leave'), I18n.t('Last_owner_team_room'), @@ -455,6 +455,25 @@ class RoomActionsView extends React.Component { ); } + showConfirmationAlert = () => { + const { room } = this.state; + Alert.alert( + I18n.t('Confirmation'), + I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }), + [ + { + text: I18n.t('Cancel'), + style: 'cancel' + }, + { + text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), + style: 'destructive', + onPress: () => this.handleLeaveTeam() + } + ] + ); + } + leaveTeam = async() => { const { room } = this.state; const { navigation } = this.props; @@ -469,24 +488,10 @@ class RoomActionsView extends React.Component { if (teamChannels.length) { navigation.navigate('SelectListView', { - title: 'Leave_Team', room, data: teamChannels, infoText: 'Select_Team_Channels', nextAction: data => this.handleLeaveTeam(data), showAlert: () => this.showNoLeaveTeamAlert() + title: 'Leave_Team', data: teamChannels, infoText: 'Select_Team_Channels', nextAction: data => this.handleLeaveTeam(data), showAlert: () => this.showErrorAlert() }); } else { - Alert.alert( - I18n.t('Confirmation'), - I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }), - [ - { - text: I18n.t('Cancel'), - style: 'cancel' - }, - { - text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), - style: 'destructive', - onPress: () => this.handleLeaveTeam() - } - ] - ); + this.showConfirmationAlert(); } } catch (e) { log(e); @@ -649,7 +654,7 @@ class RoomActionsView extends React.Component { this.onPressTouchable({ event: room.teamMain ? this.leaveTeam : this.leaveChannel })} From 03eb3d9fcb98fd9f23a1915638b9d8fbcf76dc82 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 25 May 2021 13:01:07 -0400 Subject: [PATCH 52/77] Update RoomActionsView --- app/views/RoomActionsView/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 7e1606fdd2..36daa7d414 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -431,7 +431,7 @@ class RoomActionsView extends React.Component { log(e); Alert.alert( I18n.t('Cannot_leave'), - e.data.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), + e.data?.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), [ { text: 'OK', From 1fc4122a63290647c8cfb1fbcd522285e43366e9 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Tue, 25 May 2021 14:46:11 -0300 Subject: [PATCH 53/77] Use showConfirmationAlert and showErrorAlert --- app/views/RoomActionsView/index.js | 78 ++++++++---------------------- 1 file changed, 20 insertions(+), 58 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 7e1606fdd2..bf226f1cca 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -397,21 +397,11 @@ class RoomActionsView extends React.Component { const { room } = this.state; const { leaveRoom } = this.props; - Alert.alert( - I18n.t('Are_you_sure_question_mark'), - I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: RocketChat.getRoomTitle(room) }), - [ - { - text: I18n.t('Cancel'), - style: 'cancel' - }, - { - text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), - style: 'destructive', - onPress: () => leaveRoom(room.rid, room.t) - } - ] - ); + showConfirmationAlert({ + message: I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: RocketChat.getRoomTitle(room) }), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }), + onPress: () => leaveRoom(room.rid, room.t) + }); } handleLeaveTeam = async(selected) => { @@ -429,51 +419,15 @@ class RoomActionsView extends React.Component { } } catch (e) { log(e); - Alert.alert( - I18n.t('Cannot_leave'), - e.data.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), - [ - { - text: 'OK', - style: 'cancel' - } - ] + showErrorAlert( + e.data.error + ? I18n.t(e.data.error) + : I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_team') }), + I18n.t('Cannot_leave') ); } } - showErrorAlert = () => { - Alert.alert( - I18n.t('Cannot_leave'), - I18n.t('Last_owner_team_room'), - [ - { - text: 'OK', - style: 'cancel' - } - ] - ); - } - - showConfirmationAlert = () => { - const { room } = this.state; - Alert.alert( - I18n.t('Confirmation'), - I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }), - [ - { - text: I18n.t('Cancel'), - style: 'cancel' - }, - { - text: I18n.t('Yes_action_it', { action: I18n.t('leave') }), - style: 'destructive', - onPress: () => this.handleLeaveTeam() - } - ] - ); - } - leaveTeam = async() => { const { room } = this.state; const { navigation } = this.props; @@ -488,10 +442,18 @@ class RoomActionsView extends React.Component { if (teamChannels.length) { navigation.navigate('SelectListView', { - title: 'Leave_Team', data: teamChannels, infoText: 'Select_Team_Channels', nextAction: data => this.handleLeaveTeam(data), showAlert: () => this.showErrorAlert() + title: 'Leave_Team', + data: teamChannels, + infoText: 'Select_Team_Channels', + nextAction: data => this.handleLeaveTeam(data), + showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_leave')) }); } else { - this.showConfirmationAlert(); + showConfirmationAlert({ + message: I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }), + onPress: () => this.handleLeaveTeam() + }); } } catch (e) { log(e); From f021aee33aad78c63c2ddf7229e1c53c1c9a8022 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 25 May 2021 14:32:15 -0400 Subject: [PATCH 54/77] Remove addTeamMember, update removeTeamMember --- app/lib/rocketchat.js | 14 ++++++-------- app/views/RoomActionsView/index.js | 29 ++++------------------------- app/views/RoomMembersView/index.js | 12 +++++++++--- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index b44d227a0e..679f42e31f 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -773,15 +773,13 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.leave', { teamName, rooms }); }, - addTeamMember(teamName) { - const { users } = reduxStore.getState().selectedUsers; - const members = users.map(u => ({ userId: u._id, roles: ['member'] })); - // RC 3.13.0 - return this.post('teams.addMembers', { teamName, members }); - }, - removeTeamMember({ teamName, userId }) { + removeTeamMember({ + teamId, teamName, userId, rooms + }) { // RC 3.13.0 - return this.post('teams.removeMember', { teamName, userId }); + return this.post('teams.removeMember', { + teamId, teamName, userId, rooms + }); }, updateTeamRoom({ roomId, isDefault }) { // RC 3.13.0 diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index e559a8ff4b..555c03cf20 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -62,8 +62,7 @@ class RoomActionsView extends React.Component { editRoomPermission: PropTypes.array, toggleRoomE2EEncryptionPermission: PropTypes.array, viewBroadcastMemberListPermission: PropTypes.array, - transferLivechatGuestPermission: PropTypes.array, - addTeamMemberPermission: PropTypes.array + transferLivechatGuestPermission: PropTypes.array } constructor(props) { @@ -174,18 +173,13 @@ class RoomActionsView extends React.Component { canAddUser = async() => { const { room, joined } = this.state; const { - addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission, addTeamMemberPermission + addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission } = this.props; const { rid, t } = room; let canAddUser = false; - let permissions; const userInRoom = joined; - if (room.teamMain) { - permissions = await RocketChat.hasPermission([addTeamMemberPermission], rid); - } else { - permissions = await RocketChat.hasPermission([addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission], rid); - } + const permissions = await RocketChat.hasPermission([addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission], rid); if (userInRoom && permissions[0]) { canAddUser = true; @@ -337,20 +331,6 @@ class RoomActionsView extends React.Component { } } - addMemberToTeam = async() => { - const { room } = this.state; - const { setLoadingInvite, navigation } = this.props; - try { - setLoadingInvite(true); - await RocketChat.addTeamMember(room.name); - navigation.pop(); - } catch (e) { - log(e); - } finally { - setLoadingInvite(false); - } - } - toggleBlockUser = async() => { logEvent(events.RA_TOGGLE_BLOCK_USER); const { room } = this.state; @@ -699,7 +679,7 @@ class RoomActionsView extends React.Component { params: { rid, title: I18n.t('Add_users'), - nextAction: room.teamId ? this.addMemberToTeam : this.addUser + nextAction: this.addUser } })} testID='room-actions-add-user' @@ -952,7 +932,6 @@ const mapStateToProps = state => ({ serverVersion: state.server.version, isMasterDetail: state.app.isMasterDetail, addUserToJoinedRoomPermission: state.permissions['add-user-to-joined-room'], - addTeamMemberPermission: state.permissions['add-team-member'], addUserToAnyCRoomPermission: state.permissions['add-user-to-any-c-room'], addUserToAnyPRoomPermission: state.permissions['add-user-to-any-p-room'], createInviteLinksPermission: state.permissions['create-invite-links'], diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 8dadbb4f68..7b38eb9ade 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -177,7 +177,7 @@ class RoomMembersView extends React.Component { ); if (teamChannels) { navigation.navigate('SelectListView', { - title: 'Remove_Member', subtitle: 'Remove_User_Teams', teamChannels, selectedUser + title: 'Remove_Member', infoText: 'Remove_User_Teams', data: teamChannels, nextAction: (selectedChannels = {}) => this.removeFromTeam({ selectedUser, selectedChannels }) }); } else { Alert.alert( @@ -199,11 +199,17 @@ class RoomMembersView extends React.Component { } } - removeFromTeam = async(selectedUser) => { + removeFromTeam = async(params) => { try { const { members, membersFiltered, room } = this.state; + const { selectedUser, selected } = params; const userId = selectedUser._id; - const result = await RocketChat.removeTeamMember({ teamName: room.name, userId }); + const result = await RocketChat.removeTeamMember({ + teamId: room.teamId, + teamName: room.name, + userId, + ...(selected && { rooms: selected }) + }); if (result.success) { const message = I18n.t('User_has_been_removed_from_s', { s: RocketChat.getRoomTitle(room) }); EventEmitter.emit(LISTENER, { message }); From f138e10b0e77a223056d6a989f8415079618ba52 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 25 May 2021 14:41:42 -0400 Subject: [PATCH 55/77] Update Alert --- app/views/RoomMembersView/index.js | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 7b38eb9ade..f10ac08868 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { FlatList, Alert } from 'react-native'; +import { FlatList } from 'react-native'; import { connect } from 'react-redux'; import { Q } from '@nozbe/watermelondb'; import * as List from '../../containers/List'; @@ -180,22 +180,11 @@ class RoomMembersView extends React.Component { title: 'Remove_Member', infoText: 'Remove_User_Teams', data: teamChannels, nextAction: (selectedChannels = {}) => this.removeFromTeam({ selectedUser, selectedChannels }) }); } else { - Alert.alert( - I18n.t('Confirmation'), - I18n.t('Removing_user_from_this_Team', { user: selectedUser.username }), - [ - { - text: I18n.t('Cancel'), - style: 'cancel' - }, - { - text: I18n.t('Yes_action_it', { action: I18n.t('remove') }), - style: 'destructive', - onPress: () => this.removeFromTeam(selectedUser) - } - ], - { cancelable: false } - ); + showConfirmationAlert({ + message: I18n.t('Removing_user_from_this_Team', { user: selectedUser.username }), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('remove') }), + onPress: () => this.removeFromTeam({ selectedUser }) + }); } } From 98d5f0e5d295ad71c0c2fcd4b8cd569529fe747a Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 25 May 2021 14:45:27 -0400 Subject: [PATCH 56/77] Minor tweaks --- app/lib/methods/getPermissions.js | 1 - app/views/RoomActionsView/index.js | 4 +--- app/views/RoomMembersView/index.js | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index 8a837e4b19..cc1dd46e0e 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -13,7 +13,6 @@ const PERMISSIONS = [ 'add-user-to-any-c-room', 'add-user-to-any-p-room', 'add-user-to-joined-room', - 'add-team-member', 'add-team-channel', 'archive-room', 'auto-translate', diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 555c03cf20..72ec2548ba 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -172,9 +172,7 @@ class RoomActionsView extends React.Component { canAddUser = async() => { const { room, joined } = this.state; - const { - addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission - } = this.props; + const { addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission } = this.props; const { rid, t } = room; let canAddUser = false; diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index f10ac08868..fe0c721750 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -353,7 +353,6 @@ class RoomMembersView extends React.Component { this.setState({ isLoading: true }); try { const membersResult = await RocketChat.getRoomMembers(rid, allUsers, members.length, PAGE_SIZE); - const newMembers = membersResult.records; this.setState({ members: members.concat(newMembers || []), From 6399269a75bad917f912e05c9bd67fca50eea6d7 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 25 May 2021 15:03:53 -0400 Subject: [PATCH 57/77] Minor tweaks --- app/views/RoomMembersView/index.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index fe0c721750..d570864874 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -100,7 +100,7 @@ class RoomMembersView extends React.Component { } = this.props; const result = await RocketChat.hasPermission([ - muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, ...(room.TeamId && [editTeamMemberPermission]) + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, ...(room.teamMain ? [editTeamMemberPermission] : []) ], room.rid); this.permissions = { @@ -109,7 +109,7 @@ class RoomMembersView extends React.Component { [PERMISSION_SET_OWNER]: result[2], [PERMISSION_SET_MODERATOR]: result[3], [PERMISSION_REMOVE_USER]: result[4], - ...(room.teamId && { [PERMISSION_EDIT_TEAM_MEMBER]: result[5] }) + ...(room.teamMain ? { [PERMISSION_EDIT_TEAM_MEMBER]: result[5] } : {}) }; const hasSinglePermission = Object.values(this.permissions).some(p => !!p); @@ -191,6 +191,7 @@ class RoomMembersView extends React.Component { removeFromTeam = async(params) => { try { const { members, membersFiltered, room } = this.state; + const { navigation } = this.props; const { selectedUser, selected } = params; const userId = selectedUser._id; const result = await RocketChat.removeTeamMember({ @@ -208,6 +209,7 @@ class RoomMembersView extends React.Component { members: newMembers, membersFiltered: newMembersFiltered }); + navigation.goBack(); } } catch (e) { log(e); @@ -298,7 +300,7 @@ class RoomMembersView extends React.Component { } // Remove from room - if (this.permissions['remove-user']) { + if (this.permissions['remove-user'] && !room.teamMain) { options.push({ icon: 'logout', title: I18n.t('Remove_from_room'), @@ -539,7 +541,7 @@ const mapStateToProps = state => ({ setOwnerPermission: state.permissions[PERMISSION_SET_OWNER], setModeratorPermission: state.permissions[PERMISSION_SET_MODERATOR], removeUserPermission: state.permissions[PERMISSION_REMOVE_USER], - editTeamMemberPermission: state.permissions['edit-team-member'] + editTeamMemberPermission: state.permissions[PERMISSION_EDIT_TEAM_MEMBER] }); export default connect(mapStateToProps)(withActionSheet(withTheme(RoomMembersView))); From 3844471e4cf8a9b0dee78a0b8d65b00262f5ca3f Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 25 May 2021 15:55:30 -0400 Subject: [PATCH 58/77] Minor tweak --- app/views/RoomMembersView/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index d570864874..3b20a9e010 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -177,7 +177,10 @@ class RoomMembersView extends React.Component { ); if (teamChannels) { navigation.navigate('SelectListView', { - title: 'Remove_Member', infoText: 'Remove_User_Teams', data: teamChannels, nextAction: (selectedChannels = {}) => this.removeFromTeam({ selectedUser, selectedChannels }) + title: 'Remove_Member', + infoText: 'Remove_User_Teams', + data: teamChannels, + nextAction: (selectedChannels = {}) => this.removeFromTeam({ selectedUser, selectedChannels }) }); } else { showConfirmationAlert({ From 6a16add3fa7d4b146e19f958db705f8e0704b2e3 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 25 May 2021 16:20:43 -0400 Subject: [PATCH 59/77] Update showActionSheet on RoomMembersView --- app/i18n/locales/en.json | 3 +++ app/views/RoomMembersView/index.js | 18 +++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 6de129da27..c66de14420 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -686,6 +686,9 @@ "Set_as_leader": "Set as leader", "Set_as_moderator": "Set as moderator", "Set_as_owner": "Set as owner", + "Leader": "Leader", + "Moderator": "Moderator", + "Owner": "Owner", "Remove_as_leader": "Remove as leader", "Remove_as_moderator": "Remove as moderator", "Remove_as_owner": "Remove as owner", diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 3b20a9e010..c064b12290 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -26,6 +26,7 @@ import { withActionSheet } from '../../containers/ActionSheet'; import { showConfirmationAlert } from '../../utils/info'; import SafeAreaView from '../../containers/SafeAreaView'; import { goRoom } from '../../utils/goRoom'; +import { CustomIcon } from '../../lib/Icons'; const PAGE_SIZE = 25; @@ -221,7 +222,7 @@ class RoomMembersView extends React.Component { onPressUser = (selectedUser) => { const { room } = this.state; - const { showActionSheet, user } = this.props; + const { showActionSheet, user, theme } = this.props; const options = [{ icon: 'message', @@ -275,8 +276,9 @@ class RoomMembersView extends React.Component { const isOwner = userRoleResult?.roles.includes('owner'); options.push({ icon: 'shield-check', - title: I18n.t(isOwner ? 'Remove_as_owner' : 'Set_as_owner'), - onPress: () => this.handleOwner(selectedUser, !isOwner) + title: I18n.t('Owner'), + onPress: () => this.handleOwner(selectedUser, !isOwner), + right: () => }); } @@ -286,8 +288,9 @@ class RoomMembersView extends React.Component { const isLeader = userRoleResult?.roles.includes('leader'); options.push({ icon: 'shield-alt', - title: I18n.t(isLeader ? 'Remove_as_leader' : 'Set_as_leader'), - onPress: () => this.handleLeader(selectedUser, !isLeader) + title: I18n.t('Leader'), + onPress: () => this.handleLeader(selectedUser, !isLeader), + right: () => }); } @@ -297,8 +300,9 @@ class RoomMembersView extends React.Component { const isModerator = userRoleResult?.roles.includes('moderator'); options.push({ icon: 'shield', - title: I18n.t(isModerator ? 'Remove_as_moderator' : 'Set_as_moderator'), - onPress: () => this.handleModerator(selectedUser, !isModerator) + title: I18n.t('Moderator'), + onPress: () => this.handleModerator(selectedUser, !isModerator), + right: () => }); } From 750e21ac467a3aafcd5d8429d85515af90420722 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Tue, 25 May 2021 17:51:45 -0300 Subject: [PATCH 60/77] Remove team main from query and move code around --- app/views/RoomMembersView/index.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index c064b12290..4bd4dbf255 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -174,7 +174,8 @@ class RoomMembersView extends React.Component { const db = database.active; const subCollection = db.get('subscriptions'); const teamChannels = await subCollection.query( - Q.where('team_id', Q.eq(room.teamId)) + Q.where('team_id', room.teamId), + Q.where('team_main', null) ); if (teamChannels) { navigation.navigate('SelectListView', { @@ -260,16 +261,6 @@ class RoomMembersView extends React.Component { }); } - // Remove from team - if (this.permissions['edit-team-member']) { - options.push({ - icon: 'close', - danger: true, - title: I18n.t('Remove_from_Team'), - onPress: () => this.handleRemoveFromTeam(selectedUser) - }); - } - // Owner if (this.permissions['set-owner']) { const userRoleResult = this.roomRoles.find(r => r.u._id === selectedUser._id); @@ -306,6 +297,16 @@ class RoomMembersView extends React.Component { }); } + // Remove from team + if (this.permissions['edit-team-member']) { + options.push({ + icon: 'logout', + danger: true, + title: I18n.t('Remove_from_Team'), + onPress: () => this.handleRemoveFromTeam(selectedUser) + }); + } + // Remove from room if (this.permissions['remove-user'] && !room.teamMain) { options.push({ From a08a24db5484da6a2481fb34d4802a4bc977cb82 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 26 May 2021 11:05:32 -0400 Subject: [PATCH 61/77] Fetch roles --- app/i18n/locales/en.json | 9 +-------- app/views/RoomMembersView/index.js | 14 ++++++++------ app/views/SelectListView.js | 22 ++++++++++++++++++---- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index c66de14420..b4fd729bd4 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -683,15 +683,9 @@ "No_threads_following": "You are not following any threads", "No_threads_unread": "There are no unread threads", "Messagebox_Send_to_channel": "Send to channel", - "Set_as_leader": "Set as leader", - "Set_as_moderator": "Set as moderator", - "Set_as_owner": "Set as owner", "Leader": "Leader", "Moderator": "Moderator", "Owner": "Owner", - "Remove_as_leader": "Remove as leader", - "Remove_as_moderator": "Remove as moderator", - "Remove_as_owner": "Remove as owner", "Remove_from_room": "Remove from room", "Ignore": "Ignore", "Unignore": "Unignore", @@ -737,10 +731,9 @@ "Cannot_leave": "Cannot leave", "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", "last-owner-can-not-be-removed": "Last owner cannot be removed", - "Removing_user_from_this_Team": "You are removing {{user}} from this Team", + "Removing_user_from_this_team": "You are removing {{user}} from this team", "Remove_User_Teams": "Select channels you want the user to be removed from.", "Remove_Member": "Remove Member", - "Error": "Error", "leaving_team": "leaving team", "member-does-not-exist": "Member does not exist" } diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 4bd4dbf255..b62841d542 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -23,7 +23,7 @@ import { withTheme } from '../../theme'; import { themes } from '../../constants/colors'; import { getUserSelector } from '../../selectors/login'; import { withActionSheet } from '../../containers/ActionSheet'; -import { showConfirmationAlert } from '../../utils/info'; +import { showConfirmationAlert, showErrorAlert } from '../../utils/info'; import SafeAreaView from '../../containers/SafeAreaView'; import { goRoom } from '../../utils/goRoom'; import { CustomIcon } from '../../lib/Icons'; @@ -182,22 +182,24 @@ class RoomMembersView extends React.Component { title: 'Remove_Member', infoText: 'Remove_User_Teams', data: teamChannels, - nextAction: (selectedChannels = {}) => this.removeFromTeam({ selectedUser, selectedChannels }) + extraData: selectedUser, + nextAction: selected => this.removeFromTeam(selectedUser, selected), + showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_leave')) }); } else { showConfirmationAlert({ - message: I18n.t('Removing_user_from_this_Team', { user: selectedUser.username }), + message: I18n.t('Removing_user_from_this_team', { user: selectedUser.username }), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('remove') }), - onPress: () => this.removeFromTeam({ selectedUser }) + onPress: () => this.removeFromTeam(selectedUser) }); } } - removeFromTeam = async(params) => { + removeFromTeam = async(selectedUser, selected) => { try { const { members, membersFiltered, room } = this.state; const { navigation } = this.props; - const { selectedUser, selected } = params; + const userId = selectedUser._id; const result = await RocketChat.removeTeamMember({ teamId: room.teamId, diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 9c886da804..2f2e57eb19 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -15,6 +15,8 @@ import { withTheme } from '../theme'; import SafeAreaView from '../containers/SafeAreaView'; import { animateNextTransition } from '../utils/layoutAnimation'; import Loading from '../containers/Loading'; +import RocketChat from '../lib/rocketchat'; +import log from '../utils/log'; const styles = StyleSheet.create({ buttonText: { @@ -39,10 +41,11 @@ class SelectListView extends React.Component { this.infoText = props.route?.params?.infoText; this.nextAction = props.route?.params?.nextAction; this.showAlert = props.route?.params?.showAlert; + this.extraData = props.route?.params?.extraData; this.state = { data, selected: [], - loading: false + loading: true }; this.setHeader(); } @@ -94,12 +97,23 @@ class SelectListView extends React.Component { } } + fetchUserRoles = async(room, user) => { + try { + const result = await RocketChat.getRoomRoles(room.rid, room.t); + const userRoles = result.roles.find(r => r.u._id === user._id); + this.setState({ loading: false }); + return userRoles; + } catch (e) { + log(e); + } + } + renderItem = ({ item }) => { const { theme } = this.props; - const alert = item.roles.length; - + const hasRoles = this.fetchUserRoles(item, this.extraData); + const alert = this.extraData ? hasRoles : item.roles.length; const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; - const checked = this.isChecked(item.rid, item.roles) ? 'check' : null; + const checked = this.isChecked(item.rid) ? 'check' : null; return ( <> From 55aa2942fe4836f148d0226c6e03f22fc3273eec Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 26 May 2021 13:08:39 -0400 Subject: [PATCH 62/77] Update RoomMembersView and SelectListView --- app/i18n/locales/en.json | 4 +++- app/views/RoomMembersView/index.js | 38 ++++++++++++++++++++++++++---- app/views/SelectListView.js | 24 +++---------------- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index b4fd729bd4..13e245544f 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -729,11 +729,13 @@ "Leave_Team": "Leave Team", "Select_Team_Channels": "Select the Team's channels you would like to leave.", "Cannot_leave": "Cannot leave", + "Cannot_remove": "Cannot remove", "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", "last-owner-can-not-be-removed": "Last owner cannot be removed", "Removing_user_from_this_team": "You are removing {{user}} from this team", - "Remove_User_Teams": "Select channels you want the user to be removed from.", + "Remove_User_Team_Channels": "Select the channels you want the user to be removed from.", "Remove_Member": "Remove Member", "leaving_team": "leaving team", + "removing_team": "removing from team", "member-does-not-exist": "Member does not exist" } diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index b62841d542..70724f01cc 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -168,6 +168,15 @@ class RoomMembersView extends React.Component { } } + fetchChannelsRoles = async(room) => { + try { + const result = await RocketChat.getRoomRoles(room.rid, room.t); + return result.roles; + } catch (e) { + log(e); + } + } + handleRemoveFromTeam = async(selectedUser) => { const { navigation } = this.props; const { room } = this.state; @@ -177,12 +186,21 @@ class RoomMembersView extends React.Component { Q.where('team_id', room.teamId), Q.where('team_main', null) ); + const channels = await Promise.all(teamChannels.map(async(channel) => { + const roles = await this.fetchChannelsRoles(channel); + const userRoles = roles.find(r => r.u._id === selectedUser._id); + return ({ + rid: channel.rid, + name: channel.name, + roles: userRoles + }); + })); + if (teamChannels) { navigation.navigate('SelectListView', { title: 'Remove_Member', - infoText: 'Remove_User_Teams', - data: teamChannels, - extraData: selectedUser, + infoText: 'Remove_User_Team_Channels', + data: channels, nextAction: selected => this.removeFromTeam(selectedUser, selected), showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_leave')) }); @@ -198,7 +216,7 @@ class RoomMembersView extends React.Component { removeFromTeam = async(selectedUser, selected) => { try { const { members, membersFiltered, room } = this.state; - const { navigation } = this.props; + const { navigation, isMasterDetail } = this.props; const userId = selectedUser._id; const result = await RocketChat.removeTeamMember({ @@ -216,10 +234,20 @@ class RoomMembersView extends React.Component { members: newMembers, membersFiltered: newMembersFiltered }); - navigation.goBack(); + if (isMasterDetail) { + navigation.navigate('RoomMembersView'); + } else { + navigation.goBack(); + } } } catch (e) { log(e); + showErrorAlert( + e.data.error + ? I18n.t(e.data.error) + : I18n.t('There_was_an_error_while_action', { action: I18n.t('removing_team') }), + I18n.t('Cannot_remove') + ); } } diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 2f2e57eb19..afef8ab89e 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -14,9 +14,6 @@ import { themes } from '../constants/colors'; import { withTheme } from '../theme'; import SafeAreaView from '../containers/SafeAreaView'; import { animateNextTransition } from '../utils/layoutAnimation'; -import Loading from '../containers/Loading'; -import RocketChat from '../lib/rocketchat'; -import log from '../utils/log'; const styles = StyleSheet.create({ buttonText: { @@ -41,11 +38,9 @@ class SelectListView extends React.Component { this.infoText = props.route?.params?.infoText; this.nextAction = props.route?.params?.nextAction; this.showAlert = props.route?.params?.showAlert; - this.extraData = props.route?.params?.extraData; this.state = { data, - selected: [], - loading: true + selected: [] }; this.setHeader(); } @@ -97,21 +92,9 @@ class SelectListView extends React.Component { } } - fetchUserRoles = async(room, user) => { - try { - const result = await RocketChat.getRoomRoles(room.rid, room.t); - const userRoles = result.roles.find(r => r.u._id === user._id); - this.setState({ loading: false }); - return userRoles; - } catch (e) { - log(e); - } - } - renderItem = ({ item }) => { const { theme } = this.props; - const hasRoles = this.fetchUserRoles(item, this.extraData); - const alert = this.extraData ? hasRoles : item.roles.length; + const alert = item.roles?.length; const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; const checked = this.isChecked(item.rid) ? 'check' : null; @@ -132,7 +115,7 @@ class SelectListView extends React.Component { } render() { - const { loading, data } = this.state; + const { data } = this.state; const { theme } = this.props; return ( @@ -147,7 +130,6 @@ class SelectListView extends React.Component { contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} keyboardShouldPersistTaps='always' /> - ); } From b1bde5ef8723ce52810022aa90ba62e8b748f0a2 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 26 May 2021 15:24:23 -0400 Subject: [PATCH 63/77] Update rocketchat.js --- app/lib/rocketchat.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 2ee91c97cf..6ac432548b 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -794,10 +794,6 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.delete', { teamName }); }, - updateTeamRoom({ roomId, isDefault }) { - // RC 3.13.0 - return this.post('teams.updateRoom', { roomId, isDefault }); - }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 From c9266f63f13c04e02dda8726f89f1d63168460c6 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 26 May 2021 16:24:49 -0400 Subject: [PATCH 64/77] Updated leaveTeam and handleRemoveFromTeam --- app/lib/rocketchat.js | 4 ++ app/views/RoomActionsView/index.js | 22 ++++---- app/views/RoomMembersView/index.js | 87 +++++++++++++++++------------- app/views/SelectListView.js | 5 +- 4 files changed, 67 insertions(+), 51 deletions(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index dd6538f91f..5fb3a649be 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -790,6 +790,10 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.updateRoom', { roomId, isDefault }); }, + teamListRoomsOfUser({ teamId, userId }) { + // RC 3.13.0 + return this.sdk.get('teams.listRoomsOfUser', { teamId, userId }); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 3256dd0b97..112cd31947 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -5,7 +5,6 @@ import { } from 'react-native'; import { connect } from 'react-redux'; import isEmpty from 'lodash/isEmpty'; -import { Q } from '@nozbe/watermelondb'; import { compareServerVersion, methods } from '../../lib/utils'; import Touch from '../../utils/touch'; @@ -429,18 +428,19 @@ class RoomActionsView extends React.Component { } leaveTeam = async() => { - const { room } = this.state; - const { navigation } = this.props; - try { - const db = database.active; - const subCollection = db.get('subscriptions'); - const teamChannels = await subCollection.query( - Q.where('team_id', room.teamId), - Q.where('team_main', null) - ); + const { room } = this.state; + const { navigation } = this.props; + + const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: room.u._id }); - if (teamChannels.length) { + if (result.success) { + const teamChannels = result.rooms.map(r => ({ + rid: r._id, + name: r.name, + teamId: r.teamId, + alert: r.isLastOwner + })); navigation.navigate('SelectListView', { title: 'Leave_Team', data: teamChannels, diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 70724f01cc..0be77e06a6 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -36,6 +36,8 @@ const PERMISSION_SET_OWNER = 'set-owner'; const PERMISSION_SET_MODERATOR = 'set-moderator'; const PERMISSION_REMOVE_USER = 'remove-user'; const PERMISSION_EDIT_TEAM_MEMBER = 'edit-team-member'; +const PERMISION_VIEW_ALL_TEAMS = 'view-all-teams'; +const PERMISSION_VIEW_ALL_TEAM_CHANNELS = 'view-all-team-channels'; class RoomMembersView extends React.Component { static propTypes = { @@ -58,7 +60,9 @@ class RoomMembersView extends React.Component { setOwnerPermission: PropTypes.array, setModeratorPermission: PropTypes.array, removeUserPermission: PropTypes.array, - editTeamMemberPermission: PropTypes.array + editTeamMemberPermission: PropTypes.array, + viewAllTeamChannelsPermission: PropTypes.array, + viewAllTeamsPermission: PropTypes.array } constructor(props) { @@ -97,11 +101,11 @@ class RoomMembersView extends React.Component { const { room } = this.state; const { - muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, editTeamMemberPermission + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, editTeamMemberPermission, viewAllTeamChannelsPermission, viewAllTeamsPermission } = this.props; const result = await RocketChat.hasPermission([ - muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, ...(room.teamMain ? [editTeamMemberPermission] : []) + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, ...(room.teamMain ? [editTeamMemberPermission, viewAllTeamChannelsPermission, viewAllTeamsPermission] : []) ], room.rid); this.permissions = { @@ -110,7 +114,11 @@ class RoomMembersView extends React.Component { [PERMISSION_SET_OWNER]: result[2], [PERMISSION_SET_MODERATOR]: result[3], [PERMISSION_REMOVE_USER]: result[4], - ...(room.teamMain ? { [PERMISSION_EDIT_TEAM_MEMBER]: result[5] } : {}) + ...(room.teamMain ? { + [PERMISSION_EDIT_TEAM_MEMBER]: result[5], + [PERMISSION_VIEW_ALL_TEAM_CHANNELS]: result[6], + [PERMISION_VIEW_ALL_TEAMS]: result[7] + } : {}) }; const hasSinglePermission = Object.values(this.permissions).some(p => !!p); @@ -178,38 +186,41 @@ class RoomMembersView extends React.Component { } handleRemoveFromTeam = async(selectedUser) => { - const { navigation } = this.props; - const { room } = this.state; - const db = database.active; - const subCollection = db.get('subscriptions'); - const teamChannels = await subCollection.query( - Q.where('team_id', room.teamId), - Q.where('team_main', null) - ); - const channels = await Promise.all(teamChannels.map(async(channel) => { - const roles = await this.fetchChannelsRoles(channel); - const userRoles = roles.find(r => r.u._id === selectedUser._id); - return ({ - rid: channel.rid, - name: channel.name, - roles: userRoles - }); - })); - - if (teamChannels) { - navigation.navigate('SelectListView', { - title: 'Remove_Member', - infoText: 'Remove_User_Team_Channels', - data: channels, - nextAction: selected => this.removeFromTeam(selectedUser, selected), - showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_leave')) - }); - } else { - showConfirmationAlert({ - message: I18n.t('Removing_user_from_this_team', { user: selectedUser.username }), - confirmationText: I18n.t('Yes_action_it', { action: I18n.t('remove') }), - onPress: () => this.removeFromTeam(selectedUser) - }); + try { + const { navigation } = this.props; + const { room } = this.state; + + const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: selectedUser._id }); + + if (result.success) { + const teamChannels = result.rooms.map(r => ({ + rid: r._id, + name: r.name, + teamId: r.teamId, + alert: r.isLastOwner + })); + navigation.navigate('SelectListView', { + title: 'Remove_Member', + infoText: 'Remove_User_Team_Channels', + data: teamChannels, + nextAction: selected => this.removeFromTeam(selectedUser, selected), + showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_remove')) + }); + } else { + showConfirmationAlert({ + message: I18n.t('Removing_user_from_this_team', { user: selectedUser.username }), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('remove') }), + onPress: () => this.removeFromTeam(selectedUser) + }); + } + } catch (e) { + log(e); + showErrorAlert( + e.data.error + ? I18n.t(e.data.error) + : I18n.t('There_was_an_error_while_action', { action: I18n.t('removing_team') }), + I18n.t('Cannot_remove') + ); } } @@ -579,7 +590,9 @@ const mapStateToProps = state => ({ setOwnerPermission: state.permissions[PERMISSION_SET_OWNER], setModeratorPermission: state.permissions[PERMISSION_SET_MODERATOR], removeUserPermission: state.permissions[PERMISSION_REMOVE_USER], - editTeamMemberPermission: state.permissions[PERMISSION_EDIT_TEAM_MEMBER] + editTeamMemberPermission: state.permissions[PERMISSION_EDIT_TEAM_MEMBER], + viewAllTeamChannelsPermission: state.permissions[PERMISSION_VIEW_ALL_TEAM_CHANNELS], + viewAllTeamsPermission: state.permissions[PERMISION_VIEW_ALL_TEAMS] }); export default connect(mapStateToProps)(withActionSheet(withTheme(RoomMembersView))); diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index afef8ab89e..bcbb0923f7 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -94,7 +94,6 @@ class SelectListView extends React.Component { renderItem = ({ item }) => { const { theme } = this.props; - const alert = item.roles?.length; const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; const checked = this.isChecked(item.rid) ? 'check' : null; @@ -105,8 +104,8 @@ class SelectListView extends React.Component { title={item.name} translateTitle={false} testID={`select-list-view-item-${ item.name }`} - onPress={() => (alert ? this.showAlert() : this.toggleItem(item.rid))} - alert={alert} + onPress={() => (item.alert ? this.showAlert() : this.toggleItem(item.rid))} + alert={item.alert} left={() => } right={() => (checked ? : null)} /> From 04697720009b5562390f9fb06b7eb7921c5e0b49 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 26 May 2021 16:27:14 -0400 Subject: [PATCH 65/77] Fix validation --- app/views/RoomActionsView/index.js | 2 +- app/views/RoomMembersView/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 112cd31947..45a8c11031 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -434,7 +434,7 @@ class RoomActionsView extends React.Component { const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: room.u._id }); - if (result.success) { + if (result.rooms?.length) { const teamChannels = result.rooms.map(r => ({ rid: r._id, name: r.name, diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 0be77e06a6..102819b7ae 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -192,7 +192,7 @@ class RoomMembersView extends React.Component { const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: selectedUser._id }); - if (result.success) { + if (result.rooms?.length) { const teamChannels = result.rooms.map(r => ({ rid: r._id, name: r.name, From f1815cea1ecced802c89e4c081a159aea3fcf95b Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 26 May 2021 16:29:38 -0400 Subject: [PATCH 66/77] Remove unnecessary function --- app/views/RoomMembersView/index.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 102819b7ae..c7810bd5d4 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -176,15 +176,6 @@ class RoomMembersView extends React.Component { } } - fetchChannelsRoles = async(room) => { - try { - const result = await RocketChat.getRoomRoles(room.rid, room.t); - return result.roles; - } catch (e) { - log(e); - } - } - handleRemoveFromTeam = async(selectedUser) => { try { const { navigation } = this.props; From a70a7478802e90252144a3cdcd12ba4e7051c734 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 26 May 2021 17:07:45 -0400 Subject: [PATCH 67/77] Update RoomActionsView --- app/views/RoomActionsView/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index a4a4b2b590..89d34ed074 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -428,10 +428,10 @@ class RoomActionsView extends React.Component { } leaveTeam = async() => { - try { - const { room } = this.state; - const { navigation } = this.props; + const { room } = this.state; + const { navigation } = this.props; + try { const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: room.u._id }); if (result.rooms?.length) { From 9c33263793cf80a8caf37bd9c0e2d9c62081a5dd Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 26 May 2021 17:11:07 -0400 Subject: [PATCH 68/77] Update en.json --- app/i18n/locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index c6fb162279..b41c4ce3fd 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -732,15 +732,15 @@ "Cannot_remove": "Cannot remove", "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", "last-owner-can-not-be-removed": "Last owner cannot be removed", - "member-does-not-exist": "Member does not exist", "Remove_User_Teams": "Select channels you want the user to be removed from.", - "Remove_Member": "Remove Member", "Delete_Team": "Delete Team", "Delete_Team_Warning": "You are deleting this team.", "Removing_user_from_this_team": "You are removing {{user}} from this team", "Remove_User_Team_Channels": "Select the channels you want the user to be removed from.", + "Remove_Member": "Remove Member", "leaving_team": "leaving team", "removing_team": "removing from team", + "member-does-not-exist": "Member does not exist", "Load_More": "Load More", "Load_Newer": "Load Newer", "Load_Older": "Load Older" From a77906c3ca4b7cf2bcb0ef17b7c70ead0c3005dc Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 27 May 2021 09:07:49 -0400 Subject: [PATCH 69/77] updated deleteTeam function and permissions --- app/i18n/locales/en.json | 5 +- app/lib/methods/getPermissions.js | 1 + app/lib/rocketchat.js | 4 +- app/views/RoomInfoEditView/index.js | 162 ++++++++++++++++------------ app/views/SelectListView.js | 5 +- 5 files changed, 101 insertions(+), 76 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index b41c4ce3fd..a5ba3603d7 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -730,16 +730,19 @@ "Select_Team_Channels": "Select the Team's channels you would like to leave.", "Cannot_leave": "Cannot leave", "Cannot_remove": "Cannot remove", + "Cannot_delete": "Cannot delete", "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", "last-owner-can-not-be-removed": "Last owner cannot be removed", "Remove_User_Teams": "Select channels you want the user to be removed from.", "Delete_Team": "Delete Team", - "Delete_Team_Warning": "You are deleting this team.", + "Select_channels_to_delete": "This can't be undone. Once you delete a team, all chat content and configuration will be deleted. \n\nSelect the channels you would like to delete. The ones you decide to keep, will be available on your workspace. Notice that public channels will still be public and visible to everyone.", + "You_are_deleting_the_team": "You are deleting this team.", "Removing_user_from_this_team": "You are removing {{user}} from this team", "Remove_User_Team_Channels": "Select the channels you want the user to be removed from.", "Remove_Member": "Remove Member", "leaving_team": "leaving team", "removing_team": "removing from team", + "deleting_team": "deleting team", "member-does-not-exist": "Member does not exist", "Load_More": "Load More", "Load_Newer": "Load Newer", diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index cc1dd46e0e..99a18a6c08 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -20,6 +20,7 @@ const PERMISSIONS = [ 'delete-c', 'delete-message', 'delete-p', + 'delete-team', 'edit-message', 'edit-room', 'edit-team-member', diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 131db7d51e..4774b42722 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -790,9 +790,9 @@ const RocketChat = { // RC 3.13.0 return this.post('teams.updateRoom', { roomId, isDefault }); }, - deleteTeam({ teamName }) { + deleteTeam({ teamId, roomsToRemove }) { // RC 3.13.0 - return this.post('teams.delete', { teamName }); + return this.post('teams.delete', { teamId, roomsToRemove }); }, teamListRoomsOfUser({ teamId, userId }) { // RC 3.13.0 diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index 1986e2725f..779b02ab55 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -9,15 +9,15 @@ import ImagePicker from 'react-native-image-crop-picker'; import { dequal } from 'dequal'; import isEmpty from 'lodash/isEmpty'; import { Q } from '@nozbe/watermelondb'; -import { compareServerVersion, methods } from '../../lib/utils'; +import { compareServerVersion, methods } from '../../lib/utils'; import database from '../../lib/database'; import { deleteRoom as deleteRoomAction } from '../../actions/room'; import KeyboardView from '../../presentation/KeyboardView'; import sharedStyles from '../Styles'; import styles from './styles'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; -import { showErrorAlert } from '../../utils/info'; +import { showConfirmationAlert, showErrorAlert } from '../../utils/info'; import { LISTENER } from '../../containers/Toast'; import EventEmitter from '../../utils/events'; import RocketChat from '../../lib/rocketchat'; @@ -42,7 +42,7 @@ const PERMISSION_ARCHIVE = 'archive-room'; const PERMISSION_UNARCHIVE = 'unarchive-room'; const PERMISSION_DELETE_C = 'delete-c'; const PERMISSION_DELETE_P = 'delete-p'; -const PERMISSION_EDIT_TEAM_CHANNEL = 'edit-team-channel'; +const PERMISSION_DELETE_TEAM = 'delete-team'; class RoomInfoEditView extends React.Component { static navigationOptions = () => ({ @@ -62,7 +62,8 @@ class RoomInfoEditView extends React.Component { unarchiveRoomPermission: PropTypes.array, deleteCPermission: PropTypes.array, deletePPermission: PropTypes.array, - editTeamChannelPermission: PropTypes.array + deleteTeamPermission: PropTypes.array, + isMasterDetail: PropTypes.bool }; constructor(props) { @@ -105,7 +106,7 @@ class RoomInfoEditView extends React.Component { unarchiveRoomPermission, deleteCPermission, deletePPermission, - editTeamChannelPermission + deleteTeamPermission } = this.props; const rid = route.params?.rid; if (!rid) { @@ -121,51 +122,27 @@ class RoomInfoEditView extends React.Component { this.init(this.room); }); - let result; - - if (this.room.teamId) { - result = await RocketChat.hasPermission([ - setReadOnlyPermission, - setReactWhenReadOnlyPermission, - archiveRoomPermission, - unarchiveRoomPermission, - deleteCPermission, - deletePPermission, - editTeamChannelPermission - ], rid); - - this.setState({ - permissions: { - [PERMISSION_SET_READONLY]: result[0], - [PERMISSION_SET_REACT_WHEN_READONLY]: result[1], - [PERMISSION_ARCHIVE]: result[2], - [PERMISSION_UNARCHIVE]: result[3], - [PERMISSION_DELETE_C]: result[4], - [PERMISSION_DELETE_P]: result[5], - [PERMISSION_EDIT_TEAM_CHANNEL]: result[6] - } - }); - } else { - result = await RocketChat.hasPermission([ - setReadOnlyPermission, - setReactWhenReadOnlyPermission, - archiveRoomPermission, - unarchiveRoomPermission, - deleteCPermission, - deletePPermission - ], rid); - - this.setState({ - permissions: { - [PERMISSION_SET_READONLY]: result[0], - [PERMISSION_SET_REACT_WHEN_READONLY]: result[1], - [PERMISSION_ARCHIVE]: result[2], - [PERMISSION_UNARCHIVE]: result[3], - [PERMISSION_DELETE_C]: result[4], - [PERMISSION_DELETE_P]: result[5] - } - }); - } + const result = await RocketChat.hasPermission([ + setReadOnlyPermission, + setReactWhenReadOnlyPermission, + archiveRoomPermission, + unarchiveRoomPermission, + deleteCPermission, + deletePPermission, + ...(this.room.teamMain ? [deleteTeamPermission] : []) + ], rid); + + this.setState({ + permissions: { + [PERMISSION_SET_READONLY]: result[0], + [PERMISSION_SET_REACT_WHEN_READONLY]: result[1], + [PERMISSION_ARCHIVE]: result[2], + [PERMISSION_UNARCHIVE]: result[3], + [PERMISSION_DELETE_C]: result[4], + [PERMISSION_DELETE_P]: result[5], + ...(this.room.teamMain && { [PERMISSION_DELETE_TEAM]: result[6] }) + } + }); } catch (e) { log(e); } @@ -315,27 +292,62 @@ class RoomInfoEditView extends React.Component { }, 100); } - deleteTeam = async(teamName) => { - const { navigation } = this.props; + handleDeleteTeam = async(selected) => { + const { navigation, isMasterDetail } = this.props; const { room } = this.state; try { - const result = await RocketChat.deleteTeam({ teamName }); + const result = await RocketChat.deleteTeam({ teamId: room.teamId, ...(selected && { roomsToRemove: selected }) }); if (result.success) { - const db = database.active; - const subCollection = db.get('subscriptions'); - const teamChannels = await subCollection.query( - Q.and(Q.where('team_id', Q.eq(this.room.teamId), Q.where('name', Q.notEq(this.room.name)))) - ); - if (teamChannels.length) { - navigation.navigate('SelectListView', { - title: 'Delete_Team', teamChannels: this.teamChannels, teamName: room.name, subtitle: 'Select_Teams', delete: this.delete - }); + if (isMasterDetail) { + navigation.navigate('DrawerNavigator'); } else { navigation.navigate('RoomsListView'); } } } catch (e) { log(e); + showErrorAlert( + e.data.error + ? I18n.t(e.data.error) + : I18n.t('There_was_an_error_while_action', { action: I18n.t('deleting_team') }), + I18n.t('Cannot_leave') + ); + } + } + + deleteTeam = async() => { + const { room } = this.state; + const { navigation } = this.props; + + try { + const db = database.active; + const subCollection = db.get('subscriptions'); + const teamChannels = await subCollection.query( + Q.where('team_id', room.teamId), + Q.where('team_main', null) + ); + + if (teamChannels.length) { + navigation.navigate('SelectListView', { + title: 'Delete_Team', + data: teamChannels, + infoText: 'Select_channels_to_delete', + nextAction: data => this.handleDeleteTeam(data), + showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_delete')) + }); + } else { + showConfirmationAlert({ + message: I18n.t('You_are_deleting_the_team', { team: RocketChat.getRoomTitle(room) }), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('delete') }), + onPress: () => this.handleDeleteTeam() + }); + } + } catch (e) { + showConfirmationAlert({ + message: I18n.t('You_are_deleting_the_team', { team: RocketChat.getRoomTitle(room) }), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('delete') }), + onPress: () => this.handleDeleteTeam() + }); } } @@ -344,8 +356,8 @@ class RoomInfoEditView extends React.Component { const { deleteRoom } = this.props; Alert.alert( - I18n.t('Confirmation'), - I18n.t('Delete_Team_Warning'), + I18n.t('Are_you_sure_question_mark'), + I18n.t('Delete_Room_Warning'), [ { text: I18n.t('Cancel'), @@ -354,7 +366,7 @@ class RoomInfoEditView extends React.Component { { text: I18n.t('Yes_action_it', { action: I18n.t('delete') }), style: 'destructive', - onPress: () => (this.room.teamId ? this.deleteTeam(room.name) : deleteRoom(room.rid, room.t)) + onPress: () => deleteRoom(room.rid, room.t) } ], { cancelable: false } @@ -394,9 +406,16 @@ class RoomInfoEditView extends React.Component { hasDeletePermission = () => { const { room, permissions } = this.state; - return ( - room.t === 'p' ? permissions[PERMISSION_DELETE_P] : permissions[PERMISSION_DELETE_C] - ); + + if (room.teamMain) { + return permissions[PERMISSION_DELETE_TEAM]; + } + + if (room.t === 'p') { + return permissions[PERMISSION_DELETE_P]; + } + + return permissions[PERMISSION_DELETE_C]; } hasArchivePermission = () => { @@ -702,7 +721,7 @@ class RoomInfoEditView extends React.Component { { borderColor: dangerColor }, !this.hasDeletePermission() && sharedStyles.opacity5 ]} - onPress={this.delete} + onPress={room.teamMain ? this.deleteTeam : this.delete} disabled={!this.hasDeletePermission()} testID='room-info-edit-view-delete' > @@ -733,8 +752,9 @@ const mapStateToProps = state => ({ archiveRoomPermission: state.permissions[PERMISSION_ARCHIVE], unarchiveRoomPermission: state.permissions[PERMISSION_UNARCHIVE], deleteCPermission: state.permissions[PERMISSION_DELETE_C], - deletePPermission: state.permissions[PERMISSION_DELETE_P], - editTeamChannelPermission: state.permissions[PERMISSION_EDIT_TEAM_CHANNEL] + deletePermission: state.permissions[PERMISSION_DELETE_P], + deleteTeamPermission: state.permissions[PERMISSION_DELETE_TEAM], + isMasterDetail: state.app.isMasterDetail }); const mapDispatchToProps = dispatch => ({ diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index bcbb0923f7..58c55a5672 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -95,6 +95,7 @@ class SelectListView extends React.Component { renderItem = ({ item }) => { const { theme } = this.props; const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; + const alert = item.alert || item.roles.length; const checked = this.isChecked(item.rid) ? 'check' : null; return ( @@ -104,8 +105,8 @@ class SelectListView extends React.Component { title={item.name} translateTitle={false} testID={`select-list-view-item-${ item.name }`} - onPress={() => (item.alert ? this.showAlert() : this.toggleItem(item.rid))} - alert={item.alert} + onPress={() => (alert ? this.showAlert() : this.toggleItem(item.rid))} + alert={alert} left={() => } right={() => (checked ? : null)} /> From 139a31bd93c2cfdc71a9e20023be3c7028f6c090 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 27 May 2021 09:22:03 -0400 Subject: [PATCH 70/77] Added showConfirmationAlert --- app/views/RoomInfoEditView/index.js | 11 +++++++++-- app/views/SelectListView.js | 5 ++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index 779b02ab55..1ba8848e76 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -332,11 +332,18 @@ class RoomInfoEditView extends React.Component { title: 'Delete_Team', data: teamChannels, infoText: 'Select_channels_to_delete', - nextAction: data => this.handleDeleteTeam(data), - showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_delete')) + nextAction: () => { + showConfirmationAlert({ + title: I18n.t('Confirmation'), + message: I18n.t('You_are_deleting_the_team', { team: RocketChat.getRoomTitle(room) }), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('delete') }), + onPress: data => this.handleDeleteTeam(data) + }); + } }); } else { showConfirmationAlert({ + title: I18n.t('Confirmation'), message: I18n.t('You_are_deleting_the_team', { team: RocketChat.getRoomTitle(room) }), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('delete') }), onPress: () => this.handleDeleteTeam() diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 58c55a5672..bcbb0923f7 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -95,7 +95,6 @@ class SelectListView extends React.Component { renderItem = ({ item }) => { const { theme } = this.props; const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; - const alert = item.alert || item.roles.length; const checked = this.isChecked(item.rid) ? 'check' : null; return ( @@ -105,8 +104,8 @@ class SelectListView extends React.Component { title={item.name} translateTitle={false} testID={`select-list-view-item-${ item.name }`} - onPress={() => (alert ? this.showAlert() : this.toggleItem(item.rid))} - alert={alert} + onPress={() => (item.alert ? this.showAlert() : this.toggleItem(item.rid))} + alert={item.alert} left={() => } right={() => (checked ? : null)} /> From cc6b13dfe168b18d0d5dd779f014c86a77724b37 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 27 May 2021 09:31:53 -0400 Subject: [PATCH 71/77] Added string translations for teams --- app/i18n/locales/en.json | 3 +++ app/views/RoomInfoEditView/index.js | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index a5ba3603d7..30a59f15b3 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -90,6 +90,7 @@ "alert": "alert", "alerts": "alerts", "All_users_in_the_channel_can_write_new_messages": "All users in the channel can write new messages", + "All_users_in_the_team_can_write_new_messages": "All users in the team can write new messages", "A_meaningful_name_for_the_discussion_room": "A meaningful name for the discussion room", "All": "All", "All_Messages": "All Messages", @@ -225,6 +226,7 @@ "Encryption_error_title": "Your encryption password seems wrong", "Encryption_error_desc": "It wasn't possible to decode your encryption key to be imported.", "Everyone_can_access_this_channel": "Everyone can access this channel", + "Everyone_can_access_this_team": "Everyone can access this team", "Error_uploading": "Error uploading", "Expiration_Days": "Expiration (Days)", "Favorite": "Favorite", @@ -286,6 +288,7 @@ "Join_our_open_workspace": "Join our open workspace", "Join_your_workspace": "Join your workspace", "Just_invited_people_can_access_this_channel": "Just invited people can access this channel", + "Just_invited_people_can_access_this_team": "Just invited people can access this team", "Language": "Language", "last_message": "last message", "Leave_channel": "Leave channel", diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index 1ba8848e76..2b0fcc8834 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -594,9 +594,9 @@ class RoomInfoEditView extends React.Component { Date: Thu, 27 May 2021 09:38:29 -0400 Subject: [PATCH 72/77] Fix permission --- app/views/RoomInfoEditView/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index 2b0fcc8834..6ec64f435e 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -759,7 +759,7 @@ const mapStateToProps = state => ({ archiveRoomPermission: state.permissions[PERMISSION_ARCHIVE], unarchiveRoomPermission: state.permissions[PERMISSION_UNARCHIVE], deleteCPermission: state.permissions[PERMISSION_DELETE_C], - deletePermission: state.permissions[PERMISSION_DELETE_P], + deletePPermission: state.permissions[PERMISSION_DELETE_P], deleteTeamPermission: state.permissions[PERMISSION_DELETE_TEAM], isMasterDetail: state.app.isMasterDetail }); From 786583a897295be2e86eb12a0b6960de54ea7057 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 27 May 2021 13:49:04 -0400 Subject: [PATCH 73/77] Added moveChannelToTeam and convertToTeam functionality --- app/containers/RoomHeader/index.js | 5 +- app/i18n/locales/en.json | 9 ++ app/lib/methods/getPermissions.js | 1 + app/lib/rocketchat.js | 14 +++ app/views/RoomActionsView/index.js | 153 ++++++++++++++++++++++++++++- app/views/RoomView/RightButtons.js | 4 + app/views/RoomView/index.js | 7 +- app/views/SelectListView.js | 16 ++- 8 files changed, 198 insertions(+), 11 deletions(-) diff --git a/app/containers/RoomHeader/index.js b/app/containers/RoomHeader/index.js index 4eeab701f2..7d4d22de87 100644 --- a/app/containers/RoomHeader/index.js +++ b/app/containers/RoomHeader/index.js @@ -32,7 +32,7 @@ class RoomHeaderContainer extends Component { shouldComponentUpdate(nextProps) { const { - type, title, subtitle, status, statusText, connecting, connected, onPress, usersTyping, width, height + type, title, subtitle, status, statusText, connecting, connected, onPress, usersTyping, width, height, teamMain } = this.props; if (nextProps.type !== type) { return true; @@ -67,6 +67,9 @@ class RoomHeaderContainer extends Component { if (nextProps.onPress !== onPress) { return true; } + if (nextProps.teamMain !== teamMain) { + return true; + } return false; } diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 30a59f15b3..d316594958 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -181,6 +181,7 @@ "delete": "delete", "Delete": "Delete", "DELETE": "DELETE", + "move": "move", "deleting_room": "deleting room", "description": "description", "Description": "Description", @@ -730,6 +731,7 @@ "invalid-room": "Invalid room", "You_are_leaving_the_team": "You are leaving the team '{{team}}'", "Leave_Team": "Leave Team", + "Select_Team": "Select Team", "Select_Team_Channels": "Select the Team's channels you would like to leave.", "Cannot_leave": "Cannot leave", "Cannot_remove": "Cannot remove", @@ -745,8 +747,15 @@ "Remove_Member": "Remove Member", "leaving_team": "leaving team", "removing_team": "removing from team", + "moving_channel_to_team": "moving channel to team", "deleting_team": "deleting team", "member-does-not-exist": "Member does not exist", + "Convert": "Convert", + "Convert_to_Team": "Convert to Team", + "Convert_to_Team_Warning": "This can't be undone. Once you convert a channel to a team, you can not turn it back to a channel.", + "Move_to_Team": "Move to Team", + "Move_Channel_to_Team": "Move Channel to Team", + "Move_Channel_Paragraph": "Moving a channel inside a team means that this channel will be added in the team’s context, however, all channel’s members, which are not members of the respective team, will still have access to this channel, but will not be added as team’s members. \n\nAll channel’s management will still be made by the owners of this channel.\n\nTeam’s members and even team’s owners, if not a member of this channel, can not have access to the channel’s content. \n\nPlease notice that the Team’s owner will be able remove members from the Channel.", "Load_More": "Load More", "Load_Newer": "Load Newer", "Load_Older": "Load Older" diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index 99a18a6c08..2b7da47652 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -17,6 +17,7 @@ const PERMISSIONS = [ 'archive-room', 'auto-translate', 'create-invite-links', + 'create-team', 'delete-c', 'delete-message', 'delete-p', diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 4774b42722..f174aa1eb4 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -798,6 +798,20 @@ const RocketChat = { // RC 3.13.0 return this.sdk.get('teams.listRoomsOfUser', { teamId, userId }); }, + convertChannelToTeam({ rid, name, type }) { + const params = { + ...(type === 'c' + ? { + channelId: rid, + channelName: name + } + : { + roomId: rid, + roomName: name + }) + }; + return this.sdk.post(type === 'c' ? 'channels.convertToTeam' : 'groups.convertToTeam', params); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 89d34ed074..e20b7b5eeb 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -5,8 +5,9 @@ import { } from 'react-native'; import { connect } from 'react-redux'; import isEmpty from 'lodash/isEmpty'; -import { compareServerVersion, methods } from '../../lib/utils'; +import { Q } from '@nozbe/watermelondb'; +import { compareServerVersion, methods } from '../../lib/utils'; import Touch from '../../utils/touch'; import { setLoading as setLoadingAction } from '../../actions/selectedUsers'; import { leaveRoom as leaveRoomAction, closeRoom as closeRoomAction } from '../../actions/room'; @@ -61,7 +62,9 @@ class RoomActionsView extends React.Component { editRoomPermission: PropTypes.array, toggleRoomE2EEncryptionPermission: PropTypes.array, viewBroadcastMemberListPermission: PropTypes.array, - transferLivechatGuestPermission: PropTypes.array + transferLivechatGuestPermission: PropTypes.array, + createTeamPermission: PropTypes.array, + addTeamChannelPermission: PropTypes.array } constructor(props) { @@ -83,7 +86,9 @@ class RoomActionsView extends React.Component { canForwardGuest: false, canReturnQueue: false, canEdit: false, - canToggleEncryption: false + canToggleEncryption: false, + canCreateTeam: false, + canAddChannelToTeam: false }; if (room && room.observe && room.rid) { this.roomObservable = room.observe(); @@ -132,9 +137,11 @@ class RoomActionsView extends React.Component { const canEdit = await this.canEdit(); const canToggleEncryption = await this.canToggleEncryption(); const canViewMembers = await this.canViewMembers(); + const canCreateTeam = await this.canCreateTeam(); + const canAddChannelToTeam = await this.canAddChannelToTeam(); this.setState({ - canAutoTranslate, canAddUser, canInviteUser, canEdit, canToggleEncryption, canViewMembers + canAutoTranslate, canAddUser, canInviteUser, canEdit, canToggleEncryption, canViewMembers, canCreateTeam, canAddChannelToTeam }); // livechat permissions @@ -210,6 +217,26 @@ class RoomActionsView extends React.Component { return canEdit; } + canCreateTeam = async() => { + const { room } = this.state; + const { createTeamPermission } = this.props; + const { rid } = room; + const permissions = await RocketChat.hasPermission([createTeamPermission], rid); + + const canCreateTeam = permissions[0]; + return canCreateTeam; + } + + canAddChannelToTeam = async() => { + const { room } = this.state; + const { addTeamChannelPermission } = this.props; + const { rid } = room; + const permissions = await RocketChat.hasPermission([addTeamChannelPermission], rid); + + const canAddChannelToTeam = permissions[0]; + return canAddChannelToTeam; + } + canToggleEncryption = async() => { const { room } = this.state; const { toggleRoomE2EEncryptionPermission } = this.props; @@ -464,6 +491,74 @@ class RoomActionsView extends React.Component { } } + handleConvertToTeam = async() => { + try { + const { room } = this.state; + const { navigation } = this.props; + const result = await RocketChat.convertChannelToTeam({ rid: room.rid, name: room.name, type: room.t }); + + if (result.success) { + navigation.navigate('RoomView'); + } + } catch (e) { + log(e); + } + } + + convertToTeam = () => { + showConfirmationAlert({ + title: I18n.t('Confirmation'), + message: I18n.t('Convert_to_Team_Warning'), + confirmationText: I18n.t('Convert'), + onPress: () => this.handleConvertToTeam() + }); + } + + handleMoveToTeam = async(selected) => { + try { + const { room } = this.state; + const { navigation } = this.props; + const result = await RocketChat.addRoomsToTeam({ teamId: selected.teamId, rooms: [room.rid] }); + if (result.success) { + navigation.navigate('RoomView'); + } + } catch (e) { + log(e); + showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('moving_channel_to_team') })); + } + } + + moveToTeam = async() => { + try { + const { navigation } = this.props; + const db = database.active; + const subCollection = db.get('subscriptions'); + const teamChannels = await subCollection.query( + Q.where('team_main', Q.notEq(null)) + ); + navigation.navigate('SelectListView', { + title: 'Move_to_Team', + infoText: 'Move_Channel_Paragraph', + nextAction: () => navigation.push('SelectListView', { + title: 'Select_Team', + data: teamChannels, + isRadio: true, + search: true, + nextAction: () => { + showConfirmationAlert({ + title: I18n.t('Confirmation'), + message: I18n.t('Convert_to_Team_Warning'), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('move') }), + onPress: selected => this.handleConvertToTeam(selected) + }); + } + }) + }); + } catch (e) { + log(e); + } + } + renderRoomInfo = () => { const { room, member } = this.state; const { @@ -635,6 +730,50 @@ class RoomActionsView extends React.Component { } } + teamChannelActions = (t, room) => { + const { canEdit, canCreateTeam, canAddChannelToTeam } = this.state; + const canConvertToTeam = canEdit && canCreateTeam && !room.teamMain; + const canMoveToTeam = canEdit && canAddChannelToTeam && !room.teamId; + + return ( + <> + {['c', 'p'].includes(t) && canConvertToTeam + ? ( + <> + this.onPressTouchable({ + event: this.convertToTeam + })} + testID='room-actions-convert-to-team' + left={() => } + showActionIndicator + /> + + + ) + : null} + + {['c', 'p'].includes(t) && canMoveToTeam + ? ( + <> + this.onPressTouchable({ + event: this.moveToTeam + })} + testID='room-actions-convert-to-team' + left={() => } + showActionIndicator + /> + + + ) + : null} + + ); + } + render() { const { room, membersCount, canViewMembers, canAddUser, canInviteUser, joined, canAutoTranslate, canForwardGuest, canReturnQueue @@ -836,6 +975,8 @@ class RoomActionsView extends React.Component { ) : null} + { this.teamChannelActions(t, room) } + {['l'].includes(t) && !this.isOmnichannelPreview ? ( <> @@ -922,7 +1063,9 @@ const mapStateToProps = state => ({ editRoomPermission: state.permissions['edit-room'], toggleRoomE2EEncryptionPermission: state.permissions['toggle-room-e2e-encryption'], viewBroadcastMemberListPermission: state.permissions['view-broadcast-member-list'], - transferLivechatGuestPermission: state.permissions['transfer-livechat-guest'] + transferLivechatGuestPermission: state.permissions['transfer-livechat-guest'], + createTeamPermission: state.permissions['create-team'], + addTeamChannelPermission: state.permissions['add-team-channel'] }); const mapDispatchToProps = dispatch => ({ diff --git a/app/views/RoomView/RightButtons.js b/app/views/RoomView/RightButtons.js index f61488b5bb..5b283b4ad0 100644 --- a/app/views/RoomView/RightButtons.js +++ b/app/views/RoomView/RightButtons.js @@ -59,6 +59,10 @@ class RightButtonsContainer extends Component { const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state; + const { teamId } = this.props; + if (nextProps.teamId !== teamId) { + return true; + } if (nextState.isFollowingThread !== isFollowingThread) { return true; } diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 18d123ec41..f8ac079d90 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -85,7 +85,7 @@ const stateAttrsUpdate = [ 'member', 'showingBlockingLoader' ]; -const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'tunread', 'muted', 'ignored', 'jitsiTimeout', 'announcement', 'sysMes', 'topic', 'name', 'fname', 'roles', 'bannerClosed', 'visitor', 'joinCodeRequired']; +const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'tunread', 'muted', 'ignored', 'jitsiTimeout', 'announcement', 'sysMes', 'topic', 'name', 'fname', 'roles', 'bannerClosed', 'visitor', 'joinCodeRequired', 'teamMain', 'teamId']; class RoomView extends React.Component { static propTypes = { @@ -254,7 +254,10 @@ class RoomView extends React.Component { this.setHeader(); } } - if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name)) && !this.tmid) { + if (roomUpdate.teamMain !== prevState.roomUpdate.teamMain) { + this.setHeader(); + } + if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name) || (roomUpdate.teamMain !== prevState.roomUpdate.teamMain)) && !this.tmid) { this.setHeader(); } if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) { diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index bcbb0923f7..2418b21684 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -38,6 +38,8 @@ class SelectListView extends React.Component { this.infoText = props.route?.params?.infoText; this.nextAction = props.route?.params?.nextAction; this.showAlert = props.route?.params?.showAlert; + this.search = props.route?.params?.search; + this.isRadio = props.route?.params?.isRadio; this.state = { data, selected: [] @@ -94,9 +96,17 @@ class SelectListView extends React.Component { renderItem = ({ item }) => { const { theme } = this.props; - const icon = item.t === 'p' ? 'channel-private' : 'channel-public'; + const { selected } = this.state; + + const channelIcon = item.t === 'p' ? 'channel-private' : 'channel-public'; + const icon = item.teamMain ? 'team' : channelIcon; const checked = this.isChecked(item.rid) ? 'check' : null; + const toggle = () => (this.isRadio ? this.toggleRadioItem(item.rid) : this.toggleItem(item.rid)); + const showCheck = () => (checked ? : null); + // not sure about the icon name, prob doesn't even exist, maybe i'll have to create a component for this + const showRadio = () => (this.isRadio ? : null); + return ( <> @@ -104,10 +114,10 @@ class SelectListView extends React.Component { title={item.name} translateTitle={false} testID={`select-list-view-item-${ item.name }`} - onPress={() => (item.alert ? this.showAlert() : this.toggleItem(item.rid))} + onPress={() => (item.alert ? this.showAlert() : toggle())} alert={item.alert} left={() => } - right={() => (checked ? : null)} + right={() => (this.isRadio ? showRadio() : showCheck())} /> ); From 88ab8ad744ac4caa93a1f101b2c70c552ff63d80 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 27 May 2021 15:46:45 -0400 Subject: [PATCH 74/77] Fix SelectListView RadioButton --- app/views/RoomActionsView/index.js | 34 +++++++++++++++++------------- app/views/SelectListView.js | 27 +++++++++++++----------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index e20b7b5eeb..73e50cd827 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -536,24 +536,28 @@ class RoomActionsView extends React.Component { const teamChannels = await subCollection.query( Q.where('team_main', Q.notEq(null)) ); - navigation.navigate('SelectListView', { - title: 'Move_to_Team', - infoText: 'Move_Channel_Paragraph', - nextAction: () => navigation.push('SelectListView', { - title: 'Select_Team', - data: teamChannels, - isRadio: true, - search: true, + + if (teamChannels.length) { + navigation.navigate('SelectListView', { + title: 'Move_to_Team', + infoText: 'Move_Channel_Paragraph', nextAction: () => { - showConfirmationAlert({ - title: I18n.t('Confirmation'), - message: I18n.t('Convert_to_Team_Warning'), - confirmationText: I18n.t('Yes_action_it', { action: I18n.t('move') }), - onPress: selected => this.handleConvertToTeam(selected) + navigation.push('SelectListView', { + title: 'Select_Team', + data: teamChannels, + isRadio: true, + search: true, + nextAction: () => showConfirmationAlert({ + title: I18n.t('Confirmation'), + message: I18n.t('Move_to_Team_Warning'), + confirmationText: I18n.t('Yes_action_it', { action: I18n.t('move') }), + onPress: selected => this.handleMoveToTeam(selected) + }) + }); } - }) - }); + }); + } } catch (e) { log(e); } diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 2418b21684..9a9bc0a4dd 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -4,6 +4,7 @@ import { View, StyleSheet, FlatList, Text } from 'react-native'; import { connect } from 'react-redux'; +import { RadioButton } from 'react-native-ui-lib'; import * as List from '../containers/List'; import sharedStyles from './Styles'; @@ -14,6 +15,7 @@ import { themes } from '../constants/colors'; import { withTheme } from '../theme'; import SafeAreaView from '../containers/SafeAreaView'; import { animateNextTransition } from '../utils/layoutAnimation'; +import { ICON_SIZE } from '../containers/List/constants'; const styles = StyleSheet.create({ buttonText: { @@ -70,6 +72,7 @@ class SelectListView extends React.Component { renderInfoText = () => { const { theme } = this.props; + return ( {I18n.t(this.infoText)} @@ -86,7 +89,11 @@ class SelectListView extends React.Component { const { selected } = this.state; animateNextTransition(); - if (!this.isChecked(rid)) { + if (this.isRadio) { + if (!this.isChecked(rid)) { + this.setState({ selected: [rid] }, () => this.setHeader()); + } + } else if (!this.isChecked(rid)) { this.setState({ selected: [...selected, rid] }, () => this.setHeader()); } else { const filterSelected = selected.filter(el => el !== rid); @@ -99,14 +106,11 @@ class SelectListView extends React.Component { const { selected } = this.state; const channelIcon = item.t === 'p' ? 'channel-private' : 'channel-public'; - const icon = item.teamMain ? 'team' : channelIcon; + const teamIcon = item.t === 'p' ? 'teams-private' : 'teams'; + const icon = item.teamMain ? teamIcon : channelIcon; const checked = this.isChecked(item.rid) ? 'check' : null; - - const toggle = () => (this.isRadio ? this.toggleRadioItem(item.rid) : this.toggleItem(item.rid)); - const showCheck = () => (checked ? : null); - // not sure about the icon name, prob doesn't even exist, maybe i'll have to create a component for this - const showRadio = () => (this.isRadio ? : null); - + const showRadio = () => ; + const showCheck = () => ; return ( <> @@ -114,8 +118,8 @@ class SelectListView extends React.Component { title={item.name} translateTitle={false} testID={`select-list-view-item-${ item.name }`} - onPress={() => (item.alert ? this.showAlert() : toggle())} - alert={item.alert} + onPress={() => (item?.alert ? this.showAlert() : this.toggleItem(item.rid))} + alert={item?.alert} left={() => } right={() => (this.isRadio ? showRadio() : showCheck())} /> @@ -126,7 +130,6 @@ class SelectListView extends React.Component { render() { const { data } = this.state; const { theme } = this.props; - return ( @@ -135,7 +138,7 @@ class SelectListView extends React.Component { extraData={this.state} keyExtractor={item => item.rid} renderItem={this.renderItem} - ListHeaderComponent={this.renderInfoText} + ListHeaderComponent={this.infoText ? this.renderInfoText : null} contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} keyboardShouldPersistTaps='always' /> From 587d20e0b0d6d01abc1ed177423ca28d09baa950 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 27 May 2021 16:02:47 -0400 Subject: [PATCH 75/77] Fix moveToTeam --- app/i18n/locales/en.json | 1 + app/views/RoomActionsView/index.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 8b8472fca9..8785ddcd74 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -757,6 +757,7 @@ "Move_to_Team": "Move to Team", "Move_Channel_to_Team": "Move Channel to Team", "Move_Channel_Paragraph": "Moving a channel inside a team means that this channel will be added in the team’s context, however, all channel’s members, which are not members of the respective team, will still have access to this channel, but will not be added as team’s members. \n\nAll channel’s management will still be made by the owners of this channel.\n\nTeam’s members and even team’s owners, if not a member of this channel, can not have access to the channel’s content. \n\nPlease notice that the Team’s owner will be able remove members from the Channel.", + "Move_to_Team_Warning": "After reading the previous intructions about this behavior, do you still want to move this channel to the selected team?", "Load_More": "Load More", "Load_Newer": "Load Newer", "Load_Older": "Load Older" diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 73e50cd827..3d4cb0cbda 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -547,11 +547,11 @@ class RoomActionsView extends React.Component { data: teamChannels, isRadio: true, search: true, - nextAction: () => showConfirmationAlert({ + nextAction: selected => showConfirmationAlert({ title: I18n.t('Confirmation'), message: I18n.t('Move_to_Team_Warning'), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('move') }), - onPress: selected => this.handleMoveToTeam(selected) + onPress: () => this.handleMoveToTeam(selected) }) }); From e0e14efea150fe922831ab6fc6319131b0e0820e Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 27 May 2021 17:24:40 -0400 Subject: [PATCH 76/77] Added searchBar to SelectListVIew --- app/views/RoomActionsView/index.js | 41 +++++++++++++++++++++++++++--- app/views/SelectListView.js | 40 ++++++++++++++++++++++++----- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 3d4cb0cbda..1b7148b504 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -528,25 +528,58 @@ class RoomActionsView extends React.Component { } } + searchTeam = async(onChangeText) => { + try { + const { addTeamChannelPermission, createTeamPermission } = this.props; + const QUERY_SIZE = 50; + const db = database.active; + const teams = await db.collections + .get('subscriptions') + .query( + Q.where('team_main', Q.notEq(null)), + Q.where('name', Q.like(`%${ onChangeText }%`)), + Q.experimentalTake(QUERY_SIZE), + Q.experimentalSortBy('room_updated_at', Q.desc) + ); + + const asyncFilter = async(teamArray) => { + const results = await Promise.all(teamArray.map(async(team) => { + const permissions = await RocketChat.hasPermission([addTeamChannelPermission, createTeamPermission], team.rid); + if (!permissions[0]) { + return false; + } + return true; + })); + + return teamArray.filter((_v, index) => results[index]); + }; + const teamsFiltered = await asyncFilter(teams); + return teamsFiltered; + } catch (e) { + log(e); + } + } + moveToTeam = async() => { try { const { navigation } = this.props; const db = database.active; const subCollection = db.get('subscriptions'); - const teamChannels = await subCollection.query( + const teamRooms = await subCollection.query( Q.where('team_main', Q.notEq(null)) ); - if (teamChannels.length) { + if (teamRooms.length) { navigation.navigate('SelectListView', { title: 'Move_to_Team', infoText: 'Move_Channel_Paragraph', nextAction: () => { navigation.push('SelectListView', { title: 'Select_Team', - data: teamChannels, + data: teamRooms, isRadio: true, - search: true, + isSearch: true, + onSearch: onChangeText => this.searchTeam(onChangeText), nextAction: selected => showConfirmationAlert({ title: I18n.t('Confirmation'), message: I18n.t('Move_to_Team_Warning'), diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index 9a9bc0a4dd..de52fa5fce 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -6,6 +6,7 @@ import { import { connect } from 'react-redux'; import { RadioButton } from 'react-native-ui-lib'; +import { log } from 'react-native-reanimated'; import * as List from '../containers/List'; import sharedStyles from './Styles'; import I18n from '../i18n'; @@ -16,6 +17,8 @@ import { withTheme } from '../theme'; import SafeAreaView from '../containers/SafeAreaView'; import { animateNextTransition } from '../utils/layoutAnimation'; import { ICON_SIZE } from '../containers/List/constants'; +import SearchBox from '../containers/SearchBox'; + const styles = StyleSheet.create({ buttonText: { @@ -40,10 +43,13 @@ class SelectListView extends React.Component { this.infoText = props.route?.params?.infoText; this.nextAction = props.route?.params?.nextAction; this.showAlert = props.route?.params?.showAlert; - this.search = props.route?.params?.search; + this.isSearch = props.route?.params?.isSearch; + this.onSearch = props.route?.params?.onSearch; this.isRadio = props.route?.params?.isRadio; this.state = { data, + dataFiltered: [], + isSearching: false, selected: [] }; this.setHeader(); @@ -72,7 +78,6 @@ class SelectListView extends React.Component { renderInfoText = () => { const { theme } = this.props; - return ( {I18n.t(this.infoText)} @@ -80,6 +85,25 @@ class SelectListView extends React.Component { ); } + renderSearch = () => { + const { theme } = this.props; + return ( + + this.search(text)} testID='select-list-view-search' onCancelPress={() => this.setState({ isSearching: false })} /> + + ); + } + + search = async(text) => { + try { + this.setState({ isSearching: true }); + const result = await this.onSearch(text); + this.setState({ dataFiltered: result }); + } catch (e) { + log(e); + } + } + isChecked = (rid) => { const { selected } = this.state; return selected.includes(rid); @@ -109,8 +133,10 @@ class SelectListView extends React.Component { const teamIcon = item.t === 'p' ? 'teams-private' : 'teams'; const icon = item.teamMain ? teamIcon : channelIcon; const checked = this.isChecked(item.rid) ? 'check' : null; + const showRadio = () => ; const showCheck = () => ; + return ( <> @@ -118,8 +144,8 @@ class SelectListView extends React.Component { title={item.name} translateTitle={false} testID={`select-list-view-item-${ item.name }`} - onPress={() => (item?.alert ? this.showAlert() : this.toggleItem(item.rid))} - alert={item?.alert} + onPress={() => (item.alert ? this.showAlert() : this.toggleItem(item.rid))} + alert={item.alert} left={() => } right={() => (this.isRadio ? showRadio() : showCheck())} /> @@ -128,17 +154,17 @@ class SelectListView extends React.Component { } render() { - const { data } = this.state; + const { data, isSearching, dataFiltered } = this.state; const { theme } = this.props; return ( item.rid} renderItem={this.renderItem} - ListHeaderComponent={this.infoText ? this.renderInfoText : null} + ListHeaderComponent={this.isSearch ? this.renderSearch : this.renderInfoText} contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} keyboardShouldPersistTaps='always' /> From 540a2b25aac653d9c38d7f9f00b0ce903f8c34d4 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 31 May 2021 12:43:39 -0400 Subject: [PATCH 77/77] Update RoomView , SelectListVIew and string translation for error --- app/i18n/locales/en.json | 2 +- app/views/RoomActionsView/index.js | 64 +++++++++++++++--------------- app/views/RoomView/index.js | 4 +- app/views/SelectListView.js | 2 +- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 7027885ad3..090bf5cd05 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -14,7 +14,7 @@ "error-delete-protected-role": "Cannot delete a protected role", "error-department-not-found": "Department not found", "error-direct-message-file-upload-not-allowed": "File sharing not allowed in direct messages", - "error-duplicate-channel-name": "A channel with name {{channel_name}} exists", + "error-duplicate-channel-name": "A channel with name {{room_name}} exists", "error-email-domain-blacklisted": "The email domain is blacklisted", "error-email-send-failed": "Error trying to send email: {{message}}", "error-save-image": "Error while saving image", diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 1b7148b504..7199843c8c 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -528,38 +528,6 @@ class RoomActionsView extends React.Component { } } - searchTeam = async(onChangeText) => { - try { - const { addTeamChannelPermission, createTeamPermission } = this.props; - const QUERY_SIZE = 50; - const db = database.active; - const teams = await db.collections - .get('subscriptions') - .query( - Q.where('team_main', Q.notEq(null)), - Q.where('name', Q.like(`%${ onChangeText }%`)), - Q.experimentalTake(QUERY_SIZE), - Q.experimentalSortBy('room_updated_at', Q.desc) - ); - - const asyncFilter = async(teamArray) => { - const results = await Promise.all(teamArray.map(async(team) => { - const permissions = await RocketChat.hasPermission([addTeamChannelPermission, createTeamPermission], team.rid); - if (!permissions[0]) { - return false; - } - return true; - })); - - return teamArray.filter((_v, index) => results[index]); - }; - const teamsFiltered = await asyncFilter(teams); - return teamsFiltered; - } catch (e) { - log(e); - } - } - moveToTeam = async() => { try { const { navigation } = this.props; @@ -596,6 +564,38 @@ class RoomActionsView extends React.Component { } } + searchTeam = async(onChangeText) => { + try { + const { addTeamChannelPermission, createTeamPermission } = this.props; + const QUERY_SIZE = 50; + const db = database.active; + const teams = await db.collections + .get('subscriptions') + .query( + Q.where('team_main', Q.notEq(null)), + Q.where('name', Q.like(`%${ onChangeText }%`)), + Q.experimentalTake(QUERY_SIZE), + Q.experimentalSortBy('room_updated_at', Q.desc) + ); + + const asyncFilter = async(teamArray) => { + const results = await Promise.all(teamArray.map(async(team) => { + const permissions = await RocketChat.hasPermission([addTeamChannelPermission, createTeamPermission], team.rid); + if (!permissions[0]) { + return false; + } + return true; + })); + + return teamArray.filter((_v, index) => results[index]); + }; + const teamsFiltered = await asyncFilter(teams); + return teamsFiltered; + } catch (e) { + log(e); + } + } + renderRoomInfo = () => { const { room, member } = this.state; const { diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index f8ac079d90..13de89c87d 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -254,10 +254,10 @@ class RoomView extends React.Component { this.setHeader(); } } - if (roomUpdate.teamMain !== prevState.roomUpdate.teamMain) { + if ((roomUpdate.teamMain !== prevState.roomUpdate.teamMain) || (roomUpdate.teamId !== prevState.roomUpdate.teamId)) { this.setHeader(); } - if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name) || (roomUpdate.teamMain !== prevState.roomUpdate.teamMain)) && !this.tmid) { + if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name) || (roomUpdate.teamMain !== prevState.roomUpdate.teamMain) || (roomUpdate.teamId !== prevState.roomUpdate.teamId)) && !this.tmid) { this.setHeader(); } if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) { diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js index de52fa5fce..a3ad3f8898 100644 --- a/app/views/SelectListView.js +++ b/app/views/SelectListView.js @@ -6,7 +6,7 @@ import { import { connect } from 'react-redux'; import { RadioButton } from 'react-native-ui-lib'; -import { log } from 'react-native-reanimated'; +import log from '../utils/log'; import * as List from '../containers/List'; import sharedStyles from './Styles'; import I18n from '../i18n';