[Glitch] Show suggested follows on search screen in mobile layout
Port ad510db3a19640267f94062756d558a45472af14 to glitch-soc
This commit is contained in:
		
							parent
							
								
									149aa07409
								
							
						
					
					
						commit
						9b9816aba6
					
				
							
								
								
									
										52
									
								
								app/javascript/flavours/glitch/actions/suggestions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								app/javascript/flavours/glitch/actions/suggestions.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					import api from 'flavours/glitch/util/api';
 | 
				
			||||||
 | 
					import { importFetchedAccounts } from './importer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST';
 | 
				
			||||||
 | 
					export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS';
 | 
				
			||||||
 | 
					export const SUGGESTIONS_FETCH_FAIL    = 'SUGGESTIONS_FETCH_FAIL';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function fetchSuggestions() {
 | 
				
			||||||
 | 
					  return (dispatch, getState) => {
 | 
				
			||||||
 | 
					    dispatch(fetchSuggestionsRequest());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    api(getState).get('/api/v1/suggestions').then(response => {
 | 
				
			||||||
 | 
					      dispatch(importFetchedAccounts(response.data));
 | 
				
			||||||
 | 
					      dispatch(fetchSuggestionsSuccess(response.data));
 | 
				
			||||||
 | 
					    }).catch(error => dispatch(fetchSuggestionsFail(error)));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function fetchSuggestionsRequest() {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    type: SUGGESTIONS_FETCH_REQUEST,
 | 
				
			||||||
 | 
					    skipLoading: true,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function fetchSuggestionsSuccess(accounts) {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    type: SUGGESTIONS_FETCH_SUCCESS,
 | 
				
			||||||
 | 
					    accounts,
 | 
				
			||||||
 | 
					    skipLoading: true,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function fetchSuggestionsFail(error) {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    type: SUGGESTIONS_FETCH_FAIL,
 | 
				
			||||||
 | 
					    error,
 | 
				
			||||||
 | 
					    skipLoading: true,
 | 
				
			||||||
 | 
					    skipAlert: true,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const dismissSuggestion = accountId => (dispatch, getState) => {
 | 
				
			||||||
 | 
					  dispatch({
 | 
				
			||||||
 | 
					    type: SUGGESTIONS_DISMISS,
 | 
				
			||||||
 | 
					    id: accountId,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  api(getState).delete(`/api/v1/suggestions/${accountId}`);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -31,6 +31,9 @@ export default class Account extends ImmutablePureComponent {
 | 
				
			|||||||
    intl: PropTypes.object.isRequired,
 | 
					    intl: PropTypes.object.isRequired,
 | 
				
			||||||
    hidden: PropTypes.bool,
 | 
					    hidden: PropTypes.bool,
 | 
				
			||||||
    small: PropTypes.bool,
 | 
					    small: PropTypes.bool,
 | 
				
			||||||
 | 
					    actionIcon: PropTypes.string,
 | 
				
			||||||
 | 
					    actionTitle: PropTypes.string,
 | 
				
			||||||
 | 
					    onActionClick: PropTypes.func,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleFollow = () => {
 | 
					  handleFollow = () => {
 | 
				
			||||||
@ -53,12 +56,19 @@ export default class Account extends ImmutablePureComponent {
 | 
				
			|||||||
    this.props.onMuteNotifications(this.props.account, false);
 | 
					    this.props.onMuteNotifications(this.props.account, false);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleAction = () => {
 | 
				
			||||||
 | 
					    this.props.onActionClick(this.props.account);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
      account,
 | 
					      account,
 | 
				
			||||||
      hidden,
 | 
					      hidden,
 | 
				
			||||||
      intl,
 | 
					      intl,
 | 
				
			||||||
      small,
 | 
					      small,
 | 
				
			||||||
 | 
					      onActionClick,
 | 
				
			||||||
 | 
					      actionIcon,
 | 
				
			||||||
 | 
					      actionTitle,
 | 
				
			||||||
    } = this.props;
 | 
					    } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!account) {
 | 
					    if (!account) {
 | 
				
			||||||
@ -76,7 +86,9 @@ export default class Account extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let buttons;
 | 
					    let buttons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (account.get('id') !== me && !small && account.get('relationship', null) !== null) {
 | 
					    if (onActionClick && actionIcon) {
 | 
				
			||||||
 | 
					      buttons = <IconButton icon={actionIcon} title={actionTitle} onClick={this.handleAction} />;
 | 
				
			||||||
 | 
					    } else if (account.get('id') !== me && !small && account.get('relationship', null) !== null) {
 | 
				
			||||||
      const following = account.getIn(['relationship', 'following']);
 | 
					      const following = account.getIn(['relationship', 'following']);
 | 
				
			||||||
      const requested = account.getIn(['relationship', 'requested']);
 | 
					      const requested = account.getIn(['relationship', 'requested']);
 | 
				
			||||||
      const blocking  = account.getIn(['relationship', 'blocking']);
 | 
					      const blocking  = account.getIn(['relationship', 'blocking']);
 | 
				
			||||||
 | 
				
			|||||||
@ -8,16 +8,50 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			|||||||
import Hashtag from 'flavours/glitch/components/hashtag';
 | 
					import Hashtag from 'flavours/glitch/components/hashtag';
 | 
				
			||||||
import Icon from 'flavours/glitch/components/icon';
 | 
					import Icon from 'flavours/glitch/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const messages = defineMessages({
 | 
				
			||||||
 | 
					  dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default @injectIntl
 | 
					export default @injectIntl
 | 
				
			||||||
class SearchResults extends ImmutablePureComponent {
 | 
					class SearchResults extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    results: ImmutablePropTypes.map.isRequired,
 | 
					    results: ImmutablePropTypes.map.isRequired,
 | 
				
			||||||
 | 
					    suggestions: ImmutablePropTypes.list.isRequired,
 | 
				
			||||||
 | 
					    fetchSuggestions: PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					    dismissSuggestion: PropTypes.func.isRequired,
 | 
				
			||||||
    intl: PropTypes.object.isRequired,
 | 
					    intl: PropTypes.object.isRequired,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  componentDidMount () {
 | 
				
			||||||
 | 
					    this.props.fetchSuggestions();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render() {
 | 
					  render() {
 | 
				
			||||||
    const { intl, results } = this.props;
 | 
					    const { intl, results, suggestions, dismissSuggestion } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (results.isEmpty() && !suggestions.isEmpty()) {
 | 
				
			||||||
 | 
					      return (
 | 
				
			||||||
 | 
					        <div className='drawer--results'>
 | 
				
			||||||
 | 
					          <div className='trends'>
 | 
				
			||||||
 | 
					            <div className='trends__header'>
 | 
				
			||||||
 | 
					              <i className='fa fa-user-plus fa-fw' />
 | 
				
			||||||
 | 
					              <FormattedMessage id='suggestions.header' defaultMessage='You might be interested in…' />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            {suggestions && suggestions.map(accountId => (
 | 
				
			||||||
 | 
					              <AccountContainer
 | 
				
			||||||
 | 
					                key={accountId}
 | 
				
			||||||
 | 
					                id={accountId}
 | 
				
			||||||
 | 
					                actionIcon='times'
 | 
				
			||||||
 | 
					                actionTitle={intl.formatMessage(messages.dismissSuggestion)}
 | 
				
			||||||
 | 
					                onActionClick={dismissSuggestion}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let accounts, statuses, hashtags;
 | 
					    let accounts, statuses, hashtags;
 | 
				
			||||||
    let count = 0;
 | 
					    let count = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,15 @@
 | 
				
			|||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import SearchResults from '../components/search_results';
 | 
					import SearchResults from '../components/search_results';
 | 
				
			||||||
 | 
					import { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = state => ({
 | 
					const mapStateToProps = state => ({
 | 
				
			||||||
  results: state.getIn(['search', 'results']),
 | 
					  results: state.getIn(['search', 'results']),
 | 
				
			||||||
 | 
					  suggestions: state.getIn(['suggestions', 'items']),
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default connect(mapStateToProps)(SearchResults);
 | 
					const mapDispatchToProps = dispatch => ({
 | 
				
			||||||
 | 
					  fetchSuggestions: () => dispatch(fetchSuggestions()),
 | 
				
			||||||
 | 
					  dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))),
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default connect(mapStateToProps, mapDispatchToProps)(SearchResults);
 | 
				
			||||||
 | 
				
			|||||||
@ -28,6 +28,7 @@ import lists from './lists';
 | 
				
			|||||||
import listEditor from './list_editor';
 | 
					import listEditor from './list_editor';
 | 
				
			||||||
import listAdder from './list_adder';
 | 
					import listAdder from './list_adder';
 | 
				
			||||||
import filters from './filters';
 | 
					import filters from './filters';
 | 
				
			||||||
 | 
					import suggestions from './suggestions';
 | 
				
			||||||
import pinnedAccountsEditor from './pinned_accounts_editor';
 | 
					import pinnedAccountsEditor from './pinned_accounts_editor';
 | 
				
			||||||
import polls from './polls';
 | 
					import polls from './polls';
 | 
				
			||||||
import identity_proofs from './identity_proofs';
 | 
					import identity_proofs from './identity_proofs';
 | 
				
			||||||
@ -63,6 +64,7 @@ const reducers = {
 | 
				
			|||||||
  listEditor,
 | 
					  listEditor,
 | 
				
			||||||
  listAdder,
 | 
					  listAdder,
 | 
				
			||||||
  filters,
 | 
					  filters,
 | 
				
			||||||
 | 
					  suggestions,
 | 
				
			||||||
  pinnedAccountsEditor,
 | 
					  pinnedAccountsEditor,
 | 
				
			||||||
  polls,
 | 
					  polls,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										30
									
								
								app/javascript/flavours/glitch/reducers/suggestions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								app/javascript/flavours/glitch/reducers/suggestions.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  SUGGESTIONS_FETCH_REQUEST,
 | 
				
			||||||
 | 
					  SUGGESTIONS_FETCH_SUCCESS,
 | 
				
			||||||
 | 
					  SUGGESTIONS_FETCH_FAIL,
 | 
				
			||||||
 | 
					  SUGGESTIONS_DISMISS,
 | 
				
			||||||
 | 
					} from '../actions/suggestions';
 | 
				
			||||||
 | 
					import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const initialState = ImmutableMap({
 | 
				
			||||||
 | 
					  items: ImmutableList(),
 | 
				
			||||||
 | 
					  isLoading: false,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function suggestionsReducer(state = initialState, action) {
 | 
				
			||||||
 | 
					  switch(action.type) {
 | 
				
			||||||
 | 
					  case SUGGESTIONS_FETCH_REQUEST:
 | 
				
			||||||
 | 
					    return state.set('isLoading', true);
 | 
				
			||||||
 | 
					  case SUGGESTIONS_FETCH_SUCCESS:
 | 
				
			||||||
 | 
					    return state.withMutations(map => {
 | 
				
			||||||
 | 
					      map.set('items', fromJS(action.accounts.map(x => x.id)));
 | 
				
			||||||
 | 
					      map.set('isLoading', false);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  case SUGGESTIONS_FETCH_FAIL:
 | 
				
			||||||
 | 
					    return state.set('isLoading', false);
 | 
				
			||||||
 | 
					  case SUGGESTIONS_DISMISS:
 | 
				
			||||||
 | 
					    return state.update('items', list => list.filterNot(id => id === action.id));
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    return state;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user