You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
5.3 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import ImmutablePropTypes from 'react-immutable-proptypes';
  4. import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
  5. import AccountContainer from '../../../containers/account_container';
  6. import StatusContainer from '../../../containers/status_container';
  7. import ImmutablePureComponent from 'react-immutable-pure-component';
  8. import Hashtag from '../../../components/hashtag';
  9. import Icon from 'mastodon/components/icon';
  10. import { searchEnabled } from '../../../initial_state';
  11. import LoadMore from 'mastodon/components/load_more';
  12. const messages = defineMessages({
  13. dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
  14. });
  15. export default @injectIntl
  16. class SearchResults extends ImmutablePureComponent {
  17. static propTypes = {
  18. results: ImmutablePropTypes.map.isRequired,
  19. suggestions: ImmutablePropTypes.list.isRequired,
  20. fetchSuggestions: PropTypes.func.isRequired,
  21. expandSearch: PropTypes.func.isRequired,
  22. dismissSuggestion: PropTypes.func.isRequired,
  23. searchTerm: PropTypes.string,
  24. intl: PropTypes.object.isRequired,
  25. };
  26. componentDidMount () {
  27. if (this.props.searchTerm === '') {
  28. this.props.fetchSuggestions();
  29. }
  30. }
  31. componentDidUpdate () {
  32. if (this.props.searchTerm === '') {
  33. this.props.fetchSuggestions();
  34. }
  35. }
  36. handleLoadMoreAccounts = () => this.props.expandSearch('accounts');
  37. handleLoadMoreStatuses = () => this.props.expandSearch('statuses');
  38. handleLoadMoreHashtags = () => this.props.expandSearch('hashtags');
  39. render () {
  40. const { intl, results, suggestions, dismissSuggestion, searchTerm } = this.props;
  41. if (searchTerm === '' && !suggestions.isEmpty()) {
  42. return (
  43. <div className='search-results'>
  44. <div className='trends'>
  45. <div className='trends__header'>
  46. <Icon id='user-plus' fixedWidth />
  47. <FormattedMessage id='suggestions.header' defaultMessage='You might be interested in…' />
  48. </div>
  49. {suggestions && suggestions.map(suggestion => (
  50. <AccountContainer
  51. key={suggestion.get('account')}
  52. id={suggestion.get('account')}
  53. actionIcon={suggestion.get('source') === 'past_interaction' ? 'times' : null}
  54. actionTitle={suggestion.get('source') === 'past_interaction' ? intl.formatMessage(messages.dismissSuggestion) : null}
  55. onActionClick={dismissSuggestion}
  56. />
  57. ))}
  58. </div>
  59. </div>
  60. );
  61. }
  62. let accounts, statuses, hashtags;
  63. let count = 0;
  64. if (results.get('accounts') && results.get('accounts').size > 0) {
  65. count += results.get('accounts').size;
  66. accounts = (
  67. <div className='search-results__section'>
  68. <h5><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='People' /></h5>
  69. {results.get('accounts').map(accountId => <AccountContainer key={accountId} id={accountId} />)}
  70. {results.get('accounts').size >= 5 && <LoadMore visible onClick={this.handleLoadMoreAccounts} />}
  71. </div>
  72. );
  73. }
  74. if (results.get('statuses') && results.get('statuses').size > 0) {
  75. count += results.get('statuses').size;
  76. statuses = (
  77. <div className='search-results__section'>
  78. <h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
  79. {results.get('statuses').map(statusId => <StatusContainer key={statusId} id={statusId} />)}
  80. {results.get('statuses').size >= 5 && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
  81. </div>
  82. );
  83. } else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
  84. statuses = (
  85. <div className='search-results__section'>
  86. <h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
  87. <div className='search-results__info'>
  88. <FormattedMessage id='search_results.statuses_fts_disabled' defaultMessage='Searching toots by their content is not enabled on this Mastodon server.' />
  89. </div>
  90. </div>
  91. );
  92. }
  93. if (results.get('hashtags') && results.get('hashtags').size > 0) {
  94. count += results.get('hashtags').size;
  95. hashtags = (
  96. <div className='search-results__section'>
  97. <h5><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5>
  98. {results.get('hashtags').map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
  99. {results.get('hashtags').size >= 5 && <LoadMore visible onClick={this.handleLoadMoreHashtags} />}
  100. </div>
  101. );
  102. }
  103. return (
  104. <div className='search-results'>
  105. <div className='search-results__header'>
  106. <Icon id='search' fixedWidth />
  107. <FormattedMessage id='search_results.total' defaultMessage='{count, number} {count, plural, one {result} other {results}}' values={{ count }} />
  108. </div>
  109. {accounts}
  110. {statuses}
  111. {hashtags}
  112. </div>
  113. );
  114. }
  115. }