Chore: Migrate methods/loadSurroundingMessages to Typescript (#3733)

* Chore: Migrate methods/loadSurroundingMessages to Typescript

* tweaks

* tweak

* tweak

* tweaks to make ts happy

* instead as IMessage is optional u

* enum to MessageTypeLoad

* minor tweaks
This commit is contained in:
Reinaldo Neto 2022-03-03 17:25:03 -03:00 committed by GitHub
parent 16fd64b260
commit b06be5a2ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 69 additions and 78 deletions

View File

@ -1,5 +1,7 @@
export const MESSAGE_TYPE_LOAD_MORE = 'load_more'; export enum MessageTypeLoad {
export const MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK = 'load_previous_chunk'; MORE = 'load_more',
export const MESSAGE_TYPE_LOAD_NEXT_CHUNK = 'load_next_chunk'; 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];

View File

@ -926,8 +926,8 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
let msg = `[ ](${permalink}) `; let msg = `[ ](${permalink}) `;
// if original message wasn't sent by current user and neither from a direct room // if original message wasn't sent by current user and neither from a direct room
if (user.username !== replyingMessage.u.username && roomType !== 'd' && replyWithMention) { if (user.username !== replyingMessage?.u?.username && roomType !== 'd' && replyWithMention) {
msg += `@${replyingMessage.u.username} `; msg += `@${replyingMessage?.u?.username} `;
} }
msg = `${msg} ${message}`; msg = `${msg} ${message}`;

View File

@ -1,27 +1,14 @@
import Model from '@nozbe/watermelondb/Model'; import Model from '@nozbe/watermelondb/Model';
import { MarkdownAST } from '@rocket.chat/message-parser'; import { MarkdownAST } from '@rocket.chat/message-parser';
import { MessageTypeLoad } from '../constants/messageTypeLoad';
import { IAttachment } from './IAttachment'; import { IAttachment } from './IAttachment';
import { IReaction } from './IReaction'; 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 { TThreadMessageModel } from './IThreadMessage';
import { TThreadModel } from './IThread'; import { TThreadModel } from './IThread';
import { IUrlFromServer } from './IUrl'; import { IUrlFromServer } from './IUrl';
export type MessageType = export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj' | MessageTypeLoad;
| '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 interface IUserMessage { export interface IUserMessage {
_id: string; _id: string;

View File

@ -30,6 +30,8 @@ export enum ERoomTypes {
CHANNEL = 'channel' CHANNEL = 'channel'
} }
type RelationModified<T extends Model> = { fetch(): Promise<T[]> } & Relation<T>;
export interface ISubscription { export interface ISubscription {
_id: string; // _id belongs watermelonDB _id: string; // _id belongs watermelonDB
id: string; // id from server id: string; // id from server
@ -93,10 +95,10 @@ export interface ISubscription {
teamMain?: boolean; teamMain?: boolean;
separator?: boolean; separator?: boolean;
// https://nozbe.github.io/WatermelonDB/Relation.html#relation-api // https://nozbe.github.io/WatermelonDB/Relation.html#relation-api
messages: Relation<TMessageModel>; messages: RelationModified<TMessageModel>;
threads: Relation<TThreadModel>; threads: RelationModified<TThreadModel>;
threadMessages: Relation<TThreadMessageModel>; threadMessages: RelationModified<TThreadMessageModel>;
uploads: Relation<TUploadModel>; uploads: RelationModified<TUploadModel>;
} }
export type TSubscriptionModel = ISubscription & Model; export type TSubscriptionModel = ISubscription & Model;

View File

@ -1,6 +1,7 @@
import moment from 'moment'; 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 log from '../../utils/log';
import { getMessageById } from '../database/services/Message'; import { getMessageById } from '../database/services/Message';
import roomTypeToApiType, { RoomTypes } from '../rocketchat/methods/roomTypeToApiType'; import roomTypeToApiType, { RoomTypes } from '../rocketchat/methods/roomTypeToApiType';
@ -46,7 +47,7 @@ export default function loadMessagesForRoom(args: {
_id: generateLoadMoreId(lastMessage._id as string), _id: generateLoadMoreId(lastMessage._id as string),
rid: lastMessage.rid, rid: lastMessage.rid,
ts: moment(lastMessage.ts).subtract(1, 'millisecond').toString(), ts: moment(lastMessage.ts).subtract(1, 'millisecond').toString(),
t: 'load_more' as MessageType, t: MessageTypeLoad.MORE,
msg: lastMessage.msg msg: lastMessage.msg
}; };
data.push(loadMoreMessage); data.push(loadMoreMessage);

View File

@ -4,7 +4,7 @@ import orderBy from 'lodash/orderBy';
import log from '../../utils/log'; import log from '../../utils/log';
import { getMessageById } from '../database/services/Message'; 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 { generateLoadMoreId } from '../utils';
import updateMessages from './updateMessages'; import updateMessages from './updateMessages';
import { TMessageModel } from '../../definitions'; import { TMessageModel } from '../../definitions';
@ -34,7 +34,7 @@ export default function loadNextMessages(args: ILoadNextMessages): Promise<void>
rid: lastMessage.rid, rid: lastMessage.rid,
tmid: args.tmid, tmid: args.tmid,
ts: moment(lastMessage.ts).add(1, 'millisecond'), ts: moment(lastMessage.ts).add(1, 'millisecond'),
t: MESSAGE_TYPE_LOAD_NEXT_CHUNK t: MessageTypeLoad.NEXT_CHUNK
}; };
messages.push(loadMoreItem); messages.push(loadMoreItem);
} }

View File

@ -4,21 +4,23 @@ import orderBy from 'lodash/orderBy';
import log from '../../utils/log'; import log from '../../utils/log';
import { getMessageById } from '../database/services/Message'; 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 { generateLoadMoreId } from '../utils';
import updateMessages from './updateMessages'; import updateMessages from './updateMessages';
const COUNT = 50; 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) => { return new Promise(async (resolve, reject) => {
try { try {
const data = await this.methodCallWrapper('loadSurroundingMessages', { _id: messageId, rid }, COUNT); const data = await sdk.methodCallWrapper('loadSurroundingMessages', { _id: messageId, rid }, COUNT);
let messages = EJSON.fromJSONValue(data?.messages); let messages: IMessage[] = EJSON.fromJSONValue(data?.messages);
messages = orderBy(messages, 'ts'); messages = orderBy(messages, 'ts');
const message = messages.find(m => m._id === messageId); const message = messages.find(m => m._id === messageId);
const { tmid } = message; const tmid = message?.tmid;
if (messages?.length) { if (messages?.length) {
if (data?.moreBefore) { if (data?.moreBefore) {
@ -29,10 +31,10 @@ export default function loadSurroundingMessages({ messageId, rid }) {
_id: generateLoadMoreId(firstMessage._id), _id: generateLoadMoreId(firstMessage._id),
rid: firstMessage.rid, rid: firstMessage.rid,
tmid, tmid,
ts: moment(firstMessage.ts).subtract(1, 'millisecond'), ts: moment(firstMessage.ts).subtract(1, 'millisecond').toDate(),
t: MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK, t: MessageTypeLoad.PREVIOUS_CHUNK,
msg: firstMessage.msg msg: firstMessage.msg
}; } as IMessage;
messages.unshift(loadMoreItem); messages.unshift(loadMoreItem);
} }
} }
@ -45,18 +47,18 @@ export default function loadSurroundingMessages({ messageId, rid }) {
_id: generateLoadMoreId(lastMessage._id), _id: generateLoadMoreId(lastMessage._id),
rid: lastMessage.rid, rid: lastMessage.rid,
tmid, tmid,
ts: moment(lastMessage.ts).add(1, 'millisecond'), ts: moment(lastMessage.ts).add(1, 'millisecond').toDate(),
t: MESSAGE_TYPE_LOAD_NEXT_CHUNK, t: MessageTypeLoad.NEXT_CHUNK,
msg: lastMessage.msg msg: lastMessage.msg
}; } as IMessage;
messages.push(loadMoreItem); messages.push(loadMoreItem);
} }
} }
await updateMessages({ rid, update: messages }); await updateMessages({ rid, update: messages });
return resolve(messages); return resolve(messages);
} else {
return resolve([]);
} }
return resolve([]);
} catch (e) { } catch (e) {
log(e); log(e);
reject(e); reject(e);

View File

@ -7,11 +7,7 @@ import { longText } from '../../../../storybook/utils';
import { ThemeContext } from '../../../theme'; import { ThemeContext } from '../../../theme';
import { Message, MessageDecorator, StoryProvider } from '../../../../storybook/stories/Message'; import { Message, MessageDecorator, StoryProvider } from '../../../../storybook/stories/Message';
import { themes } from '../../../constants/colors'; import { themes } from '../../../constants/colors';
import { import { MessageTypeLoad } from '../../../constants/messageTypeLoad';
MESSAGE_TYPE_LOAD_MORE,
MESSAGE_TYPE_LOAD_NEXT_CHUNK,
MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK
} from '../../../constants/messageTypeLoad';
import LoadMore from './index'; import LoadMore from './index';
const stories = storiesOf('LoadMore', module); const stories = storiesOf('LoadMore', module);
@ -23,20 +19,20 @@ stories.add('basic', () => (
<> <>
<LoadMore load={load} /> <LoadMore load={load} />
<LoadMore load={load} runOnRender /> <LoadMore load={load} runOnRender />
<LoadMore load={load} type={MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK} /> <LoadMore load={load} type={MessageTypeLoad.PREVIOUS_CHUNK} />
<LoadMore load={load} type={MESSAGE_TYPE_LOAD_NEXT_CHUNK} /> <LoadMore load={load} type={MessageTypeLoad.NEXT_CHUNK} />
</> </>
)); ));
const ThemeStory = ({ theme }) => ( const ThemeStory = ({ theme }) => (
<ThemeContext.Provider value={{ theme }}> <ThemeContext.Provider value={{ theme }}>
<ScrollView style={{ backgroundColor: themes[theme].backgroundColor }}> <ScrollView style={{ backgroundColor: themes[theme].backgroundColor }}>
<LoadMore load={load} type={MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK} /> <LoadMore load={load} type={MessageTypeLoad.PREVIOUS_CHUNK} />
<Message msg='Hey!' theme={theme} /> <Message msg='Hey!' theme={theme} />
<Message msg={longText} theme={theme} isHeader={false} /> <Message msg={longText} theme={theme} isHeader={false} />
<Message msg='Older message' theme={theme} isHeader={false} /> <Message msg='Older message' theme={theme} isHeader={false} />
<LoadMore load={load} type={MESSAGE_TYPE_LOAD_NEXT_CHUNK} /> <LoadMore load={load} type={MessageTypeLoad.NEXT_CHUNK} />
<LoadMore load={load} type={MESSAGE_TYPE_LOAD_MORE} /> <LoadMore load={load} type={MessageTypeLoad.MORE} />
<Message msg={longText} theme={theme} /> <Message msg={longText} theme={theme} />
<Message msg='This is the third message' isHeader={false} theme={theme} /> <Message msg='This is the third message' isHeader={false} theme={theme} />
<Message msg='This is the second message' isHeader={false} theme={theme} /> <Message msg='This is the second message' isHeader={false} theme={theme} />

View File

@ -2,7 +2,8 @@ import React, { useCallback, useEffect, useState } from 'react';
import { ActivityIndicator, StyleSheet, Text } from 'react-native'; import { ActivityIndicator, StyleSheet, Text } from 'react-native';
import { themes } from '../../../constants/colors'; 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 { useTheme } from '../../../theme';
import Touch from '../../../utils/touch'; import Touch from '../../../utils/touch';
import sharedStyles from '../../Styles'; 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 { theme } = useTheme();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -43,10 +52,10 @@ const LoadMore = ({ load, type, runOnRender }: { load: Function; type: string; r
}, []); }, []);
let text = 'Load_More'; let text = 'Load_More';
if (type === MESSAGE_TYPE_LOAD_NEXT_CHUNK) { if (type === MessageTypeLoad.NEXT_CHUNK) {
text = 'Load_Newer'; text = 'Load_Newer';
} }
if (type === MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK) { if (type === MessageTypeLoad.PREVIOUS_CHUNK) {
text = 'Load_Older'; text = 'Load_Older';
} }

View File

@ -24,7 +24,7 @@ import I18n from '../../i18n';
import RoomHeader from '../../containers/RoomHeader'; import RoomHeader from '../../containers/RoomHeader';
import StatusBar from '../../containers/StatusBar'; import StatusBar from '../../containers/StatusBar';
import { themes } from '../../constants/colors'; 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 debounce from '../../utils/debounce';
import ReactionsModal from '../../containers/ReactionsModal'; import ReactionsModal from '../../containers/ReactionsModal';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
@ -851,7 +851,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
* if it's from server, we don't have it saved locally and so we fetch surroundings * 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` * 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 }); await RocketChat.loadSurroundingMessages({ messageId, rid: this.rid });
} }
// @ts-ignore // @ts-ignore
@ -1161,12 +1161,12 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
} }
let content = null; 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 = ( content = (
<LoadMore <LoadMore
load={() => this.onLoadMoreMessages(item)} load={() => this.onLoadMoreMessages(item)}
type={item.t} type={item.t}
runOnRender={item.t === MESSAGE_TYPE_LOAD_MORE && !previousItem} runOnRender={item.t === MessageTypeLoad.MORE && !previousItem}
/> />
); );
} else { } else {

View File

@ -1,11 +1,7 @@
import { MessageType, SubscriptionType, TAnyMessageModel } from '../../../definitions'; import { SubscriptionType, TAnyMessageModel } from '../../../definitions';
import loadMessagesForRoom from '../../../lib/methods/loadMessagesForRoom'; import loadMessagesForRoom from '../../../lib/methods/loadMessagesForRoom';
import loadNextMessages from '../../../lib/methods/loadNextMessages'; import loadNextMessages from '../../../lib/methods/loadNextMessages';
import { import { MessageTypeLoad } from '../../../constants/messageTypeLoad';
MESSAGE_TYPE_LOAD_MORE,
MESSAGE_TYPE_LOAD_NEXT_CHUNK,
MESSAGE_TYPE_LOAD_PREVIOUS_CHUNK
} from '../../../constants/messageTypeLoad';
const getMoreMessages = ({ const getMoreMessages = ({
rid, rid,
@ -18,7 +14,7 @@ const getMoreMessages = ({
tmid?: string; tmid?: string;
loaderItem: TAnyMessageModel; loaderItem: TAnyMessageModel;
}): Promise<void> => { }): Promise<void> => {
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({ return loadMessagesForRoom({
rid, rid,
t: t as any, 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({ return loadNextMessages({
rid, rid,
tmid, tmid,

View File

@ -7,7 +7,6 @@ import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
import { RouteProp } from '@react-navigation/native'; import { RouteProp } from '@react-navigation/native';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
import Database from '@nozbe/watermelondb/Database';
import ActivityIndicator from '../../containers/ActivityIndicator'; import ActivityIndicator from '../../containers/ActivityIndicator';
import I18n from '../../i18n'; import I18n from '../../i18n';
@ -33,13 +32,12 @@ import EventEmitter from '../../utils/events';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
import SearchHeader from '../../containers/SearchHeader'; import SearchHeader from '../../containers/SearchHeader';
import { ChatsStackParamList } from '../../stacks/types'; import { ChatsStackParamList } from '../../stacks/types';
import { IThreadResult, TThreadModel } from '../../definitions/IThread';
import { Filter } from './filters'; import { Filter } from './filters';
import DropdownItemHeader from './Dropdown/DropdownItemHeader'; import DropdownItemHeader from './Dropdown/DropdownItemHeader';
import Dropdown from './Dropdown'; import Dropdown from './Dropdown';
import Item from './Item'; import Item from './Item';
import styles from './styles'; import styles from './styles';
import { SubscriptionType, TSubscriptionModel } from '../../definitions/ISubscription'; import { IMessage, SubscriptionType, TSubscriptionModel, TThreadModel } from '../../definitions';
const API_FETCH_COUNT = 50; const API_FETCH_COUNT = 50;
@ -259,8 +257,8 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
remove, remove,
lastThreadSync lastThreadSync
}: { }: {
update: IThreadResult[]; update: IMessage[];
remove?: IThreadResult[]; remove?: IMessage[];
lastThreadSync: Date; lastThreadSync: Date;
}) => { }) => {
const { subscription } = this.state; const { subscription } = this.state;
@ -272,11 +270,9 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
} }
try { try {
const db: Database = database.active; const db = database.active;
const threadsCollection = db.get('threads'); const threadsCollection = db.get('threads');
// TODO: Refactor when migrate room const allThreadsRecords = await subscription.threads.fetch();
// @ts-ignore
const allThreadsRecords = (await subscription.threads.fetch()) as TThreadModel[];
let threadsToCreate: any[] = []; let threadsToCreate: any[] = [];
let threadsToUpdate: any[] = []; let threadsToUpdate: any[] = [];
let threadsToDelete: any[] = []; let threadsToDelete: any[] = [];
@ -287,7 +283,7 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
} }
if (update && update.length) { if (update && update.length) {
update = update.map(m => buildMessage(m)) as IThreadResult[]; update = update.map(m => buildMessage(m)) as IMessage[];
// filter threads // filter threads
threadsToCreate = update.filter(i1 => !allThreadsRecords.find((i2: { id: string }) => i1._id === i2.id)); 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)); threadsToUpdate = allThreadsRecords.filter((i1: { id: string }) => update.find(i2 => i1.id === i2._id));