diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js index b5d487493..267a6a4d2 100644 --- a/app/i18n/locales/en.js +++ b/app/i18n/locales/en.js @@ -631,5 +631,9 @@ export default { After_seconds_set_by_admin: 'After {{seconds}} seconds (set by admin)', Dont_activate: 'Don\'t activate now', Queued_chats: 'Queued chats', - Queue_is_empty: 'Queue is empty' + Queue_is_empty: 'Queue is empty', + Logout_from_other_logged_in_locations: 'Logout from other logged in locations', + You_will_be_logged_out_from_other_locations: 'You\'ll be logged out from other locations.', + Logged_out_of_other_clients_successfully: 'Logged out of other clients successfully', + Logout_failed: 'Logout failed!' }; diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js index 5ba23d793..0216ab843 100644 --- a/app/i18n/locales/pt-BR.js +++ b/app/i18n/locales/pt-BR.js @@ -577,5 +577,9 @@ export default { After_seconds_set_by_admin: 'Após {{seconds}} segundos (Configurado pelo adm)', Dont_activate: 'Não ativar agora', Queued_chats: 'Bate-papos na fila', - Queue_is_empty: 'A fila está vazia' + Queue_is_empty: 'A fila está vazia', + Logout_from_other_logged_in_locations: 'Sair de outros locais logados', + You_will_be_logged_out_from_other_locations: 'Você perderá a sessão de outros clientes', + Logged_out_of_other_clients_successfully: 'Desconectado de outros clientes com sucesso', + Logout_failed: 'Falha ao desconectar!' }; diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 33fb6990a..d21398aad 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -419,6 +419,10 @@ const RocketChat = { return user; }, logout, + logoutOtherLocations() { + const { id: userId } = reduxStore.getState().login.user; + return this.sdk.post('users.removeOtherTokens', { userId }); + }, removeServer, async clearCache({ server }) { try { diff --git a/app/utils/log/events.js b/app/utils/log/events.js index c6d51d7e2..9e1dfc9d6 100644 --- a/app/utils/log/events.js +++ b/app/utils/log/events.js @@ -119,6 +119,8 @@ export default { PROFILE_SAVE_AVATAR_F: 'profile_save_avatar_f', PROFILE_SAVE_CHANGES: 'profile_save_changes', PROFILE_SAVE_CHANGES_F: 'profile_save_changes_f', + PROFILE_LOGOUT_OTHER_LOCATIONS: 'profile_logout_other_locations', + PROFILE_LOGOUT_OTHER_LOCATIONS_F: 'profile_logout_other_locations_f', // SETTINGS VIEW SE_CONTACT_US: 'se_contact_us', diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js index 19d718768..7c96c5280 100644 --- a/app/views/ProfileView/index.js +++ b/app/views/ProfileView/index.js @@ -13,7 +13,7 @@ import KeyboardView from '../../presentation/KeyboardView'; import sharedStyles from '../Styles'; import styles from './styles'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; -import { showErrorAlert } from '../../utils/info'; +import { showErrorAlert, showConfirmationAlert } from '../../utils/info'; import { LISTENER } from '../../containers/Toast'; import EventEmitter from '../../utils/events'; import RocketChat from '../../lib/rocketchat'; @@ -426,6 +426,23 @@ class ProfileView extends React.Component { } } + logoutOtherLocations = () => { + logEvent(events.PROFILE_LOGOUT_OTHER_LOCATIONS); + showConfirmationAlert({ + message: I18n.t('You_will_be_logged_out_from_other_locations'), + callToAction: I18n.t('Logout'), + onPress: async() => { + try { + await RocketChat.logoutOtherLocations(); + EventEmitter.emit(LISTENER, { message: I18n.t('Logged_out_of_other_clients_successfully') }); + } catch { + logEvent(events.PROFILE_LOGOUT_OTHER_LOCATIONS_F); + EventEmitter.emit(LISTENER, { message: I18n.t('Logout_failed') }); + } + } + }); + } + render() { const { name, username, email, newPassword, avatarUrl, customFields, avatar, saving @@ -552,6 +569,14 @@ class ProfileView extends React.Component { loading={saving} theme={theme} /> +