// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import SearchResultsHeader from './search_results_header.jsx'; import SearchResultsItem from './search_results_item.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import SearchStore from 'stores/search_store.jsx'; import UserStore from 'stores/user_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; import WebrtcStore from 'stores/webrtc_store.jsx'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; const Preferences = Constants.Preferences; import $ from 'jquery'; import PropTypes from 'prop-types'; import React from 'react'; import {FormattedMessage, FormattedHTMLMessage} from 'react-intl'; function getStateFromStores() { const results = JSON.parse(JSON.stringify(SearchStore.getSearchResults())); const channels = new Map(); if (results && results.order) { const channelIds = results.order.map((postId) => results.posts[postId].channel_id); for (const id of channelIds) { if (channels.has(id)) { continue; } channels.set(id, ChannelStore.get(id)); } } return { results, channels, searchTerm: SearchStore.getSearchTerm(), flaggedPosts: PreferenceStore.getCategory(Constants.Preferences.CATEGORY_FLAGGED_POST) }; } export default class SearchResults extends React.Component { constructor(props) { super(props); this.mounted = false; this.onChange = this.onChange.bind(this); this.onUserChange = this.onUserChange.bind(this); this.onPreferenceChange = this.onPreferenceChange.bind(this); this.onBusy = this.onBusy.bind(this); this.resize = this.resize.bind(this); this.onPreferenceChange = this.onPreferenceChange.bind(this); this.onStatusChange = this.onStatusChange.bind(this); this.handleResize = this.handleResize.bind(this); const state = getStateFromStores(); state.windowWidth = Utils.windowWidth(); state.windowHeight = Utils.windowHeight(); state.profiles = JSON.parse(JSON.stringify(UserStore.getProfiles())); state.compactDisplay = PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT; state.isBusy = WebrtcStore.isBusy(); state.statuses = Object.assign({}, UserStore.getStatuses()); this.state = state; } componentDidMount() { this.mounted = true; SearchStore.addSearchChangeListener(this.onChange); ChannelStore.addChangeListener(this.onChange); PreferenceStore.addChangeListener(this.onPreferenceChange); UserStore.addChangeListener(this.onUserChange); UserStore.addStatusesChangeListener(this.onStatusChange); PreferenceStore.addChangeListener(this.onPreferenceChange); WebrtcStore.addBusyListener(this.onBusy); this.resize(); window.addEventListener('resize', this.handleResize); if (!Utils.isMobile()) { $('.sidebar--right .search-items-container').perfectScrollbar(); } } shouldComponentUpdate(nextProps, nextState) { if (!Utils.areObjectsEqual(nextState.statuses, this.state.statuses)) { return true; } if (!Utils.areObjectsEqual(this.props, nextProps)) { return true; } if (!Utils.areObjectsEqual(this.state, nextState)) { return true; } if (nextState.compactDisplay !== this.state.compactDisplay) { return true; } if (nextState.isBusy !== this.state.isBusy) { return true; } return false; } componentWillUnmount() { this.mounted = false; SearchStore.removeSearchChangeListener(this.onChange); ChannelStore.removeChangeListener(this.onChange); PreferenceStore.removeChangeListener(this.onPreferenceChange); UserStore.removeChangeListener(this.onUserChange); UserStore.removeStatusesChangeListener(this.onStatusChange); PreferenceStore.removeChangeListener(this.onPreferenceChange); WebrtcStore.removeBusyListener(this.onBusy); window.removeEventListener('resize', this.handleResize); } componentDidUpdate(prevProps, prevState) { if (this.state.searchTerm !== prevState.searchTerm) { this.resize(); } } handleResize() { this.setState({ windowWidth: Utils.windowWidth(), windowHeight: Utils.windowHeight() }); } onPreferenceChange() { this.setState({ compactDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT, flaggedPosts: PreferenceStore.getCategory(Constants.Preferences.CATEGORY_FLAGGED_POST) }); } onChange() { if (this.mounted) { this.setState(getStateFromStores()); } } onUserChange() { this.setState({profiles: JSON.parse(JSON.stringify(UserStore.getProfiles()))}); } onBusy(isBusy) { this.setState({isBusy}); } onStatusChange() { this.setState({statuses: Object.assign({}, UserStore.getStatuses())}); } resize() { $('#search-items-container').scrollTop(0); } render() { var results = this.state.results; var noResults = (!results || !results.order || !results.order.length); const searchTerm = this.state.searchTerm; const profiles = this.state.profiles || {}; const flagIcon = Constants.FLAG_ICON_SVG; var ctls = null; if (this.props.isFlaggedPosts && noResults) { ctls = (
); } else if (this.props.isPinnedPosts && noResults) { ctls = (
); } else if (!searchTerm && noResults) { ctls = (
); } else if (noResults) { ctls = (

); } else { ctls = results.order.map(function searchResults(id, idx, arr) { const post = results.posts[id]; let profile; if (UserStore.getCurrentId() === post.user_id) { profile = UserStore.getCurrentUser(); } else { profile = profiles[post.user_id]; } let status = 'offline'; if (this.state.statuses) { status = this.state.statuses[post.user_id] || 'offline'; } let isFlagged = false; if (this.state.flaggedPosts) { isFlagged = this.state.flaggedPosts.get(post.id) === 'true'; } const reverseCount = arr.length - idx - 1; return ( = 0 && reverseCount < Constants.TEST_ID_COUNT) ? reverseCount : -1} user={profile} term={searchTerm} isMentionSearch={this.props.isMentionSearch} isFlaggedSearch={this.props.isFlaggedPosts} useMilitaryTime={this.props.useMilitaryTime} shrink={this.props.shrink} isFlagged={isFlagged} isBusy={this.state.isBusy} status={status} /> ); }, this); } return (
{ctls}
); } } SearchResults.propTypes = { isMentionSearch: PropTypes.bool, useMilitaryTime: PropTypes.bool.isRequired, toggleSize: PropTypes.func, shrink: PropTypes.func, isFlaggedPosts: PropTypes.bool, isPinnedPosts: PropTypes.bool, channelDisplayName: PropTypes.string.isRequired };