From 8dfa17e05e122f68327d709b8b956d90a7273860 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Wed, 6 Nov 2024 17:38:10 -0300 Subject: [PATCH 01/12] fix(Android): unable to login due to encryption keychain failure (#5956) --- app/lib/methods/logout.ts | 6 ++++-- app/sagas/login.js | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/lib/methods/logout.ts b/app/lib/methods/logout.ts index 7bde9e63de..2e4774062d 100644 --- a/app/lib/methods/logout.ts +++ b/app/lib/methods/logout.ts @@ -4,7 +4,7 @@ import Model from '@nozbe/watermelondb/Model'; import * as Keychain from 'react-native-keychain'; import { getDeviceToken } from '../notifications'; -import { extractHostname, isSsl } from './helpers'; +import { extractHostname, isIOS, isSsl } from './helpers'; import { BASIC_AUTH_KEY } from './helpers/fetch'; import database, { getDatabase } from '../database'; import log from './helpers/log'; @@ -25,7 +25,9 @@ async function removeServerKeys({ server, userId }: { server: string; userId?: s UserPreferences.removeItem(`${server}-${E2E_PUBLIC_KEY}`); UserPreferences.removeItem(`${server}-${E2E_PRIVATE_KEY}`); UserPreferences.removeItem(`${server}-${E2E_RANDOM_PASSWORD_KEY}`); - await Keychain.resetInternetCredentials(server); + if (isIOS) { + await Keychain.resetInternetCredentials(server); + } } async function removeSharedCredentials({ server }: { server: string }) { diff --git a/app/sagas/login.js b/app/sagas/login.js index fb2fcabc69..5f7f0c052a 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -46,6 +46,7 @@ import { appGroupSuiteName } from '../lib/methods/appGroup'; import appNavigation from '../lib/navigation/appNavigation'; import { showActionSheetRef } from '../containers/ActionSheet'; import { SupportedVersionsWarning } from '../containers/SupportedVersions'; +import { isIOS } from '../lib/methods/helpers'; const getServer = state => state.server.server; const loginWithPasswordCall = args => Services.loginWithPassword(args); @@ -234,10 +235,12 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) { UserPreferences.setString(`${TOKEN_KEY}-${server}`, user.id); UserPreferences.setString(`${TOKEN_KEY}-${user.id}`, user.token); UserPreferences.setString(CURRENT_SERVER, server); - yield Keychain.setInternetCredentials(server, user.id, user.token, { - accessGroup: appGroupSuiteName, - securityLevel: Keychain.SECURITY_LEVEL.SECURE_SOFTWARE - }); + if (isIOS) { + yield Keychain.setInternetCredentials(server, user.id, user.token, { + accessGroup: appGroupSuiteName, + securityLevel: Keychain.SECURITY_LEVEL.SECURE_SOFTWARE + }); + } yield put(setUser(user)); EventEmitter.emit('connected'); const currentRoot = yield select(state => state.app.root); From 4ce3e9a11ba96b7c88530ae136127d2fe1d90714 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Wed, 6 Nov 2024 17:54:40 -0300 Subject: [PATCH 02/12] fix: undefined emails on rooms stream (#5958) --- app/lib/methods/subscriptions/rooms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/methods/subscriptions/rooms.ts b/app/lib/methods/subscriptions/rooms.ts index 105842eb2f..3d65de530a 100644 --- a/app/lib/methods/subscriptions/rooms.ts +++ b/app/lib/methods/subscriptions/rooms.ts @@ -301,7 +301,7 @@ export default function subscribeRooms() { const [, ev] = ddpMessage.fields.eventName.split('/'); if (/userData/.test(ev)) { const [{ diff, unset }] = ddpMessage.fields.args; - if (diff.emails?.length > 0) { + if (diff?.emails?.length > 0) { store.dispatch(setUser({ emails: diff.emails })); } if (diff?.statusLivechat) { From b8bb9c727e8bee3b63a97b748ec139eda61d687e Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Wed, 6 Nov 2024 18:03:19 -0300 Subject: [PATCH 03/12] fix: add extra check on settings types to guarantee settings are fetched correctly (#5957) --- app/lib/methods/parseSettings.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/lib/methods/parseSettings.ts b/app/lib/methods/parseSettings.ts index 3dcef2aa17..33d652ed9e 100644 --- a/app/lib/methods/parseSettings.ts +++ b/app/lib/methods/parseSettings.ts @@ -15,9 +15,15 @@ export function parseSettings(settings: any) { } export function _prepareSettings(settings: any) { - return settings.map((setting: any) => { - // @ts-ignore - setting[defaultSettings[setting._id].type] = setting.value; - return setting; - }); + return settings + .map((setting: any) => { + // @ts-ignore + if (!defaultSettings[setting._id]) { + return undefined; + } + // @ts-ignore + setting[defaultSettings[setting._id].type] = setting.value; + return setting; + }) + .filter(Boolean); } From b58b2e6564b92b7e8dceab18bde3b801c36a8ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ot=C3=A1vio=20Stasiak?= <91474186+OtavioStasiak@users.noreply.github.com> Date: Thu, 7 Nov 2024 09:00:28 -0300 Subject: [PATCH 04/12] fix: Resolve crash in Directory on tablets (#5959) --- app/stacks/MasterDetailStack/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/stacks/MasterDetailStack/index.tsx b/app/stacks/MasterDetailStack/index.tsx index 48cbe0c345..f3d552240c 100644 --- a/app/stacks/MasterDetailStack/index.tsx +++ b/app/stacks/MasterDetailStack/index.tsx @@ -138,7 +138,6 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => { name='DirectoryView' // @ts-ignore component={DirectoryView} - options={props => DirectoryView.navigationOptions!({ ...props, isMasterDetail: true })} /> From 07a33b656b9f99166fd5adeaadb17ebdadb11958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ot=C3=A1vio=20Stasiak?= <91474186+OtavioStasiak@users.noreply.github.com> Date: Thu, 7 Nov 2024 09:02:05 -0300 Subject: [PATCH 05/12] chore: updated deprecated endpoint livechat/inquiries.queued (#5952) --- app/definitions/rest/v1/omnichannel.ts | 13 +++++++++++++ app/ee/omnichannel/lib/index.ts | 8 +++++++- app/ee/omnichannel/sagas/inquiry.js | 4 +++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/definitions/rest/v1/omnichannel.ts b/app/definitions/rest/v1/omnichannel.ts index 009a121f19..6b8e7c845b 100644 --- a/app/definitions/rest/v1/omnichannel.ts +++ b/app/definitions/rest/v1/omnichannel.ts @@ -109,6 +109,19 @@ export type OmnichannelEndpoints = { ]; }>; }; + + 'livechat/inquiries.queued': { + GET: () => PaginatedResult<{ + inquiries: IOmnichannelRoom[]; + }>; + }; + + 'livechat/inquiries.queuedForUser': { + GET: () => PaginatedResult<{ + inquiries: IOmnichannelRoom[]; + }>; + }; + 'livechat/rooms': { GET: (params: { guest: string; diff --git a/app/ee/omnichannel/lib/index.ts b/app/ee/omnichannel/lib/index.ts index d8a97d1de1..a464f626fa 100644 --- a/app/ee/omnichannel/lib/index.ts +++ b/app/ee/omnichannel/lib/index.ts @@ -1,5 +1,6 @@ import sdk from '../../../lib/services/sdk'; import { IUser } from '../../../definitions'; +import { compareServerVersion } from '../../../lib/methods/helpers'; import EventEmitter from '../../../lib/methods/helpers/events'; import subscribeInquiry from './subscriptions/inquiry'; @@ -10,7 +11,12 @@ export const changeLivechatStatus = () => sdk.methodCallWrapper('livechat:change // RC 2.4.0 // @ts-ignore -export const getInquiriesQueued = () => sdk.get('livechat/inquiries.queued'); +export const getInquiriesQueued = (serverVersion: string) => { + const url = compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '7.0.0') + ? 'livechat/inquiries.queuedForUser' + : 'livechat/inquiries.queued'; + return sdk.get(url); +}; // this inquiry is added to the db by the subscriptions stream // and will be removed by the queue stream diff --git a/app/ee/omnichannel/sagas/inquiry.js b/app/ee/omnichannel/sagas/inquiry.js index e45f0b9b06..ced4eea742 100644 --- a/app/ee/omnichannel/sagas/inquiry.js +++ b/app/ee/omnichannel/sagas/inquiry.js @@ -14,8 +14,10 @@ const handleRequest = function* handleRequest() { const showQueue = routingConfig.showQueue && isOmnichannelStatusAvailable(user); if (showQueue) { + const serverVersion = yield select(state => state.server.version); + // get all the current chats on the queue - const result = yield getInquiriesQueued(); + const result = yield getInquiriesQueued(serverVersion); if (result.success) { const { inquiries } = result; From c796e91b6e32297f30680aac19483255b48fd05b Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Thu, 7 Nov 2024 13:59:01 -0300 Subject: [PATCH 06/12] fix: Settings not being fetched when app is opened from push notification (#5961) --- .../SupportedVersionsExpired.tsx | 2 +- app/reducers/server.ts | 4 +- app/sagas/deepLinking.js | 41 ++++++++++--------- app/sagas/init.js | 16 ++------ app/sagas/selectServer.ts | 10 ++++- app/views/NewServerView/index.tsx | 2 +- app/views/RoomsListView/ServersList.tsx | 2 +- app/views/SelectServerView.tsx | 6 +-- app/views/SettingsView/index.tsx | 2 +- 9 files changed, 42 insertions(+), 43 deletions(-) diff --git a/app/containers/SupportedVersions/SupportedVersionsExpired.tsx b/app/containers/SupportedVersions/SupportedVersionsExpired.tsx index 06f0442c53..6d9ffdc1d2 100644 --- a/app/containers/SupportedVersions/SupportedVersionsExpired.tsx +++ b/app/containers/SupportedVersions/SupportedVersionsExpired.tsx @@ -34,7 +34,7 @@ export const SupportedVersionsExpired = () => { r.supportedVersionsWarningAt = null; }); }); - dispatch(selectServerRequest(server)); + dispatch(selectServerRequest(server, serverRecord.version)); // forces loading state a little longer until redux is finished await new Promise(res => setTimeout(res, checkAgainTimeout)); } diff --git a/app/reducers/server.ts b/app/reducers/server.ts index 2e3cd9652d..0dc0abcccf 100644 --- a/app/reducers/server.ts +++ b/app/reducers/server.ts @@ -6,7 +6,7 @@ export interface IServer { connected: boolean; failure: boolean; server: string; - version: string | null; + version: string; name: string | null; loading: boolean; previousServer: string | null; @@ -18,7 +18,7 @@ export const initialState: IServer = { connected: false, failure: false, server: '', - version: null, + version: '', name: null, loading: true, previousServer: null, diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js index bf72854640..e1b7522511 100644 --- a/app/sagas/deepLinking.js +++ b/app/sagas/deepLinking.js @@ -9,6 +9,7 @@ import { selectServerRequest, serverInitAdd } from '../actions/server'; import { RootEnum } from '../definitions'; import { CURRENT_SERVER, TOKEN_KEY } from '../lib/constants'; import database from '../lib/database'; +import { getServerById } from '../lib/database/services/Server'; import { canOpenRoom, getServerInfo } from '../lib/methods'; import { getUidDirectMessage } from '../lib/methods/helpers'; import EventEmitter from '../lib/methods/helpers/events'; @@ -111,9 +112,6 @@ const handleOpen = function* handleOpen({ params }) { return; } - const serversDB = database.servers; - const serversCollection = serversDB.get('servers'); - let { host } = params; if (params.type === 'oauth') { @@ -148,23 +146,27 @@ const handleOpen = function* handleOpen({ params }) { UserPreferences.getString(`${TOKEN_KEY}-${host}`) ]); + const serverRecord = yield getServerById(host); + if (!serverRecord) { + return; + } + // TODO: needs better test // if deep link is from same server if (server === host && user) { const connected = yield select(state => state.server.connected); if (!connected) { yield localAuthenticate(host); - yield put(selectServerRequest(host)); + yield put(selectServerRequest(host, serverRecord.version, true)); yield take(types.LOGIN.SUCCESS); } yield navigate({ params }); } else { // search if deep link's server already exists try { - const hostServerRecord = yield serversCollection.find(host); - if (hostServerRecord && user) { + if (user) { yield localAuthenticate(host); - yield put(selectServerRequest(host, hostServerRecord.version, true, true)); + yield put(selectServerRequest(host, serverRecord.version, true, true)); yield take(types.LOGIN.SUCCESS); yield navigate({ params }); return; @@ -235,27 +237,26 @@ const handleClickCallPush = function* handleOpen({ params }) { UserPreferences.getString(`${TOKEN_KEY}-${host}`) ]); + const serverRecord = yield getServerById(host); + if (!serverRecord) { + return; + } + if (server === host && user) { const connected = yield select(state => state.server.connected); if (!connected) { yield localAuthenticate(host); - yield put(selectServerRequest(host)); + yield put(selectServerRequest(host, serverRecord.version, true)); yield take(types.LOGIN.SUCCESS); } yield handleNavigateCallRoom({ params }); } else { - // search if deep link's server already exists - try { - const hostServerRecord = yield serversCollection.find(host); - if (hostServerRecord && user) { - yield localAuthenticate(host); - yield put(selectServerRequest(host, hostServerRecord.version, true, true)); - yield take(types.LOGIN.SUCCESS); - yield handleNavigateCallRoom({ params }); - return; - } - } catch (e) { - // do nothing? + if (user) { + yield localAuthenticate(host); + yield put(selectServerRequest(host, serverRecord.version, true, true)); + yield take(types.LOGIN.SUCCESS); + yield handleNavigateCallRoom({ params }); + return; } // if deep link is from a different server const result = yield Services.getServerInfo(host); diff --git a/app/sagas/init.js b/app/sagas/init.js index 8d829aecab..29d5fab0a7 100644 --- a/app/sagas/init.js +++ b/app/sagas/init.js @@ -20,7 +20,6 @@ export const initLocalSettings = function* initLocalSettings() { yield put(setAllPreferences(sortPreferences)); }; - const restore = function* restore() { console.log('RESTORE'); try { @@ -40,23 +39,14 @@ const restore = function* restore() { const newServer = servers[i].id; userId = UserPreferences.getString(`${TOKEN_KEY}-${newServer}`); if (userId) { - return yield put(selectServerRequest(newServer)); + return yield put(selectServerRequest(newServer, newServer.version)); } } } yield put(appStart({ root: RootEnum.ROOT_OUTSIDE })); } else { - const serversDB = database.servers; - const serverCollections = serversDB.get('servers'); - - let serverObj; - try { - yield localAuthenticate(server); - serverObj = yield serverCollections.find(server); - } catch { - // Server not found - } - yield put(selectServerRequest(server, serverObj && serverObj.version)); + yield localAuthenticate(server); + yield put(selectServerRequest(server)); } yield put(appReady({})); diff --git a/app/sagas/selectServer.ts b/app/sagas/selectServer.ts index d2a2461658..0047fa5f67 100644 --- a/app/sagas/selectServer.ts +++ b/app/sagas/selectServer.ts @@ -142,6 +142,14 @@ const getServerInfoSaga = function* getServerInfoSaga({ server, raiseError = tru const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }: ISelectServerAction) { try { + let currentVersion = version; + if (!currentVersion) { + const serverRecord = yield* call(getServerById, server); + if (serverRecord) { + currentVersion = serverRecord.version; + } + } + // SSL Pinning - Read certificate alias and set it to be used by network requests const certificate = UserPreferences.getString(`${CERTIFICATE_KEY}-${server}`); if (certificate) { @@ -211,7 +219,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch } // Return server version even when offline - const serverVersion = (serverInfo && serverInfo.version) || (version as string); + const serverVersion = (serverInfo && serverInfo.version) || (currentVersion as string); // we'll set serverVersion as metadata for bugsnag logServerVersion(serverVersion); diff --git a/app/views/NewServerView/index.tsx b/app/views/NewServerView/index.tsx index b3f74dfd26..73d84c1e17 100644 --- a/app/views/NewServerView/index.tsx +++ b/app/views/NewServerView/index.tsx @@ -330,4 +330,4 @@ const mapStateToProps = (state: IApplicationState) => ({ previousServer: state.server.previousServer }); -export default connect(mapStateToProps)(withTheme(NewServerView)); +export default connect(mapStateToProps)(withTheme(NewServerView)); \ No newline at end of file diff --git a/app/views/RoomsListView/ServersList.tsx b/app/views/RoomsListView/ServersList.tsx index 452c2664ed..0a59d8acce 100644 --- a/app/views/RoomsListView/ServersList.tsx +++ b/app/views/RoomsListView/ServersList.tsx @@ -81,7 +81,7 @@ const ServersList = () => { navToNewServer(server); }; - const select = async (serverParam: string, version?: string) => { + const select = async (serverParam: string, version: string) => { close(); if (server !== serverParam) { logEvent(events.RL_CHANGE_SERVER); diff --git a/app/views/SelectServerView.tsx b/app/views/SelectServerView.tsx index 62f9a90d72..46853b02cb 100644 --- a/app/views/SelectServerView.tsx +++ b/app/views/SelectServerView.tsx @@ -42,9 +42,9 @@ const SelectServerView = () => { init(); }, []); - const select = (serverSelected: string) => { + const select = (serverSelected: string, version: string) => { if (serverSelected !== server) { - dispatch(selectServerRequest(serverSelected)); + dispatch(selectServerRequest(serverSelected, version)); } navigation.pop(); }; @@ -55,7 +55,7 @@ const SelectServerView = () => { ( - select(item.id)} item={item} hasCheck={item.id === server} /> + select(item.id, item.version)} item={item} hasCheck={item.id === server} /> )} keyExtractor={keyExtractor} getItemLayout={getItemLayout} // Refactor row_height diff --git a/app/views/SettingsView/index.tsx b/app/views/SettingsView/index.tsx index 41d9f58d9b..94e25e4c38 100644 --- a/app/views/SettingsView/index.tsx +++ b/app/views/SettingsView/index.tsx @@ -105,7 +105,7 @@ const SettingsView = (): React.ReactElement => { await FastImage.clearMemoryCache(); await FastImage.clearDiskCache(); Services.disconnect(); - dispatch(selectServerRequest(server)); + dispatch(selectServerRequest(server, version, true)); } }); }; From e7008058bf2f4ddb47bac6e6d2af459140edaba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ot=C3=A1vio=20Stasiak?= <91474186+OtavioStasiak@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:33:37 -0300 Subject: [PATCH 07/12] regression: remove video thumbnails (#5963) --- .../message/Components/Attachments/Video.tsx | 119 ++++++------------ 1 file changed, 40 insertions(+), 79 deletions(-) diff --git a/app/containers/message/Components/Attachments/Video.tsx b/app/containers/message/Components/Attachments/Video.tsx index 201c9b617a..23b72e6e46 100644 --- a/app/containers/message/Components/Attachments/Video.tsx +++ b/app/containers/message/Components/Attachments/Video.tsx @@ -1,7 +1,5 @@ -import React, { useContext, useEffect, useState } from 'react'; -import { StyleProp, StyleSheet, TextStyle, View } from 'react-native'; -import FastImage from 'react-native-fast-image'; -import { getThumbnailAsync } from 'expo-video-thumbnails'; +import React, { useContext } from 'react'; +import { StyleProp, StyleSheet, Text, TextStyle, View } from 'react-native'; import { IUserMessage } from '../../../../definitions'; import { IAttachment } from '../../../../definitions/IAttachment'; @@ -10,107 +8,70 @@ import I18n from '../../../../i18n'; import { fileDownload, isIOS } from '../../../../lib/methods/helpers'; import EventEmitter from '../../../../lib/methods/helpers/events'; import { useTheme } from '../../../../theme'; +import sharedStyles from '../../../../views/Styles'; +import { TIconsName } from '../../../CustomIcon'; import { LISTENER } from '../../../Toast'; import Markdown from '../../../markdown'; import MessageContext from '../../Context'; import Touchable from '../../Touchable'; import { useMediaAutoDownload } from '../../hooks/useMediaAutoDownload'; -import messageStyles from '../../styles'; -import OverlayComponent from '../OverlayComponent'; -import { CustomIcon, TIconsName } from '../../../CustomIcon'; -import { themes } from '../../../../lib/constants'; +import BlurComponent from '../OverlayComponent'; import { TDownloadState } from '../../../../lib/methods/handleMediaDownload'; +import messageStyles from '../../styles'; const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])]; const isTypeSupported = (type: string) => SUPPORTED_TYPES.indexOf(type) !== -1; const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center' - }, - overlay: { - flex: 1 - }, - image: { - width: '100%', - height: '100%' - }, - playerIcon: { + cancelContainer: { position: 'absolute', - textShadowRadius: 3, - textShadowOffset: { - width: 0.5, - height: 0.5 - } + top: 8, + right: 8 + }, + text: { + ...sharedStyles.textRegular, + fontSize: 12 } }); -type TThumbnailImage = string | null; +interface IMessageVideo { + file: IAttachment; + showAttachment?: (file: IAttachment) => void; + getCustomEmoji: TGetCustomEmoji; + author?: IUserMessage; + style?: StyleProp[]; + isReply?: boolean; + msg?: string; +} -type ThumbnailProps = { - url: string; - status: TDownloadState; - encrypted?: boolean; +const CancelIndicator = () => { + const { colors } = useTheme(); + return ( + + {I18n.t('Cancel')} + + ); }; -const Thumbnail = ({ url, status, encrypted = false }: ThumbnailProps) => { - const { theme } = useTheme(); - +const Thumbnail = ({ status, encrypted = false }: { status: TDownloadState; encrypted: boolean }) => { + const { colors } = useTheme(); let icon: TIconsName = status === 'downloaded' ? 'play-filled' : 'arrow-down-circle'; if (encrypted && status === 'downloaded') { icon = 'encrypted'; } - const [image, setImage] = useState(null); - - const generateThumbnail = async () => { - try { - if (!url) return; - - const { uri } = await getThumbnailAsync(url, { - time: 1 - }); - setImage(uri); - } catch (e) { - console.warn(e); - } - }; - - useEffect(() => { - generateThumbnail(); - }, [url]); - return ( - - {status === 'loading' || !image || encrypted ? ( - - ) : ( - <> - - - - )} - + <> + + {status === 'loading' ? : null} + ); }; -interface IMessageVideo { - file: IAttachment; - showAttachment?: (file: IAttachment) => void; - getCustomEmoji: TGetCustomEmoji; - author?: IUserMessage; - style?: StyleProp[]; - isReply?: boolean; - msg?: string; -} - const Video = ({ file, showAttachment, @@ -151,7 +112,7 @@ const Video = ({ <> - + ); From c975a7abf5f4c5ce8fa2a882eb85380349824627 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Fri, 8 Nov 2024 11:17:45 -0300 Subject: [PATCH 08/12] fix: enforce server version on server select (#5964) --- .storybook/preview.tsx | 2 +- app/actions/server.ts | 4 ++-- app/reducers/server.test.ts | 2 +- app/sagas/deepLinking.js | 6 +++++- app/sagas/init.js | 7 ++++++- app/sagas/login.js | 4 ++-- app/sagas/selectServer.ts | 10 +--------- app/views/NewServerView/index.tsx | 14 ++++++++++---- 8 files changed, 28 insertions(+), 21 deletions(-) diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 666c6e30f3..e336aab9b3 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -10,7 +10,7 @@ import { mockedStore as store } from '../app/reducers/mockedStore'; import { setUser } from '../app/actions/login'; const baseUrl = 'https://open.rocket.chat'; -store.dispatch(selectServerRequest(baseUrl)); +store.dispatch(selectServerRequest(baseUrl, '7.0.0')); store.dispatch(setUser({ id: 'abc', username: 'rocket.cat', name: 'Rocket Cat' })); const preview: Preview = { diff --git a/app/actions/server.ts b/app/actions/server.ts index 9d5fde27e8..af3f41d04d 100644 --- a/app/actions/server.ts +++ b/app/actions/server.ts @@ -4,7 +4,7 @@ import { SERVER } from './actionsTypes'; export interface ISelectServerAction extends Action { server: string; - version?: string; + version: string; fetchVersion: boolean; changeServer: boolean; } @@ -29,7 +29,7 @@ export type TActionServer = ISelectServerAction & ISelectServerSuccess & IServer export function selectServerRequest( server: string, - version?: string, + version: string, fetchVersion = true, changeServer = false ): ISelectServerAction { diff --git a/app/reducers/server.test.ts b/app/reducers/server.test.ts index 86f5010359..6cc03a2d7d 100644 --- a/app/reducers/server.test.ts +++ b/app/reducers/server.test.ts @@ -33,7 +33,7 @@ describe('test server reducer', () => { it('should return modified store after selectServer', () => { const server = 'https://open.rocket.chat/'; - mockedStore.dispatch(selectServerRequest(server)); + mockedStore.dispatch(selectServerRequest(server, '4.1.0')); const state = mockedStore.getState().server.server; expect(state).toEqual(server); }); diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js index e1b7522511..3453397c56 100644 --- a/app/sagas/deepLinking.js +++ b/app/sagas/deepLinking.js @@ -98,7 +98,11 @@ const handleShareExtension = function* handleOpen({ params }) { yield put(appStart({ root: RootEnum.ROOT_LOADING_SHARE_EXTENSION })); yield localAuthenticate(server); - yield put(selectServerRequest(server)); + const serverRecord = yield getServerById(server); + if (!serverRecord) { + return; + } + yield put(selectServerRequest(server, serverRecord.version)); if (sdk.current?.client?.host !== server) { yield take(types.LOGIN.SUCCESS); } diff --git a/app/sagas/init.js b/app/sagas/init.js index 29d5fab0a7..94ab3eb2df 100644 --- a/app/sagas/init.js +++ b/app/sagas/init.js @@ -14,6 +14,7 @@ import { appReady, appStart } from '../actions/app'; import { RootEnum } from '../definitions'; import { getSortPreferences } from '../lib/methods'; import { deepLinkingClickCallPush } from '../actions/deepLinking'; +import { getServerById } from '../lib/database/services/Server'; export const initLocalSettings = function* initLocalSettings() { const sortPreferences = getSortPreferences(); @@ -46,7 +47,11 @@ const restore = function* restore() { yield put(appStart({ root: RootEnum.ROOT_OUTSIDE })); } else { yield localAuthenticate(server); - yield put(selectServerRequest(server)); + const serverRecord = yield getServerById(server); + if (!serverRecord) { + return; + } + yield put(selectServerRequest(server, serverRecord.version)); } yield put(appReady({})); diff --git a/app/sagas/login.js b/app/sagas/login.js index 5f7f0c052a..61e16f0dbb 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -286,7 +286,7 @@ const handleLogout = function* handleLogout({ forcedByServer, message }) { const newServer = servers[i].id; const token = UserPreferences.getString(`${TOKEN_KEY}-${newServer}`); if (token) { - yield put(selectServerRequest(newServer)); + yield put(selectServerRequest(newServer, newServer.version)); return; } } @@ -353,7 +353,7 @@ const handleDeleteAccount = function* handleDeleteAccount() { const newServer = servers[i].id; const token = UserPreferences.getString(`${TOKEN_KEY}-${newServer}`); if (token) { - yield put(selectServerRequest(newServer)); + yield put(selectServerRequest(newServer, newServer.version)); return; } } diff --git a/app/sagas/selectServer.ts b/app/sagas/selectServer.ts index 0047fa5f67..c0c9d805d2 100644 --- a/app/sagas/selectServer.ts +++ b/app/sagas/selectServer.ts @@ -142,14 +142,6 @@ const getServerInfoSaga = function* getServerInfoSaga({ server, raiseError = tru const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }: ISelectServerAction) { try { - let currentVersion = version; - if (!currentVersion) { - const serverRecord = yield* call(getServerById, server); - if (serverRecord) { - currentVersion = serverRecord.version; - } - } - // SSL Pinning - Read certificate alias and set it to be used by network requests const certificate = UserPreferences.getString(`${CERTIFICATE_KEY}-${server}`); if (certificate) { @@ -219,7 +211,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch } // Return server version even when offline - const serverVersion = (serverInfo && serverInfo.version) || (currentVersion as string); + const serverVersion = serverInfo?.version || version; // we'll set serverVersion as metadata for bugsnag logServerVersion(serverVersion); diff --git a/app/views/NewServerView/index.tsx b/app/views/NewServerView/index.tsx index 73d84c1e17..ef76c795b5 100644 --- a/app/views/NewServerView/index.tsx +++ b/app/views/NewServerView/index.tsx @@ -27,6 +27,7 @@ import SSLPinning from '../../lib/methods/helpers/sslPinning'; import sharedStyles from '../Styles'; import ServerInput from './ServerInput'; import { serializeAsciiUrl } from '../../lib/methods'; +import { getServerById } from '../../lib/database/services/Server'; const styles = StyleSheet.create({ onboardingImage: { @@ -138,12 +139,15 @@ class NewServerView extends React.Component { + close = async () => { const { dispatch, previousServer } = this.props; dispatch(inviteLinksClear()); if (previousServer) { - dispatch(selectServerRequest(previousServer)); + const serverRecord = await getServerById(previousServer); + if (serverRecord) { + dispatch(selectServerRequest(previousServer, serverRecord.version)); + } } }; @@ -299,7 +303,9 @@ class NewServerView extends React.Component - {I18n.t('Add_server')} + + {I18n.t('Add_server')} + ({ previousServer: state.server.previousServer }); -export default connect(mapStateToProps)(withTheme(NewServerView)); \ No newline at end of file +export default connect(mapStateToProps)(withTheme(NewServerView)); From 3a9ade922a49d19fc66a4e290414a35e01869c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ot=C3=A1vio=20Stasiak?= <91474186+OtavioStasiak@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:44:43 -0300 Subject: [PATCH 09/12] chore: updated params of getDirectory (#5960) --- app/lib/services/restApi.ts | 26 +++++++++++++++++++------- app/views/DirectoryView/index.tsx | 5 +++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/app/lib/services/restApi.ts b/app/lib/services/restApi.ts index c78ea16298..b43a8fd6de 100644 --- a/app/lib/services/restApi.ts +++ b/app/lib/services/restApi.ts @@ -823,23 +823,35 @@ export const executeCommandPreview = ( }); export const getDirectory = ({ - query, + text, + type, + workspace, count, offset, sort }: { - query: { [key: string]: string }; + text: string; + type: string; + workspace: string; count: number; offset: number; sort: { [key: string]: number }; -}) => - // RC 1.0 - sdk.get('directory', { - query, +}) => { + const serverVersion = reduxStore.getState().server.version; + const params: any = { count, offset, sort - }); + }; + if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '7.0.0')) { + params.text = text; + params.type = type; + params.workspace = workspace; + } else { + params.query = { text, type, workspace }; + } + return sdk.get('directory', params); +}; export const saveAutoTranslate = ({ rid, diff --git a/app/views/DirectoryView/index.tsx b/app/views/DirectoryView/index.tsx index 33a7071d73..bf1efdad48 100644 --- a/app/views/DirectoryView/index.tsx +++ b/app/views/DirectoryView/index.tsx @@ -108,9 +108,10 @@ class DirectoryView extends React.Component Date: Fri, 8 Nov 2024 13:32:33 -0300 Subject: [PATCH 10/12] fix: Remove light status bar on attachment screen (#5969) --- app/views/AttachmentView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/AttachmentView.tsx b/app/views/AttachmentView.tsx index 5cc37bebea..66a3333bb5 100644 --- a/app/views/AttachmentView.tsx +++ b/app/views/AttachmentView.tsx @@ -183,7 +183,7 @@ const AttachmentView = (): React.ReactElement => { return ( - + {loading ? : null} From 3c29677c25be68f1a195f7bda7d471a811d47295 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Fri, 8 Nov 2024 14:05:26 -0300 Subject: [PATCH 11/12] fix: Handle some promise rejections (#5962) --- app/lib/encryption/room.ts | 6 +- app/lib/methods/loadThreadMessages.ts | 3 +- app/sagas/deepLinking.js | 47 +++++----- app/sagas/login.js | 64 ++++++++++--- app/sagas/videoConf.ts | 94 +++++++++++-------- .../ChangeAvatarView/AvatarSuggestion.tsx | 26 ++--- app/views/DirectoryView/index.tsx | 61 ++++++------ app/views/LivechatEditView.tsx | 91 ++++++++++-------- app/views/RoomActionsView/index.tsx | 42 +++++---- app/views/RoomView/RightButtons.tsx | 54 ++++++----- app/views/RoomView/index.tsx | 6 +- app/views/RoomView/services/getMessages.ts | 14 ++- 12 files changed, 300 insertions(+), 208 deletions(-) diff --git a/app/lib/encryption/room.ts b/app/lib/encryption/room.ts index edd08b25cd..28a4c4470e 100644 --- a/app/lib/encryption/room.ts +++ b/app/lib/encryption/room.ts @@ -203,7 +203,11 @@ export default class EncryptionRoom { // this will be called again and run once in 5 seconds requestRoomKey = debounce( async (e2eKeyId: string) => { - await Services.e2eRequestRoomKey(this.roomId, e2eKeyId); + try { + await Services.e2eRequestRoomKey(this.roomId, e2eKeyId); + } catch { + // do nothing + } }, 5000, true diff --git a/app/lib/methods/loadThreadMessages.ts b/app/lib/methods/loadThreadMessages.ts index 9462fdea61..e6f646c710 100644 --- a/app/lib/methods/loadThreadMessages.ts +++ b/app/lib/methods/loadThreadMessages.ts @@ -18,8 +18,7 @@ async function load({ tmid }: { tmid: string }) { return []; } return EJSON.fromJSONValue(result); - } catch (error) { - console.log(error); + } catch { return []; } } diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js index 3453397c56..655306687f 100644 --- a/app/sagas/deepLinking.js +++ b/app/sagas/deepLinking.js @@ -202,34 +202,35 @@ const handleOpen = function* handleOpen({ params }) { }; const handleNavigateCallRoom = function* handleNavigateCallRoom({ params }) { - yield put(appStart({ root: RootEnum.ROOT_INSIDE })); - const db = database.active; - const subsCollection = db.get('subscriptions'); - const room = yield subsCollection.find(params.rid); - if (room) { - const isMasterDetail = yield select(state => state.app.isMasterDetail); - yield navigateToRoom({ item: room, isMasterDetail, popToRoot: true }); - const uid = params.caller._id; - const { rid, callId, event } = params; - if (event === 'accept') { - yield call(Services.notifyUser, `${uid}/video-conference`, { - action: 'accepted', - params: { uid, rid, callId } - }); - yield videoConfJoin(callId, true, false, true); - } else if (event === 'decline') { - yield call(Services.notifyUser, `${uid}/video-conference`, { - action: 'rejected', - params: { uid, rid, callId } - }); + try { + yield put(appStart({ root: RootEnum.ROOT_INSIDE })); + const db = database.active; + const subsCollection = db.get('subscriptions'); + const room = yield subsCollection.find(params.rid); + if (room) { + const isMasterDetail = yield select(state => state.app.isMasterDetail); + yield navigateToRoom({ item: room, isMasterDetail, popToRoot: true }); + const uid = params.caller._id; + const { rid, callId, event } = params; + if (event === 'accept') { + yield call(Services.notifyUser, `${uid}/video-conference`, { + action: 'accepted', + params: { uid, rid, callId } + }); + yield videoConfJoin(callId, true, false, true); + } else if (event === 'decline') { + yield call(Services.notifyUser, `${uid}/video-conference`, { + action: 'rejected', + params: { uid, rid, callId } + }); + } } + } catch (e) { + log(e); } }; const handleClickCallPush = function* handleOpen({ params }) { - const serversDB = database.servers; - const serversCollection = serversDB.get('servers'); - let { host } = params; if (host.slice(-1) === '/') { diff --git a/app/sagas/login.js b/app/sagas/login.js index 61e16f0dbb..80fa6b92a8 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -138,46 +138,82 @@ const handleLoginRequest = function* handleLoginRequest({ }; const subscribeSettingsFork = function* subscribeSettingsFork() { - yield subscribeSettings(); + try { + yield subscribeSettings(); + } catch (e) { + log(e); + } }; const fetchPermissionsFork = function* fetchPermissionsFork() { - yield getPermissions(); + try { + yield getPermissions(); + } catch (e) { + log(e); + } }; const fetchCustomEmojisFork = function* fetchCustomEmojisFork() { - yield getCustomEmojis(); + try { + yield getCustomEmojis(); + } catch (e) { + log(e); + } }; const fetchRolesFork = function* fetchRolesFork() { - sdk.subscribe('stream-roles', 'roles'); - yield getRoles(); + try { + sdk.subscribe('stream-roles', 'roles'); + yield getRoles(); + } catch (e) { + log(e); + } }; const fetchSlashCommandsFork = function* fetchSlashCommandsFork() { - yield getSlashCommands(); + try { + yield getSlashCommands(); + } catch (e) { + log(e); + } }; const registerPushTokenFork = function* registerPushTokenFork() { - yield Services.registerPushToken(); + try { + yield Services.registerPushToken(); + } catch (e) { + log(e); + } }; const fetchUsersPresenceFork = function* fetchUsersPresenceFork() { - subscribeUsersPresence(); + try { + yield subscribeUsersPresence(); + } catch (e) { + log(e); + } }; const fetchEnterpriseModulesFork = function* fetchEnterpriseModulesFork({ user }) { - yield getEnterpriseModules(); + try { + yield getEnterpriseModules(); - if (isOmnichannelStatusAvailable(user) && isOmnichannelModuleAvailable()) { - yield put(inquiryRequest()); + if (isOmnichannelStatusAvailable(user) && isOmnichannelModuleAvailable()) { + yield put(inquiryRequest()); + } + } catch (e) { + log(e); } }; const fetchUsersRoles = function* fetchRoomsFork() { - const roles = yield Services.getUsersRoles(); - if (roles.length) { - yield put(setUsersRoles(roles)); + try { + const roles = yield Services.getUsersRoles(); + if (roles.length) { + yield put(setUsersRoles(roles)); + } + } catch (e) { + log(e); } }; diff --git a/app/sagas/videoConf.ts b/app/sagas/videoConf.ts index f2b728b151..ea8628304c 100644 --- a/app/sagas/videoConf.ts +++ b/app/sagas/videoConf.ts @@ -76,12 +76,16 @@ function* onDirectCallCanceled(payload: ICallInfo) { } function* onDirectCallAccepted({ callId, rid, uid, action }: ICallInfo) { - const calls = yield* appSelector(state => state.videoConf.calls); - const userId = yield* appSelector(state => state.login.user.id); - const currentCall = calls.find(c => c.callId === callId); - if (currentCall && currentCall.action === 'calling') { - yield call(notifyUser, `${uid}/video-conference`, { action: 'confirmed', params: { uid: userId, rid, callId } }); - yield put(setVideoConfCall({ callId, rid, uid, action })); + try { + const calls = yield* appSelector(state => state.videoConf.calls); + const userId = yield* appSelector(state => state.login.user.id); + const currentCall = calls.find(c => c.callId === callId); + if (currentCall && currentCall.action === 'calling') { + yield call(notifyUser, `${uid}/video-conference`, { action: 'confirmed', params: { uid: userId, rid, callId } }); + yield put(setVideoConfCall({ callId, rid, uid, action })); + } + } catch { + // do nothing } } @@ -196,51 +200,63 @@ function* giveUp({ rid, uid, callId, rejected }: { rid: string; uid: string; cal } function* cancelCall({ payload }: { payload?: { callId?: string } }) { - const calls = yield* appSelector(state => state.videoConf.calls); - if (payload?.callId) { - const currentCall = calls.find(c => c.callId === payload.callId); - if (currentCall) { - yield call(giveUp, { ...currentCall, rejected: true }); - } - } else { - const currentCall = calls.find(c => c.action === 'calling'); - if (currentCall && currentCall.callId) { - yield call(giveUp, currentCall); + try { + const calls = yield* appSelector(state => state.videoConf.calls); + if (payload?.callId) { + const currentCall = calls.find(c => c.callId === payload.callId); + if (currentCall) { + yield call(giveUp, { ...currentCall, rejected: true }); + } + } else { + const currentCall = calls.find(c => c.action === 'calling'); + if (currentCall && currentCall.callId) { + yield call(giveUp, currentCall); + } } + } catch { + // do nothing } } function* callUser({ rid, uid, callId }: { rid: string; uid: string; callId: string }) { - const userId = yield* appSelector(state => state.login.user.id); - yield put(setVideoConfCall({ rid, uid, callId, action: 'calling' })); - for (let attempt = 1; attempt <= CALL_ATTEMPT_LIMIT; attempt++) { - if (attempt < CALL_ATTEMPT_LIMIT) { - const calls = yield* appSelector(state => state.videoConf.calls); - const currentCall = calls.find(c => c.callId === callId); - if (!currentCall || currentCall.action !== 'calling') { + try { + const userId = yield* appSelector(state => state.login.user.id); + yield put(setVideoConfCall({ rid, uid, callId, action: 'calling' })); + for (let attempt = 1; attempt <= CALL_ATTEMPT_LIMIT; attempt++) { + if (attempt < CALL_ATTEMPT_LIMIT) { + const calls = yield* appSelector(state => state.videoConf.calls); + const currentCall = calls.find(c => c.callId === callId); + if (!currentCall || currentCall.action !== 'calling') { + break; + } + yield call(notifyUser, `${uid}/video-conference`, { action: 'call', params: { uid: userId, rid, callId } }); + yield delay(CALL_INTERVAL); + } else { + hideActionSheetRef(); + yield call(giveUp, { uid, rid, callId }); break; } - yield call(notifyUser, `${uid}/video-conference`, { action: 'call', params: { uid: userId, rid, callId } }); - yield delay(CALL_INTERVAL); - } else { - hideActionSheetRef(); - yield call(giveUp, { uid, rid, callId }); - break; } + } catch { + // do nothing } } function* acceptCall({ payload: { callId } }: { payload: { callId: string } }) { - const calls = yield* appSelector(state => state.videoConf.calls); - const currentCall = calls.find(c => c.callId === callId); - if (currentCall && currentCall.action === 'call') { - const userId = yield* appSelector(state => state.login.user.id); - yield call(notifyUser, `${currentCall.uid}/video-conference`, { - action: 'accepted', - params: { uid: userId, rid: currentCall.rid, callId: currentCall.callId } - }); - yield put(setVideoConfCall({ ...currentCall, action: 'accepted' })); - hideNotification(); + try { + const calls = yield* appSelector(state => state.videoConf.calls); + const currentCall = calls.find(c => c.callId === callId); + if (currentCall && currentCall.action === 'call') { + const userId = yield* appSelector(state => state.login.user.id); + yield call(notifyUser, `${currentCall.uid}/video-conference`, { + action: 'accepted', + params: { uid: userId, rid: currentCall.rid, callId: currentCall.callId } + }); + yield put(setVideoConfCall({ ...currentCall, action: 'accepted' })); + hideNotification(); + } + } catch { + // do nothing } } diff --git a/app/views/ChangeAvatarView/AvatarSuggestion.tsx b/app/views/ChangeAvatarView/AvatarSuggestion.tsx index 3c3545a494..a6187e068b 100644 --- a/app/views/ChangeAvatarView/AvatarSuggestion.tsx +++ b/app/views/ChangeAvatarView/AvatarSuggestion.tsx @@ -23,17 +23,21 @@ const AvatarSuggestion = ({ useEffect(() => { const getAvatarSuggestion = async () => { - const result = await Services.getAvatarSuggestion(); - const suggestions = Object.keys(result).map(service => { - const { url, blob, contentType } = result[service]; - return { - url, - data: blob, - service, - contentType - }; - }); - setAvatarSuggestions(suggestions); + try { + const result = await Services.getAvatarSuggestion(); + const suggestions = Object.keys(result).map(service => { + const { url, blob, contentType } = result[service]; + return { + url, + data: blob, + service, + contentType + }; + }); + setAvatarSuggestions(suggestions); + } catch { + // do nothing + } }; getAvatarSuggestion(); }, []); diff --git a/app/views/DirectoryView/index.tsx b/app/views/DirectoryView/index.tsx index bf1efdad48..d5d91e523c 100644 --- a/app/views/DirectoryView/index.tsx +++ b/app/views/DirectoryView/index.tsx @@ -30,8 +30,8 @@ import { getSubscriptionByRoomId } from '../../lib/database/services/Subscriptio interface IDirectoryViewProps { navigation: CompositeNavigationProp< - NativeStackNavigationProp, - NativeStackNavigationProp + NativeStackNavigationProp, + NativeStackNavigationProp >; baseUrl: string; isFederationEnabled: boolean; @@ -177,40 +177,45 @@ class DirectoryView extends React.Component { - const { type } = this.state; - if (type === 'users') { - const result = await Services.createDirectMessage(item.username as string); - if (result.success) { - this.goRoom({ rid: result.room._id, name: item.username, t: SubscriptionType.DIRECT }); + try { + const { type } = this.state; + if (type === 'users') { + const result = await Services.createDirectMessage(item.username as string); + if (result.success) { + this.goRoom({ rid: result.room._id, name: item.username, t: SubscriptionType.DIRECT }); + } + return; } - return; - } - const subscription = await getSubscriptionByRoomId(item._id); - if (subscription) { - this.goRoom(subscription); - return; - } - if (['p', 'c'].includes(item.t) && !item.teamMain) { - const result = await Services.getRoomByTypeAndName(item.t, item.name || item.fname); - if (result) { + const subscription = await getSubscriptionByRoomId(item._id); + if (subscription) { + this.goRoom(subscription); + return; + } + if (['p', 'c'].includes(item.t) && !item.teamMain) { + const result = await Services.getRoomByTypeAndName(item.t, item.name || item.fname); + if (result) { + this.goRoom({ + rid: item._id, + name: item.name, + joinCodeRequired: result.joinCodeRequired, + t: item.t as SubscriptionType, + search: true + }); + } + } else { this.goRoom({ rid: item._id, name: item.name, - joinCodeRequired: result.joinCodeRequired, t: item.t as SubscriptionType, - search: true + search: true, + teamMain: item.teamMain, + teamId: item.teamId }); } - } else { - this.goRoom({ - rid: item._id, - name: item.name, - t: item.t as SubscriptionType, - search: true, - teamMain: item.teamMain, - teamId: item.teamId - }); + } catch { + // do nothing } + }; renderHeader = () => ( diff --git a/app/views/LivechatEditView.tsx b/app/views/LivechatEditView.tsx index 89d0de8034..3428aa45c6 100644 --- a/app/views/LivechatEditView.tsx +++ b/app/views/LivechatEditView.tsx @@ -5,6 +5,7 @@ import { ScrollView, StyleSheet, Text } from 'react-native'; import { connect } from 'react-redux'; import { BlockContext } from '@rocket.chat/ui-kit'; +import log from '../lib/methods/helpers/log'; import { TSupportedThemes, withTheme } from '../theme'; import { themes } from '../lib/constants'; import { FormTextInput } from '../containers/TextInput'; @@ -111,61 +112,69 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP }; const handleGetAgentDepartments = async () => { - const result = await Services.getAgentDepartments(visitor?._id); - if (result.success) { - const agentDepartments = result.departments.map(dept => dept.departmentId); - handleGetTagsList(agentDepartments); + try { + const result = await Services.getAgentDepartments(visitor?._id); + if (result.success) { + const agentDepartments = result.departments.map(dept => dept.departmentId); + handleGetTagsList(agentDepartments); + } + } catch { + // do nothing } }; const submit = async () => { - const userData = { _id: visitor?._id } as TParams; + try { + const userData = { _id: visitor?._id } as TParams; - const { rid } = livechat; - const sms = livechat?.sms; + const { rid } = livechat; + const sms = livechat?.sms; - const roomData = { _id: rid } as TParams; + const roomData = { _id: rid } as TParams; - if (params.name) { - userData.name = params.name; - } - if (params.email) { - userData.email = params.email; - } - if (params.phone) { - userData.phone = params.phone; - } + if (params.name) { + userData.name = params.name; + } + if (params.email) { + userData.email = params.email; + } + if (params.phone) { + userData.phone = params.phone; + } - userData.livechatData = {}; - Object.entries(customFields?.visitor || {}).forEach(([key]) => { - if (params[key] || params[key] === '') { - userData.livechatData[key] = params[key]; + userData.livechatData = {}; + Object.entries(customFields?.visitor || {}).forEach(([key]) => { + if (params[key] || params[key] === '') { + userData.livechatData[key] = params[key]; + } + }); + + if (params.topic) { + roomData.topic = params.topic; } - }); - if (params.topic) { - roomData.topic = params.topic; - } + roomData.tags = tagParamSelected; - roomData.tags = tagParamSelected; + roomData.livechatData = {}; + Object.entries(customFields?.livechat || {}).forEach(([key]) => { + if (params[key] || params[key] === '') { + roomData.livechatData[key] = params[key]; + } + }); - roomData.livechatData = {}; - Object.entries(customFields?.livechat || {}).forEach(([key]) => { - if (params[key] || params[key] === '') { - roomData.livechatData[key] = params[key]; + if (sms) { + delete userData.phone; } - }); - if (sms) { - delete userData.phone; - } - - const { error } = await Services.editLivechat(userData, roomData); - if (error) { - EventEmitter.emit(LISTENER, { message: error }); - } else { - EventEmitter.emit(LISTENER, { message: I18n.t('Saved') }); - navigation.goBack(); + const { error } = await Services.editLivechat(userData, roomData); + if (error) { + EventEmitter.emit(LISTENER, { message: error }); + } else { + EventEmitter.emit(LISTENER, { message: I18n.t('Saved') }); + navigation.goBack(); + } + } catch (e) { + log(e); } }; diff --git a/app/views/RoomActionsView/index.tsx b/app/views/RoomActionsView/index.tsx index 1f4fc76d0c..7f3ed3c8e8 100644 --- a/app/views/RoomActionsView/index.tsx +++ b/app/views/RoomActionsView/index.tsx @@ -375,30 +375,34 @@ class RoomActionsView extends React.Component { - const { - room: { rid, departmentId } - } = this.state; - const { livechatRequestComment, isMasterDetail, navigation } = this.props; - let departmentInfo: ILivechatDepartment | undefined; - let tagsList: ILivechatTag[] | undefined; + try { + const { + room: { rid, departmentId } + } = this.state; + const { livechatRequestComment, isMasterDetail, navigation } = this.props; + let departmentInfo: ILivechatDepartment | undefined; + let tagsList: ILivechatTag[] | undefined; + + if (departmentId) { + const result = await Services.getDepartmentInfo(departmentId); + if (result.success) { + departmentInfo = result.department as ILivechatDepartment; + } + } - if (departmentId) { - const result = await Services.getDepartmentInfo(departmentId); - if (result.success) { - departmentInfo = result.department as ILivechatDepartment; + if (departmentInfo?.requestTagBeforeClosingChat) { + tagsList = await Services.getTagsList(); } - } - if (departmentInfo?.requestTagBeforeClosingChat) { - tagsList = await Services.getTagsList(); - } + if (!livechatRequestComment && !departmentInfo?.requestTagBeforeClosingChat) { + const comment = I18n.t('Chat_closed_by_agent'); + return closeLivechat({ rid, isMasterDetail, comment }); + } - if (!livechatRequestComment && !departmentInfo?.requestTagBeforeClosingChat) { - const comment = I18n.t('Chat_closed_by_agent'); - return closeLivechat({ rid, isMasterDetail, comment }); + navigation.navigate('CloseLivechatView', { rid, departmentId, departmentInfo, tagsList }); + } catch (e) { + log(e); } - - navigation.navigate('CloseLivechatView', { rid, departmentId, departmentInfo, tagsList }); }; placeOnHoldLivechat = () => { diff --git a/app/views/RoomView/RightButtons.tsx b/app/views/RoomView/RightButtons.tsx index 8d4fb067bd..dae2f343de 100644 --- a/app/views/RoomView/RightButtons.tsx +++ b/app/views/RoomView/RightButtons.tsx @@ -253,36 +253,40 @@ class RightButtonsContainer extends Component { - const { rid, departmentId } = this.props; - const { livechatRequestComment, isMasterDetail, navigation } = this.props; - let departmentInfo: ILivechatDepartment | undefined; - let tagsList: ILivechatTag[] | undefined; - - if (departmentId) { - const result = await Services.getDepartmentInfo(departmentId); - if (result.success) { - departmentInfo = result.department as ILivechatDepartment; + try { + const { rid, departmentId } = this.props; + const { livechatRequestComment, isMasterDetail, navigation } = this.props; + let departmentInfo: ILivechatDepartment | undefined; + let tagsList: ILivechatTag[] | undefined; + + if (departmentId) { + const result = await Services.getDepartmentInfo(departmentId); + if (result.success) { + departmentInfo = result.department as ILivechatDepartment; + } } - } - - if (departmentInfo?.requestTagBeforeClosingChat) { - tagsList = await Services.getTagsList(); - } - if (rid) { - if (!livechatRequestComment && !departmentInfo?.requestTagBeforeClosingChat) { - const comment = i18n.t('Chat_closed_by_agent'); - return closeLivechatService({ rid, isMasterDetail, comment }); + if (departmentInfo?.requestTagBeforeClosingChat) { + tagsList = await Services.getTagsList(); } - if (isMasterDetail) { - navigation.navigate('ModalStackNavigator', { - screen: 'CloseLivechatView', - params: { rid, departmentId, departmentInfo, tagsList } - }); - } else { - navigation.navigate('CloseLivechatView', { rid, departmentId, departmentInfo, tagsList }); + if (rid) { + if (!livechatRequestComment && !departmentInfo?.requestTagBeforeClosingChat) { + const comment = i18n.t('Chat_closed_by_agent'); + return closeLivechatService({ rid, isMasterDetail, comment }); + } + + if (isMasterDetail) { + navigation.navigate('ModalStackNavigator', { + screen: 'CloseLivechatView', + params: { rid, departmentId, departmentInfo, tagsList } + }); + } else { + navigation.navigate('CloseLivechatView', { rid, departmentId, departmentInfo, tagsList }); + } } + } catch { + // do nothing } }; diff --git a/app/views/RoomView/index.tsx b/app/views/RoomView/index.tsx index c13aafb776..df4d70b24a 100644 --- a/app/views/RoomView/index.tsx +++ b/app/views/RoomView/index.tsx @@ -217,7 +217,11 @@ class RoomView extends React.Component { const { isAuthenticated } = this.props; this.setHeader(); if (this.rid) { - this.sub?.subscribe?.(); + try { + this.sub?.subscribe?.(); + } catch (e) { + log(e); + } if (isAuthenticated) { this.init(); } else { diff --git a/app/views/RoomView/services/getMessages.ts b/app/views/RoomView/services/getMessages.ts index b05fadeff7..85e6cd97f7 100644 --- a/app/views/RoomView/services/getMessages.ts +++ b/app/views/RoomView/services/getMessages.ts @@ -12,11 +12,17 @@ interface ILoadMissedMessagesParams extends IBaseParams { lastOpen: Date; } -const getMessages = (params: ILoadMissedMessagesParams | ILoadMessagesForRoomParams): Promise => { - if ('lastOpen' in params) { - return loadMissedMessages(params); +const getMessages = async (params: ILoadMissedMessagesParams | ILoadMessagesForRoomParams): Promise => { + try { + if ('lastOpen' in params) { + await loadMissedMessages(params); + } else { + await loadMessagesForRoom(params); + } + } catch (e) { + // Offline first } - return loadMessagesForRoom(params); + return Promise.resolve(); }; export default getMessages; From bab3de5a3ac8e8d45ea1fa0efb71d3f79d2e6aa7 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Fri, 8 Nov 2024 14:30:01 -0300 Subject: [PATCH 12/12] Bump version to 4.54.1 --- android/app/build.gradle | 2 +- ios/RocketChatRN.xcodeproj/project.pbxproj | 4 ++-- ios/RocketChatRN/Info.plist | 2 +- ios/ShareRocketChatRN/Info.plist | 2 +- package.json | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 11cbd8bd9d..8405a32123 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -93,7 +93,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode VERSIONCODE as Integer - versionName "4.54.0" + versionName "4.54.1" vectorDrawables.useSupportLibrary = true if (!isFoss) { manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String] diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 6c44bf39d2..14345bb58e 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -2975,7 +2975,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 4.54.0; + MARKETING_VERSION = 4.54.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; @@ -3019,7 +3019,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 4.54.0; + MARKETING_VERSION = 4.54.1; MTL_FAST_MATH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index b3498b4c54..0bba31e96e 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -28,7 +28,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 4.54.0 + 4.54.1 CFBundleSignature ???? CFBundleURLTypes diff --git a/ios/ShareRocketChatRN/Info.plist b/ios/ShareRocketChatRN/Info.plist index 22ea62b83d..dcc754a796 100644 --- a/ios/ShareRocketChatRN/Info.plist +++ b/ios/ShareRocketChatRN/Info.plist @@ -26,7 +26,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 4.54.0 + 4.54.1 CFBundleVersion 1 KeychainGroup diff --git a/package.json b/package.json index f890700fe7..70dbc49fb1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket-chat-reactnative", - "version": "4.54.0", + "version": "4.54.1", "private": true, "scripts": { "start": "react-native start",