[Glitch] Show suggested follows on search screen in mobile layout
Port ad510db3a1 to glitch-soc
			
			
This commit is contained in:
		
							
								
								
									
										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; | ||||
|   } | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user