diff --git a/app/containers/InAppNotification/NotifierComponent.tsx b/app/containers/InAppNotification/NotifierComponent.tsx
index b46c1b51a..8b32ae1c6 100644
--- a/app/containers/InAppNotification/NotifierComponent.tsx
+++ b/app/containers/InAppNotification/NotifierComponent.tsx
@@ -12,7 +12,6 @@ import { themes } from '../../lib/constants';
import { useTheme } from '../../theme';
import { ROW_HEIGHT } from '../RoomItem';
import { goRoom } from '../../lib/methods/helpers/goRoom';
-import Navigation from '../../lib/navigation/appNavigation';
import { useOrientation } from '../../dimensions';
import { IApplicationState, ISubscription, SubscriptionType } from '../../definitions';
@@ -98,12 +97,7 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }: INotifie
prid
};
- if (isMasterDetail) {
- Navigation.navigate('DrawerNavigator');
- } else {
- Navigation.navigate('RoomsListView');
- }
- goRoom({ item, isMasterDetail, jumpToMessageId: _id });
+ goRoom({ item, isMasterDetail, jumpToMessageId: _id, popToRoot: true });
hideNotification();
};
@@ -124,6 +118,7 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }: INotifie
onPress={onPress}
hitSlop={BUTTON_HIT_SLOP}
background={Touchable.SelectableBackgroundBorderless()}
+ testID={`in-app-notification-${text}`}
>
<>
diff --git a/app/containers/InAppNotification/index.tsx b/app/containers/InAppNotification/index.tsx
index 34354e632..d6581f27f 100644
--- a/app/containers/InAppNotification/index.tsx
+++ b/app/containers/InAppNotification/index.tsx
@@ -1,56 +1,50 @@
import React, { memo, useEffect } from 'react';
import { Easing, Notifier, NotifierRoot } from 'react-native-notifier';
-import { connect } from 'react-redux';
-import { dequal } from 'dequal';
import NotifierComponent, { INotifierComponent } from './NotifierComponent';
import EventEmitter from '../../lib/methods/helpers/events';
import Navigation from '../../lib/navigation/appNavigation';
import { getActiveRoute } from '../../lib/methods/helpers/navigation';
-import { IApplicationState } from '../../definitions';
-import { IRoom } from '../../reducers/room';
+import { useAppSelector } from '../../lib/hooks';
export const INAPP_NOTIFICATION_EMITTER = 'NotificationInApp';
-const InAppNotification = memo(
- ({ rooms, appState }: { rooms: IRoom['rooms']; appState: string }) => {
- const show = (notification: INotifierComponent['notification']) => {
- if (appState !== 'foreground') {
+const InAppNotification = memo(() => {
+ const { appState, subscribedRoom } = useAppSelector(state => ({
+ subscribedRoom: state.room.subscribedRoom,
+ appState: state.app.ready && state.app.foreground ? 'foreground' : 'background'
+ }));
+
+ const show = (notification: INotifierComponent['notification']) => {
+ if (appState !== 'foreground') {
+ return;
+ }
+
+ const { payload } = notification;
+ const state = Navigation.navigationRef.current?.getRootState();
+ const route = getActiveRoute(state);
+ if (payload.rid) {
+ if (payload.rid === subscribedRoom || route?.name === 'JitsiMeetView') {
return;
}
-
- const { payload } = notification;
- const state = Navigation.navigationRef.current?.getRootState();
- const route = getActiveRoute(state);
- if (payload.rid) {
- if (rooms.includes(payload.rid) || route?.name === 'JitsiMeetView') {
- return;
+ Notifier.showNotification({
+ showEasing: Easing.inOut(Easing.quad),
+ Component: NotifierComponent,
+ componentProps: {
+ notification
}
- Notifier.showNotification({
- showEasing: Easing.inOut(Easing.quad),
- Component: NotifierComponent,
- componentProps: {
- notification
- }
- });
- }
+ });
+ }
+ };
+
+ useEffect(() => {
+ const listener = EventEmitter.addEventListener(INAPP_NOTIFICATION_EMITTER, show);
+ return () => {
+ EventEmitter.removeListener(INAPP_NOTIFICATION_EMITTER, listener);
};
+ }, [subscribedRoom, appState]);
- useEffect(() => {
- const listener = EventEmitter.addEventListener(INAPP_NOTIFICATION_EMITTER, show);
- return () => {
- EventEmitter.removeListener(INAPP_NOTIFICATION_EMITTER, listener);
- };
- }, [rooms]);
-
- return ;
- },
- (prevProps, nextProps) => dequal(prevProps.rooms, nextProps.rooms)
-);
-
-const mapStateToProps = (state: IApplicationState) => ({
- rooms: state.room.rooms,
- appState: state.app.ready && state.app.foreground ? 'foreground' : 'background'
+ return ;
});
-export default connect(mapStateToProps)(InAppNotification);
+export default InAppNotification;
diff --git a/app/containers/MessageBox/index.tsx b/app/containers/MessageBox/index.tsx
index 306c95825..a7e6823db 100644
--- a/app/containers/MessageBox/index.tsx
+++ b/app/containers/MessageBox/index.tsx
@@ -237,7 +237,7 @@ class MessageBox extends Component {
async componentDidMount() {
const db = database.active;
- const { rid, tmid, navigation, sharing, usedCannedResponse, isMasterDetail } = this.props;
+ const { rid, tmid, navigation, sharing, usedCannedResponse } = this.props;
let msg;
try {
const threadsCollection = db.get('threads');
@@ -272,7 +272,7 @@ class MessageBox extends Component {
EventEmiter.addEventListener(KEY_COMMAND, this.handleCommands);
}
- if (isMasterDetail && usedCannedResponse) {
+ if (usedCannedResponse) {
this.onChangeText(usedCannedResponse);
}
diff --git a/app/containers/markdown/Hashtag.tsx b/app/containers/markdown/Hashtag.tsx
index fd90c74b4..5cd50030b 100644
--- a/app/containers/markdown/Hashtag.tsx
+++ b/app/containers/markdown/Hashtag.tsx
@@ -1,14 +1,11 @@
import React from 'react';
import { StyleProp, Text, TextStyle } from 'react-native';
-import { useNavigation } from '@react-navigation/native';
-import { StackNavigationProp } from '@react-navigation/stack';
import { themes } from '../../lib/constants';
import { useTheme } from '../../theme';
import { IUserChannel } from './interfaces';
import styles from './styles';
import { getSubscriptionByRoomId } from '../../lib/database/services/Subscription';
-import { ChatsStackParamList } from '../../stacks/types';
import { useAppSelector } from '../../lib/hooks';
import { goRoom } from '../../lib/methods/helpers/goRoom';
@@ -22,7 +19,6 @@ interface IHashtag {
const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [] }: IHashtag) => {
const { theme } = useTheme();
const isMasterDetail = useAppSelector(state => state.app.isMasterDetail);
- const navigation = useNavigation>();
const handlePress = async () => {
const index = channels?.findIndex(channel => channel.name === hashtag);
@@ -33,7 +29,7 @@ const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [] }: IH
};
const room = navParam.rid && (await getSubscriptionByRoomId(navParam.rid));
if (room) {
- goRoom({ item: room, isMasterDetail, navigationMethod: isMasterDetail ? navigation.replace : navigation.push });
+ goRoom({ item: room, isMasterDetail });
} else {
navToRoomInfo(navParam);
}
diff --git a/app/ee/omnichannel/views/QueueListView.tsx b/app/ee/omnichannel/views/QueueListView.tsx
index 20025ff15..8ebb3cb39 100644
--- a/app/ee/omnichannel/views/QueueListView.tsx
+++ b/app/ee/omnichannel/views/QueueListView.tsx
@@ -73,19 +73,14 @@ const QueueListView = React.memo(() => {
const onPressItem = (item = {} as IOmnichannelRoom) => {
logEvent(events.QL_GO_ROOM);
- if (isMasterDetail) {
- navigation.navigate('DrawerNavigator');
- } else {
- navigation.navigate('RoomsListView');
- }
-
goRoom({
item: {
...item,
// we're calling v as visitor on our mergeSubscriptionsRooms
visitor: item.v
},
- isMasterDetail
+ isMasterDetail,
+ popToRoot: true
});
};
diff --git a/app/lib/methods/helpers/goRoom.ts b/app/lib/methods/helpers/goRoom.ts
index a57d2e19f..0e0be7ce6 100644
--- a/app/lib/methods/helpers/goRoom.ts
+++ b/app/lib/methods/helpers/goRoom.ts
@@ -1,4 +1,5 @@
-import { ChatsStackParamList } from '../../../stacks/types';
+import { CommonActions } from '@react-navigation/native';
+
import Navigation from '../../navigation/appNavigation';
import { IOmnichannelRoom, SubscriptionType, IVisitor, TSubscriptionModel, ISubscription } from '../../../definitions';
import { getRoomTitle, getUidDirectMessage } from './helpers';
@@ -19,19 +20,14 @@ export type TGoRoomItem = IGoRoomItem | TSubscriptionModel | ISubscription | IOm
const navigate = ({
item,
isMasterDetail,
+ popToRoot,
...props
}: {
item: TGoRoomItem;
isMasterDetail: boolean;
- navigationMethod?: () => ChatsStackParamList;
+ popToRoot: boolean;
}) => {
- let navigationMethod = props.navigationMethod ?? Navigation.navigate;
-
- if (isMasterDetail) {
- navigationMethod = Navigation.replace;
- }
-
- navigationMethod('RoomView', {
+ const routeParams = {
rid: item.rid,
name: getRoomTitle(item),
t: item.t,
@@ -40,6 +36,44 @@ const navigate = ({
visitor: item.visitor,
roomUserId: getUidDirectMessage(item),
...props
+ };
+
+ if (isMasterDetail) {
+ if (popToRoot) {
+ Navigation.navigate('DrawerNavigator');
+ }
+ return Navigation.dispatch((state: any) => {
+ const routesRoomView = state.routes.filter((r: any) => r.name !== 'RoomView');
+ return CommonActions.reset({
+ ...state,
+ routes: [
+ ...routesRoomView,
+ {
+ name: 'RoomView',
+ params: routeParams
+ }
+ ],
+ index: routesRoomView.length
+ });
+ });
+ }
+
+ if (popToRoot) {
+ Navigation.navigate('RoomsListView');
+ }
+ return Navigation.dispatch((state: any) => {
+ const routesRoomsListView = state.routes.filter((r: any) => r.name === 'RoomsListView');
+ return CommonActions.reset({
+ ...state,
+ routes: [
+ ...routesRoomsListView,
+ {
+ name: 'RoomView',
+ params: routeParams
+ }
+ ],
+ index: routesRoomsListView.length
+ });
});
};
@@ -51,13 +85,14 @@ interface IOmnichannelRoomVisitor extends IOmnichannelRoom {
export const goRoom = async ({
item,
isMasterDetail = false,
+ popToRoot = false,
...props
}: {
item: TGoRoomItem;
isMasterDetail: boolean;
- navigationMethod?: any;
jumpToMessageId?: string;
usedCannedResponse?: string;
+ popToRoot?: boolean;
}): Promise => {
if (!('id' in item) && item.t === SubscriptionType.DIRECT && item?.search) {
// if user is using the search we need first to join/create room
@@ -72,6 +107,7 @@ export const goRoom = async ({
t: SubscriptionType.DIRECT
},
isMasterDetail,
+ popToRoot,
...props
});
}
@@ -80,5 +116,5 @@ export const goRoom = async ({
}
}
- return navigate({ item, isMasterDetail, ...props });
+ return navigate({ item, isMasterDetail, popToRoot, ...props });
};
diff --git a/app/lib/methods/subscriptions/room.ts b/app/lib/methods/subscriptions/room.ts
index 11d333be3..56d87d284 100644
--- a/app/lib/methods/subscriptions/room.ts
+++ b/app/lib/methods/subscriptions/room.ts
@@ -125,8 +125,8 @@ export default class RoomSubscription {
if (ev === 'typing') {
const { user } = reduxStore.getState().login;
const { UI_Use_Real_Name } = reduxStore.getState().settings;
- const { rooms } = reduxStore.getState().room;
- if (rooms[0] !== _rid) {
+ const { subscribedRoom } = reduxStore.getState().room;
+ if (subscribedRoom !== _rid) {
return;
}
const [name, typing] = ddpMessage.fields.args;
diff --git a/app/lib/methods/subscriptions/rooms.ts b/app/lib/methods/subscriptions/rooms.ts
index 37505ed63..5bbeffe3d 100644
--- a/app/lib/methods/subscriptions/rooms.ts
+++ b/app/lib/methods/subscriptions/rooms.ts
@@ -197,8 +197,8 @@ const createOrUpdateSubscription = async (subscription: ISubscription, room: ISe
}
}
- const { rooms } = store.getState().room;
- if (tmp.lastMessage && !rooms.includes(tmp.rid)) {
+ const { subscribedRoom } = store.getState().room;
+ if (tmp.lastMessage && subscribedRoom !== tmp.rid) {
const lastMessage = buildMessage(tmp.lastMessage);
const messagesCollection = db.get('messages');
let messageRecord = {} as TMessageModel | null;
diff --git a/app/lib/navigation/appNavigation.ts b/app/lib/navigation/appNavigation.ts
index 7d2f73756..404e185a9 100644
--- a/app/lib/navigation/appNavigation.ts
+++ b/app/lib/navigation/appNavigation.ts
@@ -21,11 +21,16 @@ function popToTop() {
navigationRef.current?.dispatch(StackActions.popToTop());
}
+function dispatch(params: any) {
+ navigationRef.current?.dispatch(params);
+}
+
export default {
navigationRef,
routeNameRef,
navigate,
back,
replace,
- popToTop
+ popToTop,
+ dispatch
};
diff --git a/app/reducers/room.test.ts b/app/reducers/room.test.ts
index 0d383091a..683bf2881 100644
--- a/app/reducers/room.test.ts
+++ b/app/reducers/room.test.ts
@@ -12,13 +12,13 @@ describe('test room reducer', () => {
it('should return modified store after subscribeRoom', () => {
mockedStore.dispatch(subscribeRoom('GENERAL'));
const state = mockedStore.getState().room;
- expect(state.rooms).toEqual(['GENERAL']);
+ expect(state.subscribedRoom).toEqual('GENERAL');
});
it('should return empty store after remove unsubscribeRoom', () => {
mockedStore.dispatch(unsubscribeRoom('GENERAL'));
const state = mockedStore.getState().room;
- expect(state.rooms).toEqual([]);
+ expect(state.subscribedRoom).toEqual('');
});
it('should return initial state after leaveRoom', () => {
diff --git a/app/reducers/room.ts b/app/reducers/room.ts
index e5b9815b4..3462247d3 100644
--- a/app/reducers/room.ts
+++ b/app/reducers/room.ts
@@ -6,13 +6,13 @@ export type IRoomRecord = string[];
export interface IRoom {
rid: string;
isDeleting: boolean;
- rooms: IRoomRecord;
+ subscribedRoom: string;
}
export const initialState: IRoom = {
rid: '',
isDeleting: false,
- rooms: []
+ subscribedRoom: ''
};
export default function (state = initialState, action: TActionsRoom): IRoom {
@@ -20,12 +20,12 @@ export default function (state = initialState, action: TActionsRoom): IRoom {
case ROOM.SUBSCRIBE:
return {
...state,
- rooms: [action.rid, ...state.rooms]
+ subscribedRoom: action.rid
};
case ROOM.UNSUBSCRIBE:
return {
...state,
- rooms: state.rooms.filter(rid => rid !== action.rid)
+ subscribedRoom: state.subscribedRoom === action.rid ? '' : state.subscribedRoom
};
case ROOM.LEAVE:
return {
diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js
index a7b138862..ed81d82ac 100644
--- a/app/sagas/createChannel.js
+++ b/app/sagas/createChannel.js
@@ -4,7 +4,6 @@ import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { CREATE_CHANNEL, LOGIN } from '../actions/actionsTypes';
import { createChannelFailure, createChannelSuccess } from '../actions/createChannel';
import { showErrorAlert } from '../lib/methods/helpers/info';
-import Navigation from '../lib/navigation/appNavigation';
import database from '../lib/database';
import I18n from '../i18n';
import { events, logEvent } from '../lib/methods/helpers/log';
@@ -78,10 +77,7 @@ const handleRequest = function* handleRequest({ data }) {
const handleSuccess = function* handleSuccess({ data }) {
const isMasterDetail = yield select(state => state.app.isMasterDetail);
- if (isMasterDetail) {
- Navigation.navigate('DrawerNavigator');
- }
- goRoom({ item: data, isMasterDetail });
+ goRoom({ item: data, isMasterDetail, popToRoot: true });
};
const handleFailure = function handleFailure({ err, isTeam }) {
diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js
index 47093d164..474e4a7f2 100644
--- a/app/sagas/deepLinking.js
+++ b/app/sagas/deepLinking.js
@@ -1,7 +1,6 @@
import { all, delay, put, select, take, takeLatest } from 'redux-saga/effects';
import UserPreferences from '../lib/methods/userPreferences';
-import Navigation from '../lib/navigation/appNavigation';
import * as types from '../actions/actionsTypes';
import { selectServerRequest, serverInitAdd } from '../actions/server';
import { inviteLinksRequest, inviteLinksSetToken } from '../actions/inviteLinks';
@@ -36,14 +35,6 @@ const handleInviteLink = function* handleInviteLink({ params, requireLogin = fal
}
};
-const popToRoot = function popToRoot({ isMasterDetail }) {
- if (isMasterDetail) {
- Navigation.navigate('DrawerNavigator');
- } else {
- Navigation.navigate('RoomsListView');
- }
-};
-
const navigate = function* navigate({ params }) {
yield put(appStart({ root: RootEnum.ROOT_INSIDE }));
if (params.path || params.rid) {
@@ -65,27 +56,9 @@ const navigate = function* navigate({ params }) {
};
const isMasterDetail = yield select(state => state.app.isMasterDetail);
- const focusedRooms = yield select(state => state.room.rooms);
const jumpToMessageId = params.messageId;
- if (focusedRooms.includes(room.rid)) {
- // if there's one room on the list or last room is the one
- if (focusedRooms.length === 1 || focusedRooms[0] === room.rid) {
- if (jumpToThreadId) {
- // With this conditional when there is a jumpToThreadId we can avoid the thread open again
- // above other thread and the room could call again the thread
- popToRoot({ isMasterDetail });
- }
- yield goRoom({ item, isMasterDetail, jumpToMessageId, jumpToThreadId });
- } else {
- popToRoot({ isMasterDetail });
- yield goRoom({ item, isMasterDetail, jumpToMessageId, jumpToThreadId });
- }
- } else {
- popToRoot({ isMasterDetail });
- yield goRoom({ item, isMasterDetail, jumpToMessageId, jumpToThreadId });
- }
-
+ yield goRoom({ item, isMasterDetail, jumpToMessageId, jumpToThreadId, popToRoot: true });
if (params.isCall) {
callJitsi(item);
}
diff --git a/app/sagas/messages.js b/app/sagas/messages.js
index 6940f2409..ddae85213 100644
--- a/app/sagas/messages.js
+++ b/app/sagas/messages.js
@@ -1,7 +1,6 @@
import { select, takeLatest } from 'redux-saga/effects';
import { Q } from '@nozbe/watermelondb';
-import Navigation from '../lib/navigation/appNavigation';
import { MESSAGES } from '../actions/actionsTypes';
import database from '../lib/database';
import log from '../lib/methods/helpers/log';
@@ -16,18 +15,13 @@ const handleReplyBroadcast = function* handleReplyBroadcast({ message }) {
const subscriptions = yield subsCollection.query(Q.where('name', username)).fetch();
const isMasterDetail = yield select(state => state.app.isMasterDetail);
- if (isMasterDetail) {
- Navigation.navigate('DrawerNavigator');
- } else {
- Navigation.navigate('RoomsListView');
- }
if (subscriptions.length) {
- goRoom({ item: subscriptions[0], isMasterDetail, message });
+ goRoom({ item: subscriptions[0], isMasterDetail, popToRoot: true, message });
} else {
const result = yield Services.createDirectMessage(username);
if (result?.success) {
- goRoom({ item: result?.room, isMasterDetail, message });
+ goRoom({ item: result?.room, isMasterDetail, popToRoot: true, message });
}
}
} catch (e) {
diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js
index 156c5607e..6f2bc73da 100644
--- a/app/sagas/rooms.js
+++ b/app/sagas/rooms.js
@@ -58,13 +58,13 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) {
const subsToCreate = subscriptions.filter(i1 => !existingSubs.find(i2 => i1._id === i2._id));
const subsToDelete = existingSubs.filter(i1 => !subscriptions.find(i2 => i1._id === i2._id));
- const openedRooms = yield select(state => state.room.rooms);
+ const subscribedRoom = yield select(state => state.room.subscribedRoom);
const lastMessages = subscriptions
/** Checks for opened rooms and filter them out.
* It prevents this process to try persisting the same last message on the room messages fetch.
* This race condition is easy to reproduce on push notification tap.
*/
- .filter(sub => !openedRooms.includes(sub.rid))
+ .filter(sub => subscribedRoom !== sub.rid)
.map(sub => sub.lastMessage && buildMessage(sub.lastMessage))
.filter(lm => lm);
const lastMessagesIds = lastMessages.map(lm => lm._id).filter(lm => lm);
diff --git a/app/views/AddExistingChannelView.tsx b/app/views/AddExistingChannelView.tsx
index ea4f5be67..88aa83f15 100644
--- a/app/views/AddExistingChannelView.tsx
+++ b/app/views/AddExistingChannelView.tsx
@@ -17,7 +17,6 @@ import { TSupportedThemes, withTheme } from '../theme';
import SafeAreaView from '../containers/SafeAreaView';
import { sendLoadingEvent } from '../containers/Loading';
import { animateNextTransition } from '../lib/methods/helpers/layoutAnimation';
-import { goRoom } from '../lib/methods/helpers/goRoom';
import { showErrorAlert } from '../lib/methods/helpers/info';
import { ChatsStackParamList } from '../stacks/types';
import { TSubscriptionModel, SubscriptionType, IApplicationState } from '../definitions';
@@ -126,7 +125,7 @@ class AddExistingChannelView extends React.Component {
const { selected } = this.state;
- const { isMasterDetail } = this.props;
+ const { navigation } = this.props;
sendLoadingEvent({ visible: true });
try {
@@ -134,9 +133,8 @@ class AddExistingChannelView extends React.Component state.app);
- const { rooms } = useAppSelector(state => state.room);
useEffect(() => {
navigation.setOptions({
@@ -107,31 +104,9 @@ const CannedResponseDetail = ({ navigation, route }: ICannedResponseDetailProps)
const navigateToRoom = (item: ICannedResponse) => {
const { room } = route.params;
- const { name } = room;
- const params = {
- rid: room.rid,
- name: getRoomTitle({
- t: room.t,
- fname: name
- }),
- t: room.t,
- roomUserId: getUidDirectMessage(room),
- usedCannedResponse: item.text
- };
if (room.rid) {
- // if it's on master detail layout, we close the modal and replace RoomView
- if (isMasterDetail) {
- Navigation.navigate('DrawerNavigator');
- goRoom({ item: params, isMasterDetail });
- } else {
- let navigate = navigation.push;
- // if this is a room focused
- if (rooms.includes(room.rid)) {
- ({ navigate } = navigation);
- }
- navigate('RoomView', params);
- }
+ goRoom({ item: room, isMasterDetail, popToRoot: true, usedCannedResponse: item.text });
}
};
diff --git a/app/views/CannedResponsesListView/index.tsx b/app/views/CannedResponsesListView/index.tsx
index 385454750..100e64569 100644
--- a/app/views/CannedResponsesListView/index.tsx
+++ b/app/views/CannedResponsesListView/index.tsx
@@ -12,7 +12,6 @@ import ActivityIndicator from '../../containers/ActivityIndicator';
import SearchHeader from '../../containers/SearchHeader';
import BackgroundContainer from '../../containers/BackgroundContainer';
import { useTheme } from '../../theme';
-import Navigation from '../../lib/navigation/appNavigation';
import { goRoom } from '../../lib/methods/helpers/goRoom';
import * as HeaderButton from '../../containers/HeaderButton';
import * as List from '../../containers/List';
@@ -24,7 +23,7 @@ import DropdownItemHeader from './Dropdown/DropdownItemHeader';
import styles from './styles';
import { ICannedResponse } from '../../definitions/ICannedResponse';
import { ChatsStackParamList } from '../../stacks/types';
-import { getRoomTitle, getUidDirectMessage, useDebounce } from '../../lib/methods/helpers';
+import { useDebounce } from '../../lib/methods/helpers';
import { Services } from '../../lib/services';
import { ILivechatDepartment } from '../../definitions/ILivechatDepartment';
import { useAppSelector } from '../../lib/hooks';
@@ -73,7 +72,6 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
const { theme } = useTheme();
const isMasterDetail = useAppSelector(state => state.app.isMasterDetail);
- const rooms = useAppSelector(state => state.room.rooms);
const getRoomFromDb = async () => {
const { rid } = route.params;
@@ -107,34 +105,8 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
};
const navigateToRoom = (item: ICannedResponse) => {
- if (!room) {
- return;
- }
- const { name } = room;
- const params = {
- rid: room.rid,
- name: getRoomTitle({
- t: room.t,
- fname: name
- }),
- t: room.t,
- roomUserId: getUidDirectMessage(room),
- usedCannedResponse: item.text
- };
-
- if (room.rid) {
- // if it's on master detail layout, we close the modal and replace RoomView
- if (isMasterDetail) {
- Navigation.navigate('DrawerNavigator');
- goRoom({ item: params, isMasterDetail });
- } else {
- let navigate = navigation.push;
- // if this is a room focused
- if (rooms.includes(room.rid)) {
- ({ navigate } = navigation);
- }
- navigate('RoomView', params);
- }
+ if (room?.rid) {
+ goRoom({ item: room, isMasterDetail, popToRoot: true, usedCannedResponse: item.text });
}
};
diff --git a/app/views/CreateDiscussionView/index.tsx b/app/views/CreateDiscussionView/index.tsx
index 6d781d291..9ce8e1fbe 100644
--- a/app/views/CreateDiscussionView/index.tsx
+++ b/app/views/CreateDiscussionView/index.tsx
@@ -12,7 +12,6 @@ import StatusBar from '../../containers/StatusBar';
import { withTheme } from '../../theme';
import { getUserSelector } from '../../selectors/login';
import { FormTextInput } from '../../containers/TextInput';
-import Navigation from '../../lib/navigation/appNavigation';
import { createDiscussionRequest, ICreateDiscussionRequestData } from '../../actions/createDiscussion';
import SafeAreaView from '../../containers/SafeAreaView';
import { goRoom } from '../../lib/methods/helpers/goRoom';
@@ -60,18 +59,13 @@ class CreateChannelView extends React.Component {
- const { navigation, isMasterDetail } = this.props;
- if (isMasterDetail) {
- navigation.navigate('DrawerNavigator');
- } else {
- navigation.navigate('RoomsListView');
- }
- goRoom({ item, isMasterDetail });
+ const { isMasterDetail } = this.props;
+ goRoom({ item, isMasterDetail, popToRoot: true });
};
onPressItem = async (item: IServerRoom) => {
diff --git a/app/views/NewMessageView/index.tsx b/app/views/NewMessageView/index.tsx
index 8f05d5809..f393a9f91 100644
--- a/app/views/NewMessageView/index.tsx
+++ b/app/views/NewMessageView/index.tsx
@@ -74,10 +74,7 @@ const NewMessageView = () => {
const goRoom = useCallback(
(item: TGoRoomItem) => {
logEvent(events.NEW_MSG_CHAT_WITH_USER);
-
- if (isMasterDetail) {
- navigation.pop();
- }
+ navigation.pop();
goRoomMethod({ item, isMasterDetail });
},
[isMasterDetail, navigation]
diff --git a/app/views/RoomInfoView/index.tsx b/app/views/RoomInfoView/index.tsx
index 9c7c9dde7..2744c0cc6 100644
--- a/app/views/RoomInfoView/index.tsx
+++ b/app/views/RoomInfoView/index.tsx
@@ -87,7 +87,7 @@ interface IRoomInfoViewProps {
StackNavigationProp
>;
route: RouteProp;
- rooms: string[];
+ subscribedRoom: string;
theme: TSupportedThemes;
isMasterDetail: boolean;
jitsiEnabled: boolean;
@@ -353,7 +353,7 @@ class RoomInfoView extends React.Component {
logEvent(events.RI_GO_ROOM_USER);
const { room } = this.state;
- const { rooms, navigation, isMasterDetail } = this.props;
+ const { navigation, isMasterDetail, subscribedRoom } = this.props;
const params = {
rid: room.rid,
name: getRoomTitle(room),
@@ -362,18 +362,14 @@ class RoomInfoView extends React.Component ({
- rooms: state.room.rooms,
+ subscribedRoom: state.room.subscribedRoom,
isMasterDetail: state.app.isMasterDetail,
jitsiEnabled: (state.settings.Jitsi_Enabled as boolean) || false,
editRoomPermission: state.permissions['edit-room'],
diff --git a/app/views/RoomMembersView/helpers.ts b/app/views/RoomMembersView/helpers.ts
index ff622dbf4..d1a7e8945 100644
--- a/app/views/RoomMembersView/helpers.ts
+++ b/app/views/RoomMembersView/helpers.ts
@@ -15,12 +15,7 @@ import { RoomTypes } from '../../lib/methods';
export type TRoomType = SubscriptionType.CHANNEL | SubscriptionType.GROUP | SubscriptionType.OMNICHANNEL;
const handleGoRoom = (item: TGoRoomItem, isMasterDetail: boolean): void => {
- if (isMasterDetail) {
- appNavigation.navigate('DrawerNavigator');
- } else {
- appNavigation.popToTop();
- }
- goRoom({ item, isMasterDetail });
+ goRoom({ item, isMasterDetail, popToRoot: true });
};
export const fetchRole = (role: string, selectedUser: TUserModel, roomRoles: any): boolean => {
diff --git a/app/views/RoomView/index.tsx b/app/views/RoomView/index.tsx
index 6a889943b..978372aa9 100644
--- a/app/views/RoomView/index.tsx
+++ b/app/views/RoomView/index.tsx
@@ -43,7 +43,6 @@ import SafeAreaView from '../../containers/SafeAreaView';
import { withDimensions } from '../../dimensions';
import { takeInquiry, takeResume } from '../../ee/omnichannel/lib';
import { sendLoadingEvent } from '../../containers/Loading';
-import { goRoom, TGoRoomItem } from '../../lib/methods/helpers/goRoom';
import getThreadName from '../../lib/methods/getThreadName';
import getRoomInfo from '../../lib/methods/getRoomInfo';
import { ContainerTypes } from '../../containers/UIKit/interfaces';
@@ -101,6 +100,7 @@ import {
} from '../../lib/methods/helpers';
import { Services } from '../../lib/services';
import { withActionSheet, IActionSheetProvider } from '../../containers/ActionSheet';
+import { goRoom, TGoRoomItem } from '../../lib/methods/helpers/goRoom';
type TStateAttrsUpdate = keyof IRoomViewState;
@@ -910,15 +910,15 @@ class RoomView extends React.Component {
onDiscussionPress = debounce(
async (item: TAnyMessageModel) => {
- const { navigation } = this.props;
+ const { isMasterDetail } = this.props;
if (!item.drid) return;
const sub = await getRoomInfo(item.drid);
- navigation.push('RoomView', {
- rid: item.drid as string,
- prid: item?.subscription?.id,
- name: item.msg,
- t: (sub?.t as SubscriptionType) || (this.t as SubscriptionType)
- });
+ if (sub) {
+ goRoom({
+ item: sub as TGoRoomItem,
+ isMasterDetail
+ });
+ }
},
1000,
true
@@ -987,6 +987,11 @@ class RoomView extends React.Component {
} else {
this.navToThread(message);
}
+ } else if (!message.tmid && message.rid === this.rid && this.t === 'thread' && !message.replies) {
+ /**
+ * if the user is within a thread and the message that he is trying to jump to, is a message in the main room
+ */
+ return this.navToRoom(message);
} else {
/**
* if it's from server, we don't have it saved locally and so we fetch surroundings
@@ -1198,12 +1203,12 @@ class RoomView extends React.Component {
};
navToRoom = async (message: TAnyMessageModel) => {
- const { navigation, isMasterDetail } = this.props;
+ const { isMasterDetail } = this.props;
const roomInfo = await getRoomInfo(message.rid);
+
return goRoom({
item: roomInfo as TGoRoomItem,
isMasterDetail,
- navigationMethod: navigation.push,
jumpToMessageId: message.id
});
};
diff --git a/app/views/RoomsListView/index.tsx b/app/views/RoomsListView/index.tsx
index 84062f715..3ff5ff6a6 100644
--- a/app/views/RoomsListView/index.tsx
+++ b/app/views/RoomsListView/index.tsx
@@ -6,8 +6,10 @@ import Orientation from 'react-native-orientation-locker';
import { Q } from '@nozbe/watermelondb';
import { withSafeAreaInsets } from 'react-native-safe-area-context';
import { Subscription } from 'rxjs';
-import { StackNavigationOptions } from '@react-navigation/stack';
+import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
import { Header } from '@react-navigation/elements';
+import { CompositeNavigationProp, RouteProp } from '@react-navigation/native';
+import { Dispatch } from 'redux';
import database from '../../lib/database';
import RoomItem, { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from '../../containers/RoomItem';
@@ -20,7 +22,7 @@ import StatusBar from '../../containers/StatusBar';
import ActivityIndicator from '../../containers/ActivityIndicator';
import { serverInitAdd } from '../../actions/server';
import { animateNextTransition } from '../../lib/methods/helpers/layoutAnimation';
-import { withTheme } from '../../theme';
+import { TSupportedThemes, withTheme } from '../../theme';
import EventEmitter from '../../lib/methods/helpers/events';
import { themedHeader } from '../../lib/methods/helpers/navigation';
import {
@@ -39,20 +41,12 @@ import { goRoom } from '../../lib/methods/helpers/goRoom';
import SafeAreaView from '../../containers/SafeAreaView';
import { withDimensions } from '../../dimensions';
import { getInquiryQueueSelector } from '../../ee/omnichannel/selectors/inquiry';
-import {
- IApplicationState,
- IBaseScreen,
- ISubscription,
- IUser,
- RootEnum,
- SubscriptionType,
- TSubscriptionModel
-} from '../../definitions';
+import { IApplicationState, ISubscription, IUser, RootEnum, SubscriptionType, TSubscriptionModel } from '../../definitions';
import styles from './styles';
import ServerDropdown from './ServerDropdown';
import ListHeader, { TEncryptionBanner } from './ListHeader';
import RoomsListHeaderView from './Header';
-import { ChatsStackParamList } from '../../stacks/types';
+import { ChatsStackParamList, DrawerParamList } from '../../stacks/types';
import { RoomTypes, search } from '../../lib/methods';
import {
getRoomAvatar,
@@ -67,7 +61,16 @@ import {
import { E2E_BANNER_TYPE, DisplayMode, SortBy, MAX_SIDEBAR_WIDTH, themes } from '../../lib/constants';
import { Services } from '../../lib/services';
-interface IRoomsListViewProps extends IBaseScreen {
+type TNavigation = CompositeNavigationProp<
+ StackNavigationProp,
+ CompositeNavigationProp, StackNavigationProp>
+>;
+
+interface IRoomsListViewProps {
+ navigation: TNavigation;
+ route: RouteProp;
+ theme: TSupportedThemes;
+ dispatch: Dispatch;
[key: string]: IUser | string | boolean | ISubscription[] | number | object | TEncryptionBanner;
user: IUser;
server: string;
@@ -83,7 +86,7 @@ interface IRoomsListViewProps extends IBaseScreen {
logEvent(events.RL_GO_ROOM);
const { item: currentItem } = this.state;
- const { rooms } = this.props;
- // @ts-ignore
- if (currentItem?.rid === item.rid || rooms?.includes(item.rid)) {
+ const { subscribedRoom } = this.props;
+
+ if (currentItem?.rid === item.rid || subscribedRoom === item.rid) {
return;
}
// Only mark room as focused when in master detail layout
@@ -1040,7 +1043,7 @@ const mapStateToProps = (state: IApplicationState) => ({
showUnread: state.sortPreferences.showUnread,
useRealName: state.settings.UI_Use_Real_Name,
StoreLastMessage: state.settings.Store_Last_Message,
- rooms: state.room.rooms,
+ subscribedRoom: state.room.subscribedRoom,
queueSize: getInquiryQueueSelector(state).length,
inquiryEnabled: state.inquiry.enabled,
encryptionBanner: state.encryption.banner,
diff --git a/app/views/TeamChannelsView.tsx b/app/views/TeamChannelsView.tsx
index 357c6e2ed..a6bc411f4 100644
--- a/app/views/TeamChannelsView.tsx
+++ b/app/views/TeamChannelsView.tsx
@@ -322,7 +322,7 @@ class TeamChannelsView extends React.Component {
logEvent(events.TC_GO_ROOM);
- const { navigation, isMasterDetail } = this.props;
+ const { isMasterDetail } = this.props;
try {
let params = {};
const result = await Services.getRoomInfo(item._id);
@@ -335,10 +335,7 @@ class TeamChannelsView extends React.Component {
+ let dmCreatedRid: string;
+
+ before(async () => {
+ await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
+ await navigateToLogin();
+ await login(data.users.regular.username, data.users.regular.password);
+ const result = await post(`im.create`, { username: data.users.alternate.username });
+ dmCreatedRid = result.data.room.rid;
+ });
+
+ describe('receive in RoomsListView', () => {
+ const text = 'Message in DM';
+ it('should have rooms list screen', async () => {
+ await expect(element(by.id('rooms-list-view'))).toBeVisible();
+ });
+
+ it('should send direct message from user alternate to user regular', async () => {
+ await sleep(1000);
+ await sendMessage(data.users.alternate, dmCreatedRid, text);
+ });
+
+ it('should tap on InApp Notification', async () => {
+ await waitFor(element(by.id(`in-app-notification-${text}`)))
+ .toExist()
+ .withTimeout(2000);
+ await sleep(500);
+ await element(by.id(`in-app-notification-${text}`)).tap();
+ await sleep(500);
+ await expect(element(by.id('room-header'))).toExist();
+ await expect(element(by.id(`room-view-title-${data.users.alternate.username}`))).toExist();
+ });
+ });
+
+ describe('receive in another room', () => {
+ const text = 'Another msg';
+ it('should back to RoomsListView and open the channel Detox Public', async () => {
+ await tapBack();
+ await sleep(500);
+ await element(by.id(`rooms-list-view-item-${data.userRegularChannels.detoxpublic.name}`)).tap();
+ await waitFor(element(by.id('room-view')))
+ .toBeVisible()
+ .withTimeout(5000);
+ await expect(element(by.id(`room-view-title-${data.userRegularChannels.detoxpublic.name}`))).toExist();
+ });
+
+ it('should receive and tap InAppNotification in another room', async () => {
+ await sendMessage(data.users.alternate, dmCreatedRid, text);
+ await waitFor(element(by.id(`in-app-notification-${text}`)))
+ .toExist()
+ .withTimeout(2000);
+ await sleep(500);
+ await element(by.id(`in-app-notification-${text}`)).tap();
+ await sleep(500);
+ await expect(element(by.id('room-header'))).toExist();
+ await expect(element(by.id(`room-view-title-${data.users.alternate.username}`))).toExist();
+ });
+
+ it('should back to RoomsListView', async () => {
+ await tapBack();
+ await sleep(500);
+ await expect(element(by.id('rooms-list-view'))).toBeVisible();
+ });
+ });
+});
diff --git a/e2e/tests/room/09-jumptomessage.spec.ts b/e2e/tests/room/09-jumptomessage.spec.ts
index c2aea7ffb..c1ad32a05 100644
--- a/e2e/tests/room/09-jumptomessage.spec.ts
+++ b/e2e/tests/room/09-jumptomessage.spec.ts
@@ -200,7 +200,7 @@ describe('Room', () => {
const expectThreadMessages = async (message: string) => {
await waitFor(element(by.id('room-view-title-thread 1')))
.toExist()
- .withTimeout(5000);
+ .withTimeout(10000);
await waitFor(element(by[textMatcher](message)).atIndex(0))
.toExist()
.withTimeout(10000);
diff --git a/e2e/tests/team/02-team.spec.ts b/e2e/tests/team/02-team.spec.ts
index 382ed1ddf..5e22550a8 100644
--- a/e2e/tests/team/02-team.spec.ts
+++ b/e2e/tests/team/02-team.spec.ts
@@ -199,6 +199,14 @@ describe('Team', () => {
});
it('should add existing channel to team', async () => {
+ await navigateToRoom(team);
+ await waitFor(element(by.id('room-view-header-team-channels')))
+ .toExist()
+ .withTimeout(5000);
+ await element(by.id('room-view-header-team-channels')).tap();
+ await waitFor(element(by.id('team-channels-view')))
+ .toExist()
+ .withTimeout(5000);
await element(by.id('team-channels-view-create')).tap();
await waitFor(element(by.id('add-channel-team-view')))
.toExist()