[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,
 | 
			
		||||
    hidden: PropTypes.bool,
 | 
			
		||||
    small: PropTypes.bool,
 | 
			
		||||
    actionIcon: PropTypes.string,
 | 
			
		||||
    actionTitle: PropTypes.string,
 | 
			
		||||
    onActionClick: PropTypes.func,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  handleFollow = () => {
 | 
			
		||||
@ -53,12 +56,19 @@ export default class Account extends ImmutablePureComponent {
 | 
			
		||||
    this.props.onMuteNotifications(this.props.account, false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleAction = () => {
 | 
			
		||||
    this.props.onActionClick(this.props.account);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render () {
 | 
			
		||||
    const {
 | 
			
		||||
      account,
 | 
			
		||||
      hidden,
 | 
			
		||||
      intl,
 | 
			
		||||
      small,
 | 
			
		||||
      onActionClick,
 | 
			
		||||
      actionIcon,
 | 
			
		||||
      actionTitle,
 | 
			
		||||
    } = this.props;
 | 
			
		||||
 | 
			
		||||
    if (!account) {
 | 
			
		||||
@ -76,7 +86,9 @@ export default class Account extends ImmutablePureComponent {
 | 
			
		||||
 | 
			
		||||
    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 requested = account.getIn(['relationship', 'requested']);
 | 
			
		||||
      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 Icon from 'flavours/glitch/components/icon';
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default @injectIntl
 | 
			
		||||
class SearchResults extends ImmutablePureComponent {
 | 
			
		||||
 | 
			
		||||
  static propTypes = {
 | 
			
		||||
    results: ImmutablePropTypes.map.isRequired,
 | 
			
		||||
    suggestions: ImmutablePropTypes.list.isRequired,
 | 
			
		||||
    fetchSuggestions: PropTypes.func.isRequired,
 | 
			
		||||
    dismissSuggestion: PropTypes.func.isRequired,
 | 
			
		||||
    intl: PropTypes.object.isRequired,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  componentDidMount () {
 | 
			
		||||
    this.props.fetchSuggestions();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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 count = 0;
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,15 @@
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import SearchResults from '../components/search_results';
 | 
			
		||||
import { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestions';
 | 
			
		||||
 | 
			
		||||
const mapStateToProps = state => ({
 | 
			
		||||
  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 listAdder from './list_adder';
 | 
			
		||||
import filters from './filters';
 | 
			
		||||
import suggestions from './suggestions';
 | 
			
		||||
import pinnedAccountsEditor from './pinned_accounts_editor';
 | 
			
		||||
import polls from './polls';
 | 
			
		||||
import identity_proofs from './identity_proofs';
 | 
			
		||||
@ -63,6 +64,7 @@ const reducers = {
 | 
			
		||||
  listEditor,
 | 
			
		||||
  listAdder,
 | 
			
		||||
  filters,
 | 
			
		||||
  suggestions,
 | 
			
		||||
  pinnedAccountsEditor,
 | 
			
		||||
  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