import React from 'react'; import PropTypes from 'prop-types'; import { FlatList, View, Text } from 'react-native'; import { connect } from 'react-redux'; import { SafeAreaView } from 'react-navigation'; import equal from 'deep-equal'; import ActionSheet from 'react-native-action-sheet'; import styles from './styles'; import Message from '../../containers/message/Message'; import RCActivityIndicator from '../../containers/ActivityIndicator'; import I18n from '../../i18n'; import RocketChat from '../../lib/rocketchat'; import StatusBar from '../../containers/StatusBar'; import getFileUrlFromMessage from '../../lib/methods/helpers/getFileUrlFromMessage'; import FileModal from '../../containers/FileModal'; const ACTION_INDEX = 0; const CANCEL_INDEX = 1; class MessagesView extends React.Component { static navigationOptions = ({ navigation }) => ({ title: navigation.state.params.name }); static propTypes = { user: PropTypes.object, baseUrl: PropTypes.string, navigation: PropTypes.object, customEmojis: PropTypes.object } constructor(props) { super(props); this.state = { loading: false, messages: [], selectedAttachment: {}, photoModalVisible: false, fileLoading: true }; this.rid = props.navigation.getParam('rid'); this.t = props.navigation.getParam('t'); this.content = this.defineMessagesViewContent(props.navigation.getParam('name')); } componentDidMount() { this.load(); } shouldComponentUpdate(nextProps, nextState) { const { loading, messages, photoModalVisible, fileLoading } = this.state; if (nextState.loading !== loading) { return true; } if (nextState.photoModalVisible !== photoModalVisible) { return true; } if (!equal(nextState.messages, messages)) { return true; } if (fileLoading !== nextState.fileLoading) { return true; } return false; } defineMessagesViewContent = (name) => { const { messages } = this.state; const { user, baseUrl } = this.props; const renderItemCommonProps = item => ({ baseUrl, user, author: item.u || item.user, ts: item.ts || item.uploadedAt, timeFormat: 'MMM Do YYYY, h:mm:ss a', isEdited: !!item.editedAt, isHeader: true, attachments: item.attachments || [], onOpenFileModal: this.onOpenFileModal, getCustomEmoji: this.getCustomEmoji }); return ({ // Files Messages Screen Files: { name: I18n.t('Files'), fetchFunc: async() => { const result = await RocketChat.getFiles(this.rid, this.t, messages.length); return { ...result, messages: result.files }; }, noDataMsg: I18n.t('No_files'), testID: 'room-files-view', renderItem: (item) => { const url = getFileUrlFromMessage(item); return ( ); } }, // Mentions Messages Screen Mentions: { name: I18n.t('Mentions'), fetchFunc: () => RocketChat.getMessages( this.rid, this.t, { 'mentions._id': { $in: [user.id] } }, messages.length ), noDataMsg: I18n.t('No_mentioned_messages'), testID: 'mentioned-messages-view', renderItem: item => ( ) }, // Starred Messages Screen Starred: { name: I18n.t('Starred'), fetchFunc: () => RocketChat.getMessages( this.rid, this.t, { 'starred._id': { $in: [user.id] } }, messages.length ), noDataMsg: I18n.t('No_starred_messages'), testID: 'starred-messages-view', renderItem: item => ( this.onLongPress(item)} /> ), actionTitle: I18n.t('Unstar'), handleActionPress: message => RocketChat.toggleStarMessage(message._id, message.starred) }, // Pinned Messages Screen Pinned: { name: I18n.t('Pinned'), fetchFunc: () => RocketChat.getMessages(this.rid, this.t, { pinned: true }, messages.length), noDataMsg: I18n.t('No_pinned_messages'), testID: 'pinned-messages-view', renderItem: item => ( this.onLongPress(item)} /> ), actionTitle: I18n.t('Unpin'), handleActionPress: message => RocketChat.togglePinMessage(message._id, message.pinned) } }[name]); } load = async() => { const { messages, total, loading } = this.state; if (messages.length === total || loading) { return; } this.setState({ loading: true }); try { const result = await this.content.fetchFunc(); if (result.success) { this.setState({ messages: [...messages, ...result.messages], total: result.total, loading: false }); } } catch (error) { this.setState({ loading: false }); console.warn('MessagesView -> catch -> error', error); } } getCustomEmoji = (name) => { const { customEmojis } = this.props; const emoji = customEmojis[name]; if (emoji) { return emoji; } return null; } onOpenFileModal = (attachment) => { this.setState({ selectedAttachment: attachment, photoModalVisible: true }); } onCloseFileModal = () => { this.setState({ selectedAttachment: {}, photoModalVisible: false }); } onLongPress = (message) => { this.setState({ message }); this.showActionSheet(); } showActionSheet = () => { ActionSheet.showActionSheetWithOptions({ options: [this.content.actionTitle, I18n.t('Cancel')], cancelButtonIndex: CANCEL_INDEX, title: I18n.t('Actions') }, (actionIndex) => { this.handleActionPress(actionIndex); }); } handleActionPress = async(actionIndex) => { if (actionIndex === ACTION_INDEX) { const { message } = this.state; try { const result = await this.content.handleActionPress(message); if (result.success) { this.setState(prevState => ({ messages: prevState.messages.filter(item => item._id !== message._id), total: prevState.total - 1 })); } } catch (error) { console.warn('MessagesView -> handleActionPress -> catch -> error', error); } } } setFileLoading = (fileLoading) => { this.setState({ fileLoading }); } renderEmpty = () => ( {this.content.noDataMsg} ) renderItem = ({ item }) => this.content.renderItem(item) render() { const { messages, loading, selectedAttachment, photoModalVisible, fileLoading } = this.state; const { user, baseUrl } = this.props; if (!loading && messages.length === 0) { return this.renderEmpty(); } return ( item._id} onEndReached={this.load} ListFooterComponent={loading ? : null} /> ); } } const mapStateToProps = state => ({ baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', user: { id: state.login.user && state.login.user.id, username: state.login.user && state.login.user.username, token: state.login.user && state.login.user.token }, customEmojis: state.customEmojis }); export default connect(mapStateToProps)(MessagesView);