diff --git a/app/constants/messageTypeLoad.ts b/app/constants/messageTypeLoad.ts index 4bdaa54de8..6836981aa6 100644 --- a/app/constants/messageTypeLoad.ts +++ b/app/constants/messageTypeLoad.ts @@ -1,5 +1,7 @@ -export const MESSAGE_TYPE_LOAD_MORE = 'load_more'; -export const MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK = 'load_previous_chunk'; -export const MESSAGE_TYPE_LOAD_NEXT_CHUNK = 'load_next_chunk'; +export enum MessageTypeLoad { + MORE = 'load_more', + PREVIOUS_CHUNK = 'load_previous_chunk', + NEXT_CHUNK = 'load_next_chunk' +} -export const MESSAGE_TYPE_ANY_LOAD = [MESSAGE_TYPE_LOAD_MORE, MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK, MESSAGE_TYPE_LOAD_NEXT_CHUNK]; +export const MESSAGE_TYPE_ANY_LOAD = [MessageTypeLoad.MORE, MessageTypeLoad.PREVIOUS_CHUNK, MessageTypeLoad.NEXT_CHUNK]; diff --git a/app/containers/MessageBox/index.tsx b/app/containers/MessageBox/index.tsx index 13eefd7fa6..2143eb6308 100644 --- a/app/containers/MessageBox/index.tsx +++ b/app/containers/MessageBox/index.tsx @@ -926,8 +926,8 @@ class MessageBox extends Component { let msg = `[ ](${permalink}) `; // if original message wasn't sent by current user and neither from a direct room - if (user.username !== replyingMessage.u.username && roomType !== 'd' && replyWithMention) { - msg += `@${replyingMessage.u.username} `; + if (user.username !== replyingMessage?.u?.username && roomType !== 'd' && replyWithMention) { + msg += `@${replyingMessage?.u?.username} `; } msg = `${msg} ${message}`; diff --git a/app/definitions/IMessage.ts b/app/definitions/IMessage.ts index 0d0a4683f3..c0dbe40701 100644 --- a/app/definitions/IMessage.ts +++ b/app/definitions/IMessage.ts @@ -1,27 +1,14 @@ import Model from '@nozbe/watermelondb/Model'; import { MarkdownAST } from '@rocket.chat/message-parser'; +import { MessageTypeLoad } from '../constants/messageTypeLoad'; import { IAttachment } from './IAttachment'; import { IReaction } from './IReaction'; -import { - MESSAGE_TYPE_LOAD_MORE, - MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK, - MESSAGE_TYPE_LOAD_NEXT_CHUNK -} from '../constants/messageTypeLoad'; import { TThreadMessageModel } from './IThreadMessage'; import { TThreadModel } from './IThread'; import { IUrlFromServer } from './IUrl'; -export type MessageType = - | 'jitsi_call_started' - | 'discussion-created' - | 'e2e' - | 'load_more' - | 'rm' - | 'uj' - | typeof MESSAGE_TYPE_LOAD_MORE - | typeof MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK - | typeof MESSAGE_TYPE_LOAD_NEXT_CHUNK; +export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj' | MessageTypeLoad; export interface IUserMessage { _id: string; diff --git a/app/definitions/ISubscription.ts b/app/definitions/ISubscription.ts index a0dd4c5a26..dee63ecb50 100644 --- a/app/definitions/ISubscription.ts +++ b/app/definitions/ISubscription.ts @@ -30,6 +30,8 @@ export enum ERoomTypes { CHANNEL = 'channel' } +type RelationModified = { fetch(): Promise } & Relation; + export interface ISubscription { _id: string; // _id belongs watermelonDB id: string; // id from server @@ -93,10 +95,10 @@ export interface ISubscription { teamMain?: boolean; separator?: boolean; // https://nozbe.github.io/WatermelonDB/Relation.html#relation-api - messages: Relation; - threads: Relation; - threadMessages: Relation; - uploads: Relation; + messages: RelationModified; + threads: RelationModified; + threadMessages: RelationModified; + uploads: RelationModified; } export type TSubscriptionModel = ISubscription & Model; diff --git a/app/lib/methods/loadMessagesForRoom.ts b/app/lib/methods/loadMessagesForRoom.ts index b72371bfb1..f2bce7102c 100644 --- a/app/lib/methods/loadMessagesForRoom.ts +++ b/app/lib/methods/loadMessagesForRoom.ts @@ -1,6 +1,7 @@ import moment from 'moment'; -import { IMessage, MessageType, TMessageModel } from '../../definitions'; +import { MessageTypeLoad } from '../../constants/messageTypeLoad'; +import { IMessage, TMessageModel } from '../../definitions'; import log from '../../utils/log'; import { getMessageById } from '../database/services/Message'; import roomTypeToApiType, { RoomTypes } from '../rocketchat/methods/roomTypeToApiType'; @@ -46,7 +47,7 @@ export default function loadMessagesForRoom(args: { _id: generateLoadMoreId(lastMessage._id as string), rid: lastMessage.rid, ts: moment(lastMessage.ts).subtract(1, 'millisecond').toString(), - t: 'load_more' as MessageType, + t: MessageTypeLoad.MORE, msg: lastMessage.msg }; data.push(loadMoreMessage); diff --git a/app/lib/methods/loadNextMessages.ts b/app/lib/methods/loadNextMessages.ts index 45a007d632..063170652c 100644 --- a/app/lib/methods/loadNextMessages.ts +++ b/app/lib/methods/loadNextMessages.ts @@ -4,7 +4,7 @@ import orderBy from 'lodash/orderBy'; import log from '../../utils/log'; import { getMessageById } from '../database/services/Message'; -import { MESSAGE_TYPE_LOAD_NEXT_CHUNK } from '../../constants/messageTypeLoad'; +import { MessageTypeLoad } from '../../constants/messageTypeLoad'; import { generateLoadMoreId } from '../utils'; import updateMessages from './updateMessages'; import { TMessageModel } from '../../definitions'; @@ -34,7 +34,7 @@ export default function loadNextMessages(args: ILoadNextMessages): Promise rid: lastMessage.rid, tmid: args.tmid, ts: moment(lastMessage.ts).add(1, 'millisecond'), - t: MESSAGE_TYPE_LOAD_NEXT_CHUNK + t: MessageTypeLoad.NEXT_CHUNK }; messages.push(loadMoreItem); } diff --git a/app/lib/methods/loadSurroundingMessages.js b/app/lib/methods/loadSurroundingMessages.ts similarity index 67% rename from app/lib/methods/loadSurroundingMessages.js rename to app/lib/methods/loadSurroundingMessages.ts index bc25ae6953..727bd200ea 100644 --- a/app/lib/methods/loadSurroundingMessages.js +++ b/app/lib/methods/loadSurroundingMessages.ts @@ -4,21 +4,23 @@ import orderBy from 'lodash/orderBy'; import log from '../../utils/log'; import { getMessageById } from '../database/services/Message'; -import { MESSAGE_TYPE_LOAD_NEXT_CHUNK, MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK } from '../../constants/messageTypeLoad'; +import { MessageTypeLoad } from '../../constants/messageTypeLoad'; +import sdk from '../rocketchat/services/sdk'; +import { IMessage } from '../../definitions'; import { generateLoadMoreId } from '../utils'; import updateMessages from './updateMessages'; const COUNT = 50; -export default function loadSurroundingMessages({ messageId, rid }) { +export default function loadSurroundingMessages({ messageId, rid }: { messageId: string; rid: string }) { return new Promise(async (resolve, reject) => { try { - const data = await this.methodCallWrapper('loadSurroundingMessages', { _id: messageId, rid }, COUNT); - let messages = EJSON.fromJSONValue(data?.messages); + const data = await sdk.methodCallWrapper('loadSurroundingMessages', { _id: messageId, rid }, COUNT); + let messages: IMessage[] = EJSON.fromJSONValue(data?.messages); messages = orderBy(messages, 'ts'); const message = messages.find(m => m._id === messageId); - const { tmid } = message; + const tmid = message?.tmid; if (messages?.length) { if (data?.moreBefore) { @@ -29,10 +31,10 @@ export default function loadSurroundingMessages({ messageId, rid }) { _id: generateLoadMoreId(firstMessage._id), rid: firstMessage.rid, tmid, - ts: moment(firstMessage.ts).subtract(1, 'millisecond'), - t: MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK, + ts: moment(firstMessage.ts).subtract(1, 'millisecond').toDate(), + t: MessageTypeLoad.PREVIOUS_CHUNK, msg: firstMessage.msg - }; + } as IMessage; messages.unshift(loadMoreItem); } } @@ -45,18 +47,18 @@ export default function loadSurroundingMessages({ messageId, rid }) { _id: generateLoadMoreId(lastMessage._id), rid: lastMessage.rid, tmid, - ts: moment(lastMessage.ts).add(1, 'millisecond'), - t: MESSAGE_TYPE_LOAD_NEXT_CHUNK, + ts: moment(lastMessage.ts).add(1, 'millisecond').toDate(), + t: MessageTypeLoad.NEXT_CHUNK, msg: lastMessage.msg - }; + } as IMessage; messages.push(loadMoreItem); } } + await updateMessages({ rid, update: messages }); return resolve(messages); - } else { - return resolve([]); } + return resolve([]); } catch (e) { log(e); reject(e); diff --git a/app/views/RoomView/LoadMore/LoadMore.stories.js b/app/views/RoomView/LoadMore/LoadMore.stories.js index eb719646bd..7f8137d1c3 100644 --- a/app/views/RoomView/LoadMore/LoadMore.stories.js +++ b/app/views/RoomView/LoadMore/LoadMore.stories.js @@ -7,11 +7,7 @@ import { longText } from '../../../../storybook/utils'; import { ThemeContext } from '../../../theme'; import { Message, MessageDecorator, StoryProvider } from '../../../../storybook/stories/Message'; import { themes } from '../../../constants/colors'; -import { - MESSAGE_TYPE_LOAD_MORE, - MESSAGE_TYPE_LOAD_NEXT_CHUNK, - MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK -} from '../../../constants/messageTypeLoad'; +import { MessageTypeLoad } from '../../../constants/messageTypeLoad'; import LoadMore from './index'; const stories = storiesOf('LoadMore', module); @@ -23,20 +19,20 @@ stories.add('basic', () => ( <> - - + + )); const ThemeStory = ({ theme }) => ( - + - - + + diff --git a/app/views/RoomView/LoadMore/index.tsx b/app/views/RoomView/LoadMore/index.tsx index c29fe2053b..7dcd85ea61 100644 --- a/app/views/RoomView/LoadMore/index.tsx +++ b/app/views/RoomView/LoadMore/index.tsx @@ -2,7 +2,8 @@ import React, { useCallback, useEffect, useState } from 'react'; import { ActivityIndicator, StyleSheet, Text } from 'react-native'; import { themes } from '../../../constants/colors'; -import { MESSAGE_TYPE_LOAD_NEXT_CHUNK, MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK } from '../../../constants/messageTypeLoad'; +import { MessageTypeLoad } from '../../../constants/messageTypeLoad'; +import { MessageType } from '../../../definitions'; import { useTheme } from '../../../theme'; import Touch from '../../../utils/touch'; import sharedStyles from '../../Styles'; @@ -20,7 +21,15 @@ const styles = StyleSheet.create({ } }); -const LoadMore = ({ load, type, runOnRender }: { load: Function; type: string; runOnRender: boolean }): React.ReactElement => { +const LoadMore = ({ + load, + type, + runOnRender +}: { + load: Function; + type: MessageType; + runOnRender: boolean; +}): React.ReactElement => { const { theme } = useTheme(); const [loading, setLoading] = useState(false); @@ -43,10 +52,10 @@ const LoadMore = ({ load, type, runOnRender }: { load: Function; type: string; r }, []); let text = 'Load_More'; - if (type === MESSAGE_TYPE_LOAD_NEXT_CHUNK) { + if (type === MessageTypeLoad.NEXT_CHUNK) { text = 'Load_Newer'; } - if (type === MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK) { + if (type === MessageTypeLoad.PREVIOUS_CHUNK) { text = 'Load_Older'; } diff --git a/app/views/RoomView/index.tsx b/app/views/RoomView/index.tsx index f5aa59e15d..0fbbc44940 100644 --- a/app/views/RoomView/index.tsx +++ b/app/views/RoomView/index.tsx @@ -24,7 +24,7 @@ import I18n from '../../i18n'; import RoomHeader from '../../containers/RoomHeader'; import StatusBar from '../../containers/StatusBar'; import { themes } from '../../constants/colors'; -import { MESSAGE_TYPE_ANY_LOAD, MESSAGE_TYPE_LOAD_MORE } from '../../constants/messageTypeLoad'; +import { MESSAGE_TYPE_ANY_LOAD, MessageTypeLoad } from '../../constants/messageTypeLoad'; import debounce from '../../utils/debounce'; import ReactionsModal from '../../containers/ReactionsModal'; import { LISTENER } from '../../containers/Toast'; @@ -851,7 +851,7 @@ class RoomView extends React.Component { * if it's from server, we don't have it saved locally and so we fetch surroundings * we test if it's not from threads because we're fetching from threads currently with `getThreadMessages` */ - if (message.fromServer && !message.tmid) { + if (message.fromServer && !message.tmid && this.rid) { await RocketChat.loadSurroundingMessages({ messageId, rid: this.rid }); } // @ts-ignore @@ -1161,12 +1161,12 @@ class RoomView extends React.Component { } let content = null; - if (item.t && MESSAGE_TYPE_ANY_LOAD.includes(item.t)) { + if (item.t && MESSAGE_TYPE_ANY_LOAD.includes(item.t as MessageTypeLoad)) { content = ( this.onLoadMoreMessages(item)} type={item.t} - runOnRender={item.t === MESSAGE_TYPE_LOAD_MORE && !previousItem} + runOnRender={item.t === MessageTypeLoad.MORE && !previousItem} /> ); } else { diff --git a/app/views/RoomView/services/getMoreMessages.ts b/app/views/RoomView/services/getMoreMessages.ts index dae63c3b06..99e22bbc49 100644 --- a/app/views/RoomView/services/getMoreMessages.ts +++ b/app/views/RoomView/services/getMoreMessages.ts @@ -1,11 +1,7 @@ -import { MessageType, SubscriptionType, TAnyMessageModel } from '../../../definitions'; +import { SubscriptionType, TAnyMessageModel } from '../../../definitions'; import loadMessagesForRoom from '../../../lib/methods/loadMessagesForRoom'; import loadNextMessages from '../../../lib/methods/loadNextMessages'; -import { - MESSAGE_TYPE_LOAD_MORE, - MESSAGE_TYPE_LOAD_NEXT_CHUNK, - MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK -} from '../../../constants/messageTypeLoad'; +import { MessageTypeLoad } from '../../../constants/messageTypeLoad'; const getMoreMessages = ({ rid, @@ -18,7 +14,7 @@ const getMoreMessages = ({ tmid?: string; loaderItem: TAnyMessageModel; }): Promise => { - if ([MESSAGE_TYPE_LOAD_MORE, MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK].includes(loaderItem.t as MessageType)) { + if ([MessageTypeLoad.MORE, MessageTypeLoad.PREVIOUS_CHUNK].includes(loaderItem.t as MessageTypeLoad)) { return loadMessagesForRoom({ rid, t: t as any, @@ -27,7 +23,7 @@ const getMoreMessages = ({ }); } - if (loaderItem.t === MESSAGE_TYPE_LOAD_NEXT_CHUNK) { + if (loaderItem.t === MessageTypeLoad.NEXT_CHUNK) { return loadNextMessages({ rid, tmid, diff --git a/app/views/ThreadMessagesView/index.tsx b/app/views/ThreadMessagesView/index.tsx index d2ea4527de..cf40dab82b 100644 --- a/app/views/ThreadMessagesView/index.tsx +++ b/app/views/ThreadMessagesView/index.tsx @@ -7,7 +7,6 @@ import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context'; import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; import { RouteProp } from '@react-navigation/native'; import { Observable, Subscription } from 'rxjs'; -import Database from '@nozbe/watermelondb/Database'; import ActivityIndicator from '../../containers/ActivityIndicator'; import I18n from '../../i18n'; @@ -33,13 +32,12 @@ import EventEmitter from '../../utils/events'; import { LISTENER } from '../../containers/Toast'; import SearchHeader from '../../containers/SearchHeader'; import { ChatsStackParamList } from '../../stacks/types'; -import { IThreadResult, TThreadModel } from '../../definitions/IThread'; import { Filter } from './filters'; import DropdownItemHeader from './Dropdown/DropdownItemHeader'; import Dropdown from './Dropdown'; import Item from './Item'; import styles from './styles'; -import { SubscriptionType, TSubscriptionModel } from '../../definitions/ISubscription'; +import { IMessage, SubscriptionType, TSubscriptionModel, TThreadModel } from '../../definitions'; const API_FETCH_COUNT = 50; @@ -259,8 +257,8 @@ class ThreadMessagesView extends React.Component { const { subscription } = this.state; @@ -272,11 +270,9 @@ class ThreadMessagesView extends React.Component buildMessage(m)) as IThreadResult[]; + update = update.map(m => buildMessage(m)) as IMessage[]; // filter threads threadsToCreate = update.filter(i1 => !allThreadsRecords.find((i2: { id: string }) => i1._id === i2.id)); threadsToUpdate = allThreadsRecords.filter((i1: { id: string }) => update.find(i2 => i1.id === i2._id));