Chore: Migrate ThreadMessagesView to Typescript (#3538)
Co-authored-by: AlexAlexandre <alexalexandrejr@gmail.com>
This commit is contained in:
parent
a2b92f5e70
commit
cd9ce58660
|
@ -0,0 +1,6 @@
|
|||
export interface IMention {
|
||||
_id: string;
|
||||
name: string;
|
||||
username: string;
|
||||
type: string;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export interface IUrl {
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
url: string;
|
||||
}
|
|
@ -18,7 +18,7 @@ export type ChatsStackParamList = {
|
|||
name?: string;
|
||||
fname?: string;
|
||||
prid?: string;
|
||||
room: ISubscription;
|
||||
room?: ISubscription;
|
||||
jumpToMessageId?: string;
|
||||
jumpToThreadId?: string;
|
||||
roomUserId?: string;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import { themes } from '../../../constants/colors';
|
||||
|
@ -23,7 +22,14 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const DropdownItem = React.memo(({ theme, onPress, iconName, text }) => (
|
||||
interface IDropdownItem {
|
||||
text: string;
|
||||
iconName: string;
|
||||
theme: string;
|
||||
onPress: () => void;
|
||||
}
|
||||
|
||||
const DropdownItem = React.memo(({ theme, onPress, iconName, text }: IDropdownItem) => (
|
||||
<Touch theme={theme} onPress={onPress} style={{ backgroundColor: themes[theme].backgroundColor }}>
|
||||
<View style={styles.container}>
|
||||
<Text style={[styles.text, { color: themes[theme].auxiliaryText }]}>{text}</Text>
|
||||
|
@ -32,11 +38,4 @@ const DropdownItem = React.memo(({ theme, onPress, iconName, text }) => (
|
|||
</Touch>
|
||||
));
|
||||
|
||||
DropdownItem.propTypes = {
|
||||
text: PropTypes.string,
|
||||
iconName: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
onPress: PropTypes.func
|
||||
};
|
||||
|
||||
export default withTheme(DropdownItem);
|
|
@ -1,17 +1,16 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import I18n from '../../../i18n';
|
||||
import DropdownItem from './DropdownItem';
|
||||
|
||||
const DropdownItemFilter = ({ currentFilter, value, onPress }) => (
|
||||
interface IDropdownItemFilter {
|
||||
currentFilter: string;
|
||||
value: string;
|
||||
onPress: (value: string) => void;
|
||||
}
|
||||
|
||||
const DropdownItemFilter = ({ currentFilter, value, onPress }: IDropdownItemFilter): JSX.Element => (
|
||||
<DropdownItem text={I18n.t(value)} iconName={currentFilter === value ? 'check' : null} onPress={() => onPress(value)} />
|
||||
);
|
||||
|
||||
DropdownItemFilter.propTypes = {
|
||||
currentFilter: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
onPress: PropTypes.func
|
||||
};
|
||||
|
||||
export default DropdownItemFilter;
|
|
@ -1,17 +1,21 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { FILTER } from '../filters';
|
||||
import { Filter } from '../filters';
|
||||
import I18n from '../../../i18n';
|
||||
import DropdownItem from './DropdownItem';
|
||||
|
||||
const DropdownItemHeader = ({ currentFilter, onPress }) => {
|
||||
interface IDropdownItemHeader {
|
||||
currentFilter: Filter;
|
||||
onPress: () => void;
|
||||
}
|
||||
|
||||
const DropdownItemHeader = ({ currentFilter, onPress }: IDropdownItemHeader): JSX.Element => {
|
||||
let text;
|
||||
switch (currentFilter) {
|
||||
case FILTER.FOLLOWING:
|
||||
case Filter.Following:
|
||||
text = I18n.t('Threads_displaying_following');
|
||||
break;
|
||||
case FILTER.UNREAD:
|
||||
case Filter.Unread:
|
||||
text = I18n.t('Threads_displaying_unread');
|
||||
break;
|
||||
default:
|
||||
|
@ -21,9 +25,4 @@ const DropdownItemHeader = ({ currentFilter, onPress }) => {
|
|||
return <DropdownItem text={text} iconName='filter' onPress={onPress} />;
|
||||
};
|
||||
|
||||
DropdownItemHeader.propTypes = {
|
||||
currentFilter: PropTypes.string,
|
||||
onPress: PropTypes.func
|
||||
};
|
||||
|
||||
export default DropdownItemHeader;
|
|
@ -1,30 +1,31 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Animated, Easing, TouchableWithoutFeedback } from 'react-native';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import styles from '../styles';
|
||||
import { themes } from '../../../constants/colors';
|
||||
import { withTheme } from '../../../theme';
|
||||
import { headerHeight } from '../../../containers/Header';
|
||||
import * as List from '../../../containers/List';
|
||||
import { FILTER } from '../filters';
|
||||
import { Filter } from '../filters';
|
||||
import DropdownItemFilter from './DropdownItemFilter';
|
||||
import DropdownItemHeader from './DropdownItemHeader';
|
||||
|
||||
const ANIMATION_DURATION = 200;
|
||||
|
||||
class Dropdown extends React.Component {
|
||||
static propTypes = {
|
||||
isMasterDetail: PropTypes.bool,
|
||||
theme: PropTypes.string,
|
||||
insets: PropTypes.object,
|
||||
currentFilter: PropTypes.string,
|
||||
onClose: PropTypes.func,
|
||||
onFilterSelected: PropTypes.func
|
||||
};
|
||||
interface IDropdownProps {
|
||||
isMasterDetail: boolean;
|
||||
theme: string;
|
||||
insets: EdgeInsets;
|
||||
currentFilter: Filter;
|
||||
onClose: () => void;
|
||||
onFilterSelected: (value: string) => void;
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
class Dropdown extends React.Component<IDropdownProps> {
|
||||
private animatedValue: Animated.Value;
|
||||
|
||||
constructor(props: IDropdownProps) {
|
||||
super(props);
|
||||
this.animatedValue = new Animated.Value(0);
|
||||
}
|
||||
|
@ -85,9 +86,9 @@ class Dropdown extends React.Component {
|
|||
]}>
|
||||
<DropdownItemHeader currentFilter={currentFilter} onPress={this.close} />
|
||||
<List.Separator />
|
||||
<DropdownItemFilter currentFilter={currentFilter} value={FILTER.ALL} onPress={onFilterSelected} />
|
||||
<DropdownItemFilter currentFilter={currentFilter} value={FILTER.FOLLOWING} onPress={onFilterSelected} />
|
||||
<DropdownItemFilter currentFilter={currentFilter} value={FILTER.UNREAD} onPress={onFilterSelected} />
|
||||
<DropdownItemFilter currentFilter={currentFilter} value={Filter.All} onPress={onFilterSelected} />
|
||||
<DropdownItemFilter currentFilter={currentFilter} value={Filter.Following} onPress={onFilterSelected} />
|
||||
<DropdownItemFilter currentFilter={currentFilter} value={Filter.Unread} onPress={onFilterSelected} />
|
||||
</Animated.View>
|
||||
</>
|
||||
);
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
|
||||
|
@ -10,6 +9,7 @@ import { themes } from '../../constants/colors';
|
|||
import Markdown from '../../containers/markdown';
|
||||
import { formatDateThreads, makeThreadName } from '../../utils/room';
|
||||
import ThreadDetails from '../../containers/ThreadDetails';
|
||||
import { TThreadModel } from '../../definitions/IThread';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -56,7 +56,18 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, toggleFollowThread }) => {
|
||||
interface IItem {
|
||||
item: TThreadModel;
|
||||
baseUrl: string;
|
||||
theme: string;
|
||||
useRealName: boolean;
|
||||
user: any;
|
||||
badgeColor: string;
|
||||
onPress: (item: TThreadModel) => void;
|
||||
toggleFollowThread: (isFollowing: boolean, id: string) => void;
|
||||
}
|
||||
|
||||
const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, toggleFollowThread }: IItem) => {
|
||||
const username = (useRealName && item?.u?.name) || item?.u?.username;
|
||||
let time;
|
||||
if (item?.ts) {
|
||||
|
@ -69,16 +80,7 @@ const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, to
|
|||
testID={`thread-messages-view-${item.msg}`}
|
||||
style={{ backgroundColor: themes[theme].backgroundColor }}>
|
||||
<View style={styles.container}>
|
||||
<Avatar
|
||||
style={styles.avatar}
|
||||
text={item?.u?.username}
|
||||
size={36}
|
||||
borderRadius={4}
|
||||
baseUrl={baseUrl}
|
||||
userId={user?.id}
|
||||
token={user?.token}
|
||||
theme={theme}
|
||||
/>
|
||||
<Avatar style={styles.avatar} text={item?.u?.username} size={36} borderRadius={4} theme={theme} />
|
||||
<View style={styles.contentContainer}>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text style={[styles.title, { color: themes[theme].titleText }]} numberOfLines={1}>
|
||||
|
@ -87,10 +89,11 @@ const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, to
|
|||
<Text style={[styles.time, { color: themes[theme].auxiliaryText }]}>{time}</Text>
|
||||
</View>
|
||||
<View style={styles.messageContainer}>
|
||||
{/* @ts-ignore */}
|
||||
<Markdown
|
||||
msg={makeThreadName(item)}
|
||||
baseUrl={baseUrl}
|
||||
username={username}
|
||||
username={username!}
|
||||
theme={theme}
|
||||
numberOfLines={2}
|
||||
style={[styles.markdown]}
|
||||
|
@ -105,15 +108,4 @@ const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, to
|
|||
);
|
||||
};
|
||||
|
||||
Item.propTypes = {
|
||||
item: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
useRealName: PropTypes.bool,
|
||||
user: PropTypes.object,
|
||||
badgeColor: PropTypes.string,
|
||||
onPress: PropTypes.func,
|
||||
toggleFollowThread: PropTypes.func
|
||||
};
|
||||
|
||||
export default withTheme(Item);
|
|
@ -1,5 +0,0 @@
|
|||
export const FILTER = {
|
||||
ALL: 'All',
|
||||
FOLLOWING: 'Following',
|
||||
UNREAD: 'Unread'
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
export enum Filter {
|
||||
All = 'All',
|
||||
Following = 'Following',
|
||||
Unread = 'Unread'
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FlatList } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { HeaderBackButton } from '@react-navigation/stack';
|
||||
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 Model from '@nozbe/watermelondb/Model';
|
||||
import Database from '@nozbe/watermelondb/Database';
|
||||
|
||||
import ActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import I18n from '../../i18n';
|
||||
|
@ -30,27 +33,62 @@ import { getHeaderTitlePosition } from '../../containers/Header';
|
|||
import EventEmitter from '../../utils/events';
|
||||
import { LISTENER } from '../../containers/Toast';
|
||||
import SearchHeader from '../../containers/SearchHeader';
|
||||
import { FILTER } from './filters';
|
||||
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';
|
||||
|
||||
const API_FETCH_COUNT = 50;
|
||||
|
||||
class ThreadMessagesView extends React.Component {
|
||||
static propTypes = {
|
||||
user: PropTypes.object,
|
||||
navigation: PropTypes.object,
|
||||
route: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
useRealName: PropTypes.bool,
|
||||
theme: PropTypes.string,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
insets: PropTypes.object
|
||||
};
|
||||
interface IResultFetch {
|
||||
threads: IThreadResult[];
|
||||
count: number;
|
||||
offset: number;
|
||||
total: number;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
interface IThreadMessagesViewState {
|
||||
loading: boolean;
|
||||
end: boolean;
|
||||
messages: any[];
|
||||
displayingThreads: TThreadModel[];
|
||||
subscription: TSubscriptionModel;
|
||||
showFilterDropdown: boolean;
|
||||
currentFilter: Filter;
|
||||
isSearching: boolean;
|
||||
searchText: string;
|
||||
}
|
||||
|
||||
interface IThreadMessagesViewProps {
|
||||
navigation: StackNavigationProp<ChatsStackParamList, 'ThreadMessagesView'>;
|
||||
route: RouteProp<ChatsStackParamList, 'ThreadMessagesView'>;
|
||||
user: any;
|
||||
baseUrl: string;
|
||||
useRealName: boolean;
|
||||
theme: string;
|
||||
isMasterDetail: boolean;
|
||||
insets: EdgeInsets;
|
||||
}
|
||||
|
||||
class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThreadMessagesViewState> {
|
||||
private mounted: boolean;
|
||||
|
||||
private rid: string;
|
||||
|
||||
private t: string;
|
||||
|
||||
private subSubscription: any;
|
||||
|
||||
private messagesSubscription?: Subscription;
|
||||
|
||||
private messagesObservable!: Observable<Model>;
|
||||
|
||||
constructor(props: IThreadMessagesViewProps) {
|
||||
super(props);
|
||||
this.mounted = false;
|
||||
this.rid = props.route.params?.rid;
|
||||
|
@ -60,9 +98,9 @@ class ThreadMessagesView extends React.Component {
|
|||
end: false,
|
||||
messages: [],
|
||||
displayingThreads: [],
|
||||
subscription: {},
|
||||
subscription: {} as TSubscriptionModel,
|
||||
showFilterDropdown: false,
|
||||
currentFilter: FILTER.ALL,
|
||||
currentFilter: Filter.All,
|
||||
isSearching: false,
|
||||
searchText: ''
|
||||
};
|
||||
|
@ -76,7 +114,7 @@ class ThreadMessagesView extends React.Component {
|
|||
this.init();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps: IThreadMessagesViewProps) {
|
||||
const { insets } = this.props;
|
||||
if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) {
|
||||
this.setHeader();
|
||||
|
@ -93,7 +131,7 @@ class ThreadMessagesView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
getHeader = () => {
|
||||
getHeader = (): StackNavigationOptions => {
|
||||
const { isSearching } = this.state;
|
||||
const { navigation, isMasterDetail, insets, theme } = this.props;
|
||||
|
||||
|
@ -115,7 +153,7 @@ class ThreadMessagesView extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
const options = {
|
||||
const options: StackNavigationOptions = {
|
||||
headerLeft: () => (
|
||||
<HeaderBackButton labelVisible={false} onPress={() => navigation.pop()} tintColor={themes[theme].headerTintColor} />
|
||||
),
|
||||
|
@ -150,7 +188,7 @@ class ThreadMessagesView extends React.Component {
|
|||
const db = database.active;
|
||||
|
||||
// subscription query
|
||||
const subscription = await db.collections.get('subscriptions').find(this.rid);
|
||||
const subscription = (await db.collections.get('subscriptions').find(this.rid)) as TSubscriptionModel;
|
||||
const observable = subscription.observe();
|
||||
this.subSubscription = observable.subscribe(data => {
|
||||
this.setState({ subscription: data });
|
||||
|
@ -162,7 +200,7 @@ class ThreadMessagesView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
subscribeMessages = (subscription, searchText) => {
|
||||
subscribeMessages = (subscription?: TSubscriptionModel, searchText?: string) => {
|
||||
try {
|
||||
const db = database.active;
|
||||
|
||||
|
@ -180,13 +218,17 @@ class ThreadMessagesView extends React.Component {
|
|||
.get('threads')
|
||||
.query(...whereClause)
|
||||
.observeWithColumns(['updated_at']);
|
||||
this.messagesSubscription = this.messagesObservable.subscribe(messages => {
|
||||
|
||||
// TODO: Refactor when migrate messages
|
||||
this.messagesSubscription = this.messagesObservable.subscribe((messages: any) => {
|
||||
const { currentFilter } = this.state;
|
||||
const displayingThreads = this.getFilteredThreads(messages, subscription, currentFilter);
|
||||
const displayingThreads = this.getFilteredThreads(messages, subscription!, currentFilter);
|
||||
if (this.mounted) {
|
||||
this.setState({ messages, displayingThreads });
|
||||
} else {
|
||||
// @ts-ignore
|
||||
this.state.messages = messages;
|
||||
// @ts-ignore
|
||||
this.state.displayingThreads = displayingThreads;
|
||||
}
|
||||
});
|
||||
|
@ -212,7 +254,15 @@ class ThreadMessagesView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
updateThreads = async ({ update, remove, lastThreadSync }) => {
|
||||
updateThreads = async ({
|
||||
update,
|
||||
remove,
|
||||
lastThreadSync
|
||||
}: {
|
||||
update: IThreadResult[];
|
||||
remove?: IThreadResult[];
|
||||
lastThreadSync: Date;
|
||||
}) => {
|
||||
const { subscription } = this.state;
|
||||
// if there's no subscription, manage data on this.state.messages
|
||||
// note: sync will never be called without subscription
|
||||
|
@ -222,21 +272,23 @@ class ThreadMessagesView extends React.Component {
|
|||
}
|
||||
|
||||
try {
|
||||
const db = database.active;
|
||||
const db: Database = database.active;
|
||||
const threadsCollection = db.get('threads');
|
||||
const allThreadsRecords = await subscription.threads.fetch();
|
||||
let threadsToCreate = [];
|
||||
let threadsToUpdate = [];
|
||||
let threadsToDelete = [];
|
||||
// TODO: Refactor when migrate room
|
||||
// @ts-ignore
|
||||
const allThreadsRecords = (await subscription.threads.fetch()) as TThreadModel[];
|
||||
let threadsToCreate: any[] = [];
|
||||
let threadsToUpdate: any[] = [];
|
||||
let threadsToDelete: any[] = [];
|
||||
|
||||
if (update && update.length) {
|
||||
update = update.map(m => buildMessage(m));
|
||||
// filter threads
|
||||
threadsToCreate = update.filter(i1 => !allThreadsRecords.find(i2 => i1._id === i2.id));
|
||||
threadsToUpdate = allThreadsRecords.filter(i1 => update.find(i2 => 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));
|
||||
threadsToCreate = threadsToCreate.map(thread =>
|
||||
threadsCollection.prepareCreate(
|
||||
protectedFunction(t => {
|
||||
protectedFunction((t: any) => {
|
||||
t._raw = sanitizedRaw({ id: thread._id }, threadsCollection.schema);
|
||||
t.subscription.set(subscription);
|
||||
Object.assign(t, thread);
|
||||
|
@ -246,7 +298,7 @@ class ThreadMessagesView extends React.Component {
|
|||
threadsToUpdate = threadsToUpdate.map(thread => {
|
||||
const newThread = update.find(t => t._id === thread.id);
|
||||
return thread.prepareUpdate(
|
||||
protectedFunction(t => {
|
||||
protectedFunction((t: any) => {
|
||||
Object.assign(t, newThread);
|
||||
})
|
||||
);
|
||||
|
@ -254,16 +306,16 @@ class ThreadMessagesView extends React.Component {
|
|||
}
|
||||
|
||||
if (remove && remove.length) {
|
||||
threadsToDelete = allThreadsRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
|
||||
threadsToDelete = allThreadsRecords.filter((i1: { id: string }) => remove.find(i2 => i1.id === i2._id));
|
||||
threadsToDelete = threadsToDelete.map(t => t.prepareDestroyPermanently());
|
||||
}
|
||||
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await db.batch(
|
||||
...threadsToCreate,
|
||||
...threadsToUpdate,
|
||||
...threadsToDelete,
|
||||
subscription.prepareUpdate(s => {
|
||||
subscription.prepareUpdate((s: any) => {
|
||||
s.lastThreadSync = lastThreadSync;
|
||||
})
|
||||
);
|
||||
|
@ -274,7 +326,7 @@ class ThreadMessagesView extends React.Component {
|
|||
};
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
load = debounce(async lastThreadSync => {
|
||||
load = debounce(async (lastThreadSync: Date) => {
|
||||
const { loading, end, messages, searchText } = this.state;
|
||||
if (end || loading || !this.mounted) {
|
||||
return;
|
||||
|
@ -283,7 +335,7 @@ class ThreadMessagesView extends React.Component {
|
|||
this.setState({ loading: true });
|
||||
|
||||
try {
|
||||
const result = await RocketChat.getThreadsList({
|
||||
const result: IResultFetch = await RocketChat.getThreadsList({
|
||||
rid: this.rid,
|
||||
count: API_FETCH_COUNT,
|
||||
offset: messages.length,
|
||||
|
@ -303,7 +355,7 @@ class ThreadMessagesView extends React.Component {
|
|||
}, 300);
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
sync = async updatedSince => {
|
||||
sync = async (updatedSince: Date) => {
|
||||
this.setState({ loading: true });
|
||||
|
||||
try {
|
||||
|
@ -336,13 +388,13 @@ class ThreadMessagesView extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
onSearchChangeText = debounce(searchText => {
|
||||
onSearchChangeText = debounce((searchText: string) => {
|
||||
const { subscription } = this.state;
|
||||
this.setState({ searchText }, () => this.subscribeMessages(subscription, searchText));
|
||||
}, 300);
|
||||
|
||||
onThreadPress = debounce(
|
||||
item => {
|
||||
(item: any) => {
|
||||
const { subscription } = this.state;
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
if (isMasterDetail) {
|
||||
|
@ -352,7 +404,7 @@ class ThreadMessagesView extends React.Component {
|
|||
rid: item.subscription.id,
|
||||
tmid: item.id,
|
||||
name: makeThreadName(item),
|
||||
t: 'thread',
|
||||
t: SubscriptionType.THREAD,
|
||||
roomUserId: RocketChat.getUidDirectMessage(subscription)
|
||||
});
|
||||
},
|
||||
|
@ -360,20 +412,21 @@ class ThreadMessagesView extends React.Component {
|
|||
true
|
||||
);
|
||||
|
||||
getBadgeColor = item => {
|
||||
getBadgeColor = (item: TThreadModel) => {
|
||||
const { subscription } = this.state;
|
||||
const { theme } = this.props;
|
||||
return getBadgeColor({ subscription, theme, messageId: item?.id });
|
||||
};
|
||||
|
||||
// helper to query threads
|
||||
getFilteredThreads = (messages, subscription, currentFilter) => {
|
||||
getFilteredThreads = (messages: any, subscription: TSubscriptionModel, currentFilter?: Filter): TThreadModel[] => {
|
||||
// const { currentFilter } = this.state;
|
||||
const { user } = this.props;
|
||||
if (currentFilter === FILTER.FOLLOWING) {
|
||||
return messages?.filter(item => item?.replies?.find(u => u === user.id));
|
||||
} else if (currentFilter === FILTER.UNREAD) {
|
||||
return messages?.filter(item => subscription?.tunread?.includes(item?.id));
|
||||
if (currentFilter === Filter.Following) {
|
||||
return messages?.filter((item: { replies: any[] }) => item?.replies?.find(u => u === user.id));
|
||||
}
|
||||
if (currentFilter === Filter.Unread) {
|
||||
return messages?.filter((item: { id: string }) => subscription?.tunread?.includes(item?.id));
|
||||
}
|
||||
return messages;
|
||||
};
|
||||
|
@ -389,13 +442,13 @@ class ThreadMessagesView extends React.Component {
|
|||
|
||||
closeFilterDropdown = () => this.setState({ showFilterDropdown: false });
|
||||
|
||||
onFilterSelected = filter => {
|
||||
onFilterSelected = (filter: Filter) => {
|
||||
const { messages, subscription } = this.state;
|
||||
const displayingThreads = this.getFilteredThreads(messages, subscription, filter);
|
||||
this.setState({ currentFilter: filter, displayingThreads });
|
||||
};
|
||||
|
||||
toggleFollowThread = async (isFollowingThread, tmid) => {
|
||||
toggleFollowThread = async (isFollowingThread: boolean, tmid: string) => {
|
||||
try {
|
||||
await RocketChat.toggleFollowMessage(tmid, !isFollowingThread);
|
||||
EventEmitter.emit(LISTENER, { message: isFollowingThread ? I18n.t('Unfollowed_thread') : I18n.t('Following_thread') });
|
||||
|
@ -404,7 +457,7 @@ class ThreadMessagesView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem = ({ item }: { item: TThreadModel }) => {
|
||||
const { user, navigation, baseUrl, useRealName } = this.props;
|
||||
const badgeColor = this.getBadgeColor(item);
|
||||
return (
|
||||
|
@ -442,9 +495,9 @@ class ThreadMessagesView extends React.Component {
|
|||
const { theme } = this.props;
|
||||
if (!messages?.length || !displayingThreads?.length) {
|
||||
let text;
|
||||
if (currentFilter === FILTER.FOLLOWING) {
|
||||
if (currentFilter === Filter.Following) {
|
||||
text = I18n.t('No_threads_following');
|
||||
} else if (currentFilter === FILTER.UNREAD) {
|
||||
} else if (currentFilter === Filter.Unread) {
|
||||
text = I18n.t('No_threads_unread');
|
||||
} else {
|
||||
text = I18n.t('No_threads');
|
||||
|
@ -494,7 +547,7 @@ class ThreadMessagesView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
baseUrl: state.server.server,
|
||||
user: getUserSelector(state),
|
||||
useRealName: state.settings.UI_Use_Real_Name,
|
|
@ -25,6 +25,6 @@ export default StyleSheet.create({
|
|||
borderBottomWidth: StyleSheet.hairlineWidth
|
||||
},
|
||||
backdrop: {
|
||||
...StyleSheet.absoluteFill
|
||||
...StyleSheet.absoluteFillObject
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue