diff --git a/app/presentation/UserItem.tsx b/app/presentation/UserItem.tsx index a3dede48b..b2e9d0b16 100644 --- a/app/presentation/UserItem.tsx +++ b/app/presentation/UserItem.tsx @@ -46,7 +46,7 @@ interface IUserItem { testID: string; onLongPress?: () => void; style?: StyleProp; - icon?: string; + icon?: string | null; theme: string; } diff --git a/app/views/SelectedUsersView.js b/app/views/SelectedUsersView.tsx similarity index 73% rename from app/views/SelectedUsersView.js rename to app/views/SelectedUsersView.tsx index b7b254511..8d4a19fc4 100644 --- a/app/views/SelectedUsersView.js +++ b/app/views/SelectedUsersView.tsx @@ -1,9 +1,11 @@ import React from 'react'; -import PropTypes from 'prop-types'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { RouteProp } from '@react-navigation/native'; import { FlatList, View } from 'react-native'; import { connect } from 'react-redux'; import orderBy from 'lodash/orderBy'; import { Q } from '@nozbe/watermelondb'; +import { Subscription } from 'rxjs'; import * as List from '../containers/List'; import database from '../lib/database'; @@ -22,33 +24,51 @@ import { addUser as addUserAction, removeUser as removeUserAction, reset as rese import { showErrorAlert } from '../utils/info'; import SafeAreaView from '../containers/SafeAreaView'; import sharedStyles from './Styles'; +import { ChatsStackParamList } from '../stacks/types'; const ITEM_WIDTH = 250; -const getItemLayout = (_, index) => ({ length: ITEM_WIDTH, offset: ITEM_WIDTH * index, index }); +const getItemLayout = (_: any, index: number) => ({ length: ITEM_WIDTH, offset: ITEM_WIDTH * index, index }); -class SelectedUsersView extends React.Component { - static propTypes = { - baseUrl: PropTypes.string, - addUser: PropTypes.func.isRequired, - removeUser: PropTypes.func.isRequired, - reset: PropTypes.func.isRequired, - users: PropTypes.array, - loading: PropTypes.bool, - user: PropTypes.shape({ - id: PropTypes.string, - token: PropTypes.string, - username: PropTypes.string, - name: PropTypes.string - }), - navigation: PropTypes.object, - route: PropTypes.object, - theme: PropTypes.string +interface IUser { + _id: string; + name: string; + fname: string; + search?: boolean; + // username is used when is from searching + username?: string; +} +interface ISelectedUsersViewState { + maxUsers?: number; + search: IUser[]; + chats: IUser[]; +} + +interface ISelectedUsersViewProps { + navigation: StackNavigationProp; + route: RouteProp; + baseUrl: string; + addUser(user: IUser): void; + removeUser(user: IUser): void; + reset(): void; + users: IUser[]; + loading: boolean; + user: { + id: string; + token: string; + username: string; + name: string; }; + theme: string; +} - constructor(props) { +class SelectedUsersView extends React.Component { + private flatlist?: FlatList; + + private querySubscription?: Subscription; + + constructor(props: ISelectedUsersViewProps) { super(props); this.init(); - this.flatlist = React.createRef(); const maxUsers = props.route.params?.maxUsers; this.state = { maxUsers, @@ -62,7 +82,7 @@ class SelectedUsersView extends React.Component { this.setHeader(props.route.params?.showButton); } - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps: ISelectedUsersViewProps) { if (this.isGroupChat()) { const { users } = this.props; if (prevProps.users.length !== users.length) { @@ -80,7 +100,7 @@ class SelectedUsersView extends React.Component { } // showButton can be sent as route params or updated by the component - setHeader = showButton => { + setHeader = (showButton?: boolean) => { const { navigation, route } = this.props; const title = route.params?.title ?? I18n.t('Select_Users'); const buttonText = route.params?.buttonText ?? I18n.t('Next'); @@ -107,7 +127,8 @@ class SelectedUsersView extends React.Component { .query(Q.where('t', 'd')) .observeWithColumns(['room_updated_at']); - this.querySubscription = observable.subscribe(data => { + // TODO: Refactor when migrate room + this.querySubscription = observable.subscribe((data: any) => { const chats = orderBy(data, ['roomUpdatedAt'], ['desc']); this.setState({ chats }); }); @@ -116,11 +137,11 @@ class SelectedUsersView extends React.Component { } }; - onSearchChangeText(text) { + onSearchChangeText(text: string) { this.search(text); } - search = async text => { + search = async (text: string) => { const result = await RocketChat.search({ text, filterRooms: false }); this.setState({ search: result @@ -129,15 +150,15 @@ class SelectedUsersView extends React.Component { isGroupChat = () => { const { maxUsers } = this.state; - return maxUsers > 2; + return maxUsers! > 2; }; - isChecked = username => { + isChecked = (username: string) => { const { users } = this.props; return users.findIndex(el => el.name === username) !== -1; }; - toggleUser = user => { + toggleUser = (user: IUser) => { const { maxUsers } = this.state; const { addUser, @@ -163,29 +184,29 @@ class SelectedUsersView extends React.Component { } }; - _onPressItem = (id, item = {}) => { + _onPressItem = (id: string, item = {} as IUser) => { if (item.search) { - this.toggleUser({ _id: item._id, name: item.username, fname: item.name }); + this.toggleUser({ _id: item._id, name: item.username!, fname: item.name }); } else { this.toggleUser({ _id: item._id, name: item.name, fname: item.fname }); } }; - _onPressSelectedItem = item => this.toggleUser(item); + _onPressSelectedItem = (item: IUser) => this.toggleUser(item); renderHeader = () => { const { theme } = this.props; return ( - this.onSearchChangeText(text)} testID='select-users-view-search' /> + this.onSearchChangeText(text)} testID='select-users-view-search' /> {this.renderSelected()} ); }; - setFlatListRef = ref => (this.flatlist = ref); + setFlatListRef = (ref: FlatList) => (this.flatlist = ref); - onContentSizeChange = () => this.flatlist.scrollToEnd({ animated: true }); + onContentSizeChange = () => this.flatlist?.scrollToEnd({ animated: true }); renderSelected = () => { const { users, theme } = this.props; @@ -204,35 +225,32 @@ class SelectedUsersView extends React.Component { style={[sharedStyles.separatorTop, { borderColor: themes[theme].separatorColor }]} contentContainerStyle={{ marginVertical: 5 }} renderItem={this.renderSelectedItem} - enableEmptySections keyboardShouldPersistTaps='always' horizontal /> ); }; - renderSelectedItem = ({ item }) => { - const { baseUrl, user, theme } = this.props; + renderSelectedItem = ({ item }: { item: IUser }) => { + const { theme } = this.props; return ( this._onPressSelectedItem(item)} testID={`selected-user-${item.name}`} - baseUrl={baseUrl} style={{ paddingRight: 15 }} - user={user} theme={theme} /> ); }; - renderItem = ({ item, index }) => { + renderItem = ({ item, index }: { item: IUser; index: number }) => { const { search, chats } = this.state; - const { baseUrl, user, theme } = this.props; + const { theme } = this.props; const name = item.search ? item.name : item.fname; - const username = item.search ? item.username : item.name; + const username = item.search ? item.username! : item.name; let style = { borderColor: themes[theme].separatorColor }; if (index === 0) { style = { ...style, ...sharedStyles.separatorTop }; @@ -250,9 +268,7 @@ class SelectedUsersView extends React.Component { onPress={() => this._onPressItem(item._id, item)} testID={`select-users-view-item-${item.name}`} icon={this.isChecked(username) ? 'check' : null} - baseUrl={baseUrl} style={style} - user={user} theme={theme} /> ); @@ -275,7 +291,6 @@ class SelectedUsersView extends React.Component { ItemSeparatorComponent={List.Separator} ListHeaderComponent={this.renderHeader} contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} - enableEmptySections keyboardShouldPersistTaps='always' /> ); @@ -293,16 +308,16 @@ class SelectedUsersView extends React.Component { }; } -const mapStateToProps = state => ({ +const mapStateToProps = (state: any) => ({ baseUrl: state.server.server, users: state.selectedUsers.users, loading: state.selectedUsers.loading, user: getUserSelector(state) }); -const mapDispatchToProps = dispatch => ({ - addUser: user => dispatch(addUserAction(user)), - removeUser: user => dispatch(removeUserAction(user)), +const mapDispatchToProps = (dispatch: any) => ({ + addUser: (user: any) => dispatch(addUserAction(user)), + removeUser: (user: any) => dispatch(removeUserAction(user)), reset: () => dispatch(resetAction()) });