diff options
author | Eugen Rochko <eugen@zeonfederated.com> | 2016-11-23 23:34:12 +0100 |
---|---|---|
committer | Eugen Rochko <eugen@zeonfederated.com> | 2016-11-23 23:34:12 +0100 |
commit | cbc50016eb3d0a46e76aca9ed199b036ce20abdb (patch) | |
tree | 39930478584c1bcd73061b69e2d18be868f78d9a | |
parent | 7cee27f51790617859da87c7aef432373b40aad4 (diff) |
Follow/unfollow button outside of dropdown, also make favs/reblogs update indicator instantly and
then adjust to failure later if the request fails
5 files changed, 48 insertions, 15 deletions
diff --git a/app/assets/javascripts/components/components/button.jsx b/app/assets/javascripts/components/components/button.jsx index fe36d40c5..d63129013 100644 --- a/app/assets/javascripts/components/components/button.jsx +++ b/app/assets/javascripts/components/components/button.jsx @@ -7,7 +7,14 @@ const Button = React.createClass({ onClick: React.PropTypes.func, disabled: React.PropTypes.bool, block: React.PropTypes.bool, - secondary: React.PropTypes.bool + secondary: React.PropTypes.bool, + size: React.PropTypes.number, + }, + + getDefaultProps () { + return { + size: 36 + }; }, mixins: [PureRenderMixin], @@ -32,16 +39,16 @@ const Button = React.createClass({ fontWeight: '500', letterSpacing: '0', textTransform: 'uppercase', - padding: '0 16px', - height: '36px', + padding: `0 ${this.props.size / 2.25}px`, + height: `${this.props.size}px`, cursor: 'pointer', - lineHeight: '36px', + lineHeight: `${this.props.size}px`, borderRadius: '4px', textDecoration: 'none' }; - + return ( - <button className={`button ${this.props.secondary ? 'button-secondary' : ''}`} disabled={this.props.disabled} onClick={this.handleClick} style={style}> + <button className={`button ${this.props.secondary ? 'button-secondary' : ''}`} disabled={this.props.disabled} onClick={this.handleClick} style={{ ...style, ...this.props.style }}> {this.props.text || this.props.children} </button> ); diff --git a/app/assets/javascripts/components/features/account/components/action_bar.jsx b/app/assets/javascripts/components/features/account/components/action_bar.jsx index cd01de2e2..f09dea6ab 100644 --- a/app/assets/javascripts/components/features/account/components/action_bar.jsx +++ b/app/assets/javascripts/components/features/account/components/action_bar.jsx @@ -58,10 +58,8 @@ const ActionBar = React.createClass({ } else if (account.getIn(['relationship', 'blocking'])) { menu.push({ text: intl.formatMessage(messages.unblock), action: this.props.onBlock }); } else if (account.getIn(['relationship', 'following'])) { - menu.push({ text: intl.formatMessage(messages.unfollow), action: this.props.onFollow }); menu.push({ text: intl.formatMessage(messages.block), action: this.props.onBlock }); } else { - menu.push({ text: intl.formatMessage(messages.follow), action: this.props.onFollow }); menu.push({ text: intl.formatMessage(messages.block), action: this.props.onBlock }); } diff --git a/app/assets/javascripts/components/features/account/components/header.jsx b/app/assets/javascripts/components/features/account/components/header.jsx index b3e9e2a9f..d39a06062 100644 --- a/app/assets/javascripts/components/features/account/components/header.jsx +++ b/app/assets/javascripts/components/features/account/components/header.jsx @@ -2,22 +2,30 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; import emojify from '../../../emoji'; import escapeTextContentForBrowser from 'react/lib/escapeTextContentForBrowser'; -import { FormattedMessage } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import IconButton from '../../../components/icon_button'; + +const messages = defineMessages({ + unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, + follow: { id: 'account.follow', defaultMessage: 'Follow' }, +}); const Header = React.createClass({ propTypes: { account: ImmutablePropTypes.map.isRequired, - me: React.PropTypes.number.isRequired + me: React.PropTypes.number.isRequired, + onFollow: React.PropTypes.func.isRequired }, mixins: [PureRenderMixin], render () { - const { account, me } = this.props; + const { account, me, intl } = this.props; let displayName = account.get('display_name'); let info = ''; + let actionBtn = ''; if (displayName.length === 0) { displayName = account.get('username'); @@ -27,6 +35,14 @@ const Header = React.createClass({ info = <span style={{ position: 'absolute', top: '10px', right: '10px', opacity: '0.7', display: 'inline-block', verticalAlign: 'top', background: 'rgba(0, 0, 0, 0.4)', color: '#fff', textTransform: 'uppercase', fontSize: '11px', fontWeight: '500', padding: '4px', borderRadius: '4px' }}><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span> } + if (me !== account.get('id')) { + actionBtn = ( + <div style={{ position: 'absolute', top: '10px', left: '20px' }}> + <IconButton size={26} icon={account.getIn(['relationship', 'following']) ? 'user-times' : 'user-plus'} active={account.getIn(['relationship', 'following'])} title={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} /> + </div> + ); + } + const content = { __html: emojify(account.get('note')) }; const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) }; @@ -45,6 +61,7 @@ const Header = React.createClass({ <div style={{ color: '#616b86', fontSize: '14px' }} className='account__header__content' dangerouslySetInnerHTML={content} /> {info} + {actionBtn} </div> </div> ); @@ -52,4 +69,4 @@ const Header = React.createClass({ }); -export default Header; +export default injectIntl(Header); diff --git a/app/assets/javascripts/components/features/account/index.jsx b/app/assets/javascripts/components/features/account/index.jsx index 818979f8f..c2cc58bb2 100644 --- a/app/assets/javascripts/components/features/account/index.jsx +++ b/app/assets/javascripts/components/features/account/index.jsx @@ -87,9 +87,8 @@ const Account = React.createClass({ return ( <Column> <ColumnBackButton /> - <Header account={account} me={me} /> - - <ActionBar account={account} me={me} onFollow={this.handleFollow} onBlock={this.handleBlock} onMention={this.handleMention} /> + <Header account={account} me={me} onFollow={this.handleFollow} /> + <ActionBar account={account} me={me} onBlock={this.handleBlock} onMention={this.handleMention} /> {this.props.children} </Column> diff --git a/app/assets/javascripts/components/reducers/statuses.jsx b/app/assets/javascripts/components/reducers/statuses.jsx index f42b1a481..c740b6d64 100644 --- a/app/assets/javascripts/components/reducers/statuses.jsx +++ b/app/assets/javascripts/components/reducers/statuses.jsx @@ -1,7 +1,11 @@ import { + REBLOG_REQUEST, REBLOG_SUCCESS, + REBLOG_FAIL, UNREBLOG_SUCCESS, + FAVOURITE_REQUEST, FAVOURITE_SUCCESS, + FAVOURITE_FAIL, UNFAVOURITE_SUCCESS } from '../actions/interactions'; import { @@ -82,6 +86,14 @@ export default function statuses(state = initialState, action) { case FAVOURITE_SUCCESS: case UNFAVOURITE_SUCCESS: return normalizeStatus(state, action.response); + case FAVOURITE_REQUEST: + return state.setIn([action.status.get('id'), 'favourited'], true); + case FAVOURITE_FAIL: + return state.setIn([action.status.get('id'), 'favourited'], false); + case REBLOG_REQUEST: + return state.setIn([action.status.get('id'), 'reblogged'], true); + case REBLOG_FAIL: + return state.setIn([action.status.get('id'), 'reblogged'], false); case TIMELINE_REFRESH_SUCCESS: case TIMELINE_EXPAND_SUCCESS: case ACCOUNT_TIMELINE_FETCH_SUCCESS: |