Improved how user lists look, added follow button to them
This commit is contained in:
		
							parent
							
								
									1c84d505c8
								
							
						
					
					
						commit
						ac4f53a3a2
					
				| @ -40,6 +40,10 @@ export const FOLLOWING_FETCH_REQUEST = 'FOLLOWING_FETCH_REQUEST'; | |||||||
| export const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS'; | export const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS'; | ||||||
| export const FOLLOWING_FETCH_FAIL    = 'FOLLOWING_FETCH_FAIL'; | export const FOLLOWING_FETCH_FAIL    = 'FOLLOWING_FETCH_FAIL'; | ||||||
| 
 | 
 | ||||||
|  | export const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST'; | ||||||
|  | export const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS'; | ||||||
|  | export const RELATIONSHIPS_FETCH_FAIL    = 'RELATIONSHIPS_FETCH_FAIL'; | ||||||
|  | 
 | ||||||
| export function setAccountSelf(account) { | export function setAccountSelf(account) { | ||||||
|   return { |   return { | ||||||
|     type: ACCOUNT_SET_SELF, |     type: ACCOUNT_SET_SELF, | ||||||
| @ -304,6 +308,7 @@ export function fetchFollowers(id) { | |||||||
| 
 | 
 | ||||||
|     api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => { |     api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => { | ||||||
|       dispatch(fetchFollowersSuccess(id, response.data)); |       dispatch(fetchFollowersSuccess(id, response.data)); | ||||||
|  |       dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||||
|     }).catch(error => { |     }).catch(error => { | ||||||
|       dispatch(fetchFollowersFail(id, error)); |       dispatch(fetchFollowersFail(id, error)); | ||||||
|     }); |     }); | ||||||
| @ -339,6 +344,7 @@ export function fetchFollowing(id) { | |||||||
| 
 | 
 | ||||||
|     api(getState).get(`/api/v1/accounts/${id}/following`).then(response => { |     api(getState).get(`/api/v1/accounts/${id}/following`).then(response => { | ||||||
|       dispatch(fetchFollowingSuccess(id, response.data)); |       dispatch(fetchFollowingSuccess(id, response.data)); | ||||||
|  |       dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||||
|     }).catch(error => { |     }).catch(error => { | ||||||
|       dispatch(fetchFollowingFail(id, error)); |       dispatch(fetchFollowingFail(id, error)); | ||||||
|     }); |     }); | ||||||
| @ -367,3 +373,36 @@ export function fetchFollowingFail(id, error) { | |||||||
|     error: error |     error: error | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export function fetchRelationships(account_ids) { | ||||||
|  |   return (dispatch, getState) => { | ||||||
|  |     dispatch(fetchRelationshipsRequest(account_ids)); | ||||||
|  | 
 | ||||||
|  |     api(getState).get(`/api/v1/accounts/relationships?${account_ids.map(id => `id[]=${id}`).join('&')}`).then(response => { | ||||||
|  |       dispatch(fetchRelationshipsSuccess(response.data)); | ||||||
|  |     }).catch(error => { | ||||||
|  |       dispatch(fetchRelationshipsFail(error)); | ||||||
|  |     }); | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export function fetchRelationshipsRequest(ids) { | ||||||
|  |   return { | ||||||
|  |     type: RELATIONSHIPS_FETCH_REQUEST, | ||||||
|  |     ids: ids | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export function fetchRelationshipsSuccess(relationships) { | ||||||
|  |   return { | ||||||
|  |     type: RELATIONSHIPS_FETCH_SUCCESS, | ||||||
|  |     relationships: relationships | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export function fetchRelationshipsFail(error) { | ||||||
|  |   return { | ||||||
|  |     type: RELATIONSHIPS_FETCH_FAIL, | ||||||
|  |     error: error | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -109,7 +109,7 @@ const SuggestionsBox = React.createClass({ | |||||||
|             <Link key={account.get('id')} style={itemStyle} to={`/accounts/${account.get('id')}`}> |             <Link key={account.get('id')} style={itemStyle} to={`/accounts/${account.get('id')}`}> | ||||||
|               <div style={{ float: 'left', marginRight: '10px' }}><Avatar src={account.get('avatar')} size={36} /></div> |               <div style={{ float: 'left', marginRight: '10px' }}><Avatar src={account.get('avatar')} size={36} /></div> | ||||||
|               <strong style={displayNameStyle}>{displayName}</strong> |               <strong style={displayNameStyle}>{displayName}</strong> | ||||||
|               <span style={acctStyle}>{account.get('acct')}</span> |               <span style={acctStyle}>@{account.get('acct')}</span> | ||||||
|             </Link> |             </Link> | ||||||
|           ) |           ) | ||||||
|         })} |         })} | ||||||
|  | |||||||
| @ -1,62 +1,82 @@ | |||||||
| import PureRenderMixin    from 'react-addons-pure-render-mixin'; | import PureRenderMixin    from 'react-addons-pure-render-mixin'; | ||||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||||
| import Avatar             from '../../../components/avatar'; | import Avatar             from '../../../components/avatar'; | ||||||
|  | import DisplayName        from '../../../components/display_name'; | ||||||
| import { Link }           from 'react-router'; | import { Link }           from 'react-router'; | ||||||
|  | import IconButton         from '../../../components/icon_button'; | ||||||
| 
 | 
 | ||||||
| const outerStyle = { | const outerStyle = { | ||||||
|   padding: '10px' |   padding: '10px', | ||||||
| }; |   borderBottom: '1px solid #363c4b' | ||||||
| 
 |  | ||||||
| const displayNameStyle = { |  | ||||||
|   display: 'block', |  | ||||||
|   fontWeight: '500', |  | ||||||
|   overflow: 'hidden', |  | ||||||
|   textOverflow: 'ellipsis', |  | ||||||
|   color: '#fff' |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const acctStyle = { |  | ||||||
|   display: 'block', |  | ||||||
|   overflow: 'hidden', |  | ||||||
|   textOverflow: 'ellipsis' |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const itemStyle = { | const itemStyle = { | ||||||
|  |   flex: '1 1 auto', | ||||||
|   display: 'block', |   display: 'block', | ||||||
|   color: '#9baec8', |   color: '#9baec8', | ||||||
|   overflow: 'hidden', |   overflow: 'hidden', | ||||||
|   textDecoration: 'none' |   textDecoration: 'none', | ||||||
|  |   fontSize: '14px' | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const noteStyle = { | ||||||
|  |   paddingTop: '5px', | ||||||
|  |   fontSize: '12px', | ||||||
|  |   color: '#616b86' | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const buttonsStyle = { | ||||||
|  |   padding: '10px' | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const Account = React.createClass({ | const Account = React.createClass({ | ||||||
| 
 | 
 | ||||||
|   propTypes: { |   propTypes: { | ||||||
|     account: ImmutablePropTypes.map.isRequired, |     account: ImmutablePropTypes.map.isRequired, | ||||||
|     me: React.PropTypes.number.isRequired |     me: React.PropTypes.number.isRequired, | ||||||
|  |     onFollow: React.PropTypes.func.isRequired, | ||||||
|  |     withNote: React.PropTypes.bool | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   mixins: [PureRenderMixin], |   mixins: [PureRenderMixin], | ||||||
| 
 | 
 | ||||||
|  |   handleFollow () { | ||||||
|  |     this.props.onFollow(this.props.account); | ||||||
|  |   }, | ||||||
|  | 
 | ||||||
|   render () { |   render () { | ||||||
|     const { account } = this.props; |     const { account, me } = this.props; | ||||||
| 
 | 
 | ||||||
|     if (!account) { |     if (!account) { | ||||||
|       return <div />; |       return <div />; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let displayName = account.get('display_name'); |     let note, buttons; | ||||||
| 
 | 
 | ||||||
|     if (displayName.length === 0) { |     if (account.get('note').length > 0) { | ||||||
|       displayName = account.get('username'); |       note = <div style={noteStyle}>{account.get('note')}</div>; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (account.get('id') !== me) { | ||||||
|  |       buttons = ( | ||||||
|  |         <div style={buttonsStyle}> | ||||||
|  |           <IconButton icon='user-plus' title='Follow' onClick={this.handleFollow} active={account.getIn(['relationship', 'following'])} /> | ||||||
|  |         </div> | ||||||
|  |       ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|       <div style={outerStyle}> |       <div style={outerStyle}> | ||||||
|         <Link key={account.get('id')} style={itemStyle} to={`/accounts/${account.get('id')}`}> |         <div style={{ display: 'flex' }}> | ||||||
|  |           <Link key={account.get('id')} style={itemStyle} className='account__display-name' to={`/accounts/${account.get('id')}`}> | ||||||
|             <div style={{ float: 'left', marginRight: '10px' }}><Avatar src={account.get('avatar')} size={36} /></div> |             <div style={{ float: 'left', marginRight: '10px' }}><Avatar src={account.get('avatar')} size={36} /></div> | ||||||
|           <strong style={displayNameStyle}>{displayName}</strong> |             <DisplayName account={account} /> | ||||||
|           <span style={acctStyle}>{account.get('acct')}</span> |  | ||||||
|           </Link> |           </Link> | ||||||
|  | 
 | ||||||
|  |           {buttons} | ||||||
|  |         </div> | ||||||
|  | 
 | ||||||
|  |         {note} | ||||||
|       </div> |       </div> | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -1,6 +1,10 @@ | |||||||
| import { connect }            from 'react-redux'; | import { connect }            from 'react-redux'; | ||||||
| import { makeGetAccount }     from '../../../selectors'; | import { makeGetAccount }     from '../../../selectors'; | ||||||
| import Account                from '../components/account'; | import Account                from '../components/account'; | ||||||
|  | import { | ||||||
|  |   followAccount, | ||||||
|  |   unfollowAccount | ||||||
|  | }                             from '../../../actions/accounts'; | ||||||
| 
 | 
 | ||||||
| const makeMapStateToProps = () => { | const makeMapStateToProps = () => { | ||||||
|   const getAccount = makeGetAccount(); |   const getAccount = makeGetAccount(); | ||||||
| @ -14,7 +18,13 @@ const makeMapStateToProps = () => { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const mapDispatchToProps = (dispatch) => ({ | const mapDispatchToProps = (dispatch) => ({ | ||||||
|   // |   onFollow (account) { | ||||||
|  |     if (account.getIn(['relationship', 'following'])) { | ||||||
|  |       dispatch(unfollowAccount(account.get('id'))); | ||||||
|  |     } else { | ||||||
|  |       dispatch(followAccount(account.get('id'))); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| export default connect(makeMapStateToProps, mapDispatchToProps)(Account); | export default connect(makeMapStateToProps, mapDispatchToProps)(Account); | ||||||
|  | |||||||
| @ -20,7 +20,8 @@ import { | |||||||
|   ACCOUNT_TIMELINE_FETCH_SUCCESS, |   ACCOUNT_TIMELINE_FETCH_SUCCESS, | ||||||
|   ACCOUNT_TIMELINE_EXPAND_SUCCESS, |   ACCOUNT_TIMELINE_EXPAND_SUCCESS, | ||||||
|   FOLLOWERS_FETCH_SUCCESS, |   FOLLOWERS_FETCH_SUCCESS, | ||||||
|   FOLLOWING_FETCH_SUCCESS |   FOLLOWING_FETCH_SUCCESS, | ||||||
|  |   RELATIONSHIPS_FETCH_SUCCESS | ||||||
| }                                from '../actions/accounts'; | }                                from '../actions/accounts'; | ||||||
| import { | import { | ||||||
|   STATUS_FETCH_SUCCESS, |   STATUS_FETCH_SUCCESS, | ||||||
| @ -184,6 +185,14 @@ function normalizeRelationship(state, relationship) { | |||||||
|   return state.setIn(['relationships', relationship.get('id')], relationship); |   return state.setIn(['relationships', relationship.get('id')], relationship); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | function normalizeRelationships(state, relationships) { | ||||||
|  |   relationships.forEach(relationship => { | ||||||
|  |     state = normalizeRelationship(state, relationship); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   return state; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| function setSelf(state, account) { | function setSelf(state, account) { | ||||||
|   state = normalizeAccount(state, account); |   state = normalizeAccount(state, account); | ||||||
|   return state.set('me', account.get('id')); |   return state.set('me', account.get('id')); | ||||||
| @ -252,6 +261,8 @@ export default function timelines(state = initialState, action) { | |||||||
|     case FOLLOWERS_FETCH_SUCCESS: |     case FOLLOWERS_FETCH_SUCCESS: | ||||||
|     case FOLLOWING_FETCH_SUCCESS: |     case FOLLOWING_FETCH_SUCCESS: | ||||||
|       return normalizeAccounts(state, Immutable.fromJS(action.accounts)); |       return normalizeAccounts(state, Immutable.fromJS(action.accounts)); | ||||||
|  |     case RELATIONSHIPS_FETCH_SUCCESS: | ||||||
|  |       return normalizeRelationships(state, Immutable.fromJS(action.relationships)); | ||||||
|     default: |     default: | ||||||
|       return state; |       return state; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -117,17 +117,17 @@ | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .status__display-name, .status__relative-time, .detailed-status__display-name, .detailed-status__datetime { | .status__display-name, .status__relative-time, .detailed-status__display-name, .detailed-status__datetime, .account__display-name { | ||||||
|   text-decoration: none; |   text-decoration: none; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .status__display-name { | .status__display-name, .account__display-name { | ||||||
|   strong { |   strong { | ||||||
|     color: #fff; |     color: #fff; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .status__display-name, .reply-indicator__display-name, .detailed-status__display-name { | .status__display-name, .reply-indicator__display-name, .detailed-status__display-name, .account__display-name { | ||||||
|   &:hover { |   &:hover { | ||||||
|     strong { |     strong { | ||||||
|       text-decoration: underline; |       text-decoration: underline; | ||||||
| @ -135,6 +135,12 @@ | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .account__display-name { | ||||||
|  |   strong { | ||||||
|  |     display: block; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .detailed-status__display-name { | .detailed-status__display-name { | ||||||
|   color: #d9e1e8; |   color: #d9e1e8; | ||||||
|   line-height: 24px; |   line-height: 24px; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user