From f21e7d6ac06556671c2663ce2879442c60230b32 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 30 Jan 2017 21:40:55 +0100 Subject: Make profile header scroll along with contents. AccountTimeline, Followers and Following are no longer nested inside a common parent (), instead they all embed --- .../components/features/account/index.jsx | 109 --------------------- .../account_timeline/components/header.jsx | 59 +++++++++++ .../containers/header_container.jsx | 45 +++++++++ .../components/features/account_timeline/index.jsx | 23 ++++- .../components/features/followers/index.jsx | 32 ++++-- .../components/features/following/index.jsx | 32 ++++-- .../features/status/components/action_bar.jsx | 6 +- .../components/features/status/index.jsx | 8 +- 8 files changed, 182 insertions(+), 132 deletions(-) delete mode 100644 app/assets/javascripts/components/features/account/index.jsx create mode 100644 app/assets/javascripts/components/features/account_timeline/components/header.jsx create mode 100644 app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx (limited to 'app/assets/javascripts/components/features') diff --git a/app/assets/javascripts/components/features/account/index.jsx b/app/assets/javascripts/components/features/account/index.jsx deleted file mode 100644 index 3a9b48f21..000000000 --- a/app/assets/javascripts/components/features/account/index.jsx +++ /dev/null @@ -1,109 +0,0 @@ -import { connect } from 'react-redux'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { - fetchAccount, - followAccount, - unfollowAccount, - blockAccount, - unblockAccount, - fetchAccountTimeline, - expandAccountTimeline -} from '../../actions/accounts'; -import { mentionCompose } from '../../actions/compose'; -import Header from './components/header'; -import { - getAccountTimeline, - makeGetAccount -} from '../../selectors'; -import LoadingIndicator from '../../components/loading_indicator'; -import ActionBar from './components/action_bar'; -import Column from '../ui/components/column'; -import ColumnBackButton from '../../components/column_back_button'; -import { isMobile } from '../../is_mobile' - -const makeMapStateToProps = () => { - const getAccount = makeGetAccount(); - - const mapStateToProps = (state, props) => ({ - account: getAccount(state, Number(props.params.accountId)), - me: state.getIn(['meta', 'me']) - }); - - return mapStateToProps; -}; - -const Account = React.createClass({ - - contextTypes: { - router: React.PropTypes.object - }, - - propTypes: { - params: React.PropTypes.object.isRequired, - dispatch: React.PropTypes.func.isRequired, - account: ImmutablePropTypes.map, - me: React.PropTypes.number.isRequired, - children: React.PropTypes.node - }, - - mixins: [PureRenderMixin], - - componentWillMount () { - this.props.dispatch(fetchAccount(Number(this.props.params.accountId))); - }, - - componentWillReceiveProps (nextProps) { - if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { - this.props.dispatch(fetchAccount(Number(nextProps.params.accountId))); - } - }, - - handleFollow () { - if (this.props.account.getIn(['relationship', 'following'])) { - this.props.dispatch(unfollowAccount(this.props.account.get('id'))); - } else { - this.props.dispatch(followAccount(this.props.account.get('id'))); - } - }, - - handleBlock () { - if (this.props.account.getIn(['relationship', 'blocking'])) { - this.props.dispatch(unblockAccount(this.props.account.get('id'))); - } else { - this.props.dispatch(blockAccount(this.props.account.get('id'))); - } - }, - - handleMention () { - this.props.dispatch(mentionCompose(this.props.account)); - if (isMobile(window.innerWidth)) { - this.context.router.push('/statuses/new'); - } - }, - - render () { - const { account, me } = this.props; - - if (account === null) { - return ( - - - - ); - } - - return ( - - -
- - - {this.props.children} - - ); - } - -}); - -export default connect(makeMapStateToProps)(Account); diff --git a/app/assets/javascripts/components/features/account_timeline/components/header.jsx b/app/assets/javascripts/components/features/account_timeline/components/header.jsx new file mode 100644 index 000000000..ff3e8af2d --- /dev/null +++ b/app/assets/javascripts/components/features/account_timeline/components/header.jsx @@ -0,0 +1,59 @@ +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import InnerHeader from '../../account/components/header'; +import ActionBar from '../../account/components/action_bar'; + +const Header = React.createClass({ + contextTypes: { + router: React.PropTypes.object + }, + + propTypes: { + account: ImmutablePropTypes.map.isRequired, + me: React.PropTypes.number.isRequired, + onFollow: React.PropTypes.func.isRequired, + onBlock: React.PropTypes.func.isRequired, + onMention: React.PropTypes.func.isRequired + }, + + mixins: [PureRenderMixin], + + handleFollow () { + this.props.onFollow(this.props.account); + }, + + handleBlock () { + this.props.onBlock(this.props.account); + }, + + handleMention () { + this.props.onMention(this.props.account, this.context.router); + }, + + render () { + const { account, me } = this.props; + + if (!account) { + return null; + } + + return ( +
+ + + +
+ ); + } +}); + +export default Header; diff --git a/app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx b/app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx new file mode 100644 index 000000000..dca826596 --- /dev/null +++ b/app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx @@ -0,0 +1,45 @@ +import { connect } from 'react-redux'; +import { makeGetAccount } from '../../../selectors'; +import Header from '../components/header'; +import { + followAccount, + unfollowAccount, + blockAccount, + unblockAccount +} from '../../../actions/accounts'; +import { mentionCompose } from '../../../actions/compose'; + +const makeMapStateToProps = () => { + const getAccount = makeGetAccount(); + + const mapStateToProps = (state, { accountId }) => ({ + account: getAccount(state, Number(accountId)), + me: state.getIn(['meta', 'me']) + }); + + return mapStateToProps; +}; + +const mapDispatchToProps = dispatch => ({ + onFollow (account) { + if (account.getIn(['relationship', 'following'])) { + dispatch(unfollowAccount(account.get('id'))); + } else { + dispatch(followAccount(account.get('id'))); + } + }, + + onBlock (account) { + if (account.getIn(['relationship', 'blocking'])) { + dispatch(unblockAccount(account.get('id'))); + } else { + dispatch(blockAccount(account.get('id'))); + } + }, + + onMention (account, router) { + dispatch(mentionCompose(account, router)); + } +}); + +export default connect(makeMapStateToProps, mapDispatchToProps)(Header); diff --git a/app/assets/javascripts/components/features/account_timeline/index.jsx b/app/assets/javascripts/components/features/account_timeline/index.jsx index 5c09839f7..6e2356dc1 100644 --- a/app/assets/javascripts/components/features/account_timeline/index.jsx +++ b/app/assets/javascripts/components/features/account_timeline/index.jsx @@ -7,6 +7,9 @@ import { } from '../../actions/accounts'; import StatusList from '../../components/status_list'; import LoadingIndicator from '../../components/loading_indicator'; +import Column from '../ui/components/column'; +import HeaderContainer from './containers/header_container'; +import ColumnBackButton from '../../components/column_back_button'; const mapStateToProps = (state, props) => ({ statusIds: state.getIn(['timelines', 'accounts_timelines', Number(props.params.accountId), 'items']), @@ -44,10 +47,26 @@ const AccountTimeline = React.createClass({ const { statusIds, isLoading, me } = this.props; if (!statusIds) { - return ; + return ( + + + + ); } - return + return ( + + + + } + statusIds={statusIds} + isLoading={isLoading} + me={me} + onScrollToBottom={this.handleScrollToBottom} + /> + + ); } }); diff --git a/app/assets/javascripts/components/features/followers/index.jsx b/app/assets/javascripts/components/features/followers/index.jsx index 38755d862..b96516813 100644 --- a/app/assets/javascripts/components/features/followers/index.jsx +++ b/app/assets/javascripts/components/features/followers/index.jsx @@ -8,6 +8,10 @@ import { } from '../../actions/accounts'; import { ScrollContainer } from 'react-router-scroll'; import AccountContainer from '../../containers/account_container'; +import Column from '../ui/components/column'; +import HeaderContainer from '../account_timeline/containers/header_container'; +import LoadMore from '../../components/load_more'; +import ColumnBackButton from '../../components/column_back_button'; const mapStateToProps = (state, props) => ({ accountIds: state.getIn(['user_lists', 'followers', Number(props.params.accountId), 'items']) @@ -41,21 +45,35 @@ const Followers = React.createClass({ } }, + handleLoadMore (e) { + e.preventDefault(); + this.props.dispatch(expandFollowing(Number(this.props.params.accountId))); + }, + render () { const { accountIds } = this.props; if (!accountIds) { - return ; + return ( + + + + ); } return ( - -
-
- {accountIds.map(id => )} + + + +
+
+ + {accountIds.map(id => )} + +
-
- + + ); } diff --git a/app/assets/javascripts/components/features/following/index.jsx b/app/assets/javascripts/components/features/following/index.jsx index c4ec7bb67..559911a7d 100644 --- a/app/assets/javascripts/components/features/following/index.jsx +++ b/app/assets/javascripts/components/features/following/index.jsx @@ -8,6 +8,10 @@ import { } from '../../actions/accounts'; import { ScrollContainer } from 'react-router-scroll'; import AccountContainer from '../../containers/account_container'; +import Column from '../ui/components/column'; +import HeaderContainer from '../account_timeline/containers/header_container'; +import LoadMore from '../../components/load_more'; +import ColumnBackButton from '../../components/column_back_button'; const mapStateToProps = (state, props) => ({ accountIds: state.getIn(['user_lists', 'following', Number(props.params.accountId), 'items']) @@ -41,21 +45,35 @@ const Following = React.createClass({ } }, + handleLoadMore (e) { + e.preventDefault(); + this.props.dispatch(expandFollowing(Number(this.props.params.accountId))); + }, + render () { const { accountIds } = this.props; if (!accountIds) { - return ; + return ( + + + + ); } return ( - -
-
- {accountIds.map(id => )} + + + +
+
+ + {accountIds.map(id => )} + +
-
- + + ); } diff --git a/app/assets/javascripts/components/features/status/components/action_bar.jsx b/app/assets/javascripts/components/features/status/components/action_bar.jsx index 3f8a0457d..2f152e919 100644 --- a/app/assets/javascripts/components/features/status/components/action_bar.jsx +++ b/app/assets/javascripts/components/features/status/components/action_bar.jsx @@ -14,6 +14,10 @@ const messages = defineMessages({ const ActionBar = React.createClass({ + contextTypes: { + router: React.PropTypes.object + }, + propTypes: { status: ImmutablePropTypes.map.isRequired, onReply: React.PropTypes.func.isRequired, @@ -43,7 +47,7 @@ const ActionBar = React.createClass({ }, handleMentionClick () { - this.props.onMention(this.props.status.get('account')); + this.props.onMention(this.props.status.get('account'), this.context.router); }, render () { diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx index 389549849..993c649d2 100644 --- a/app/assets/javascripts/components/features/status/index.jsx +++ b/app/assets/javascripts/components/features/status/index.jsx @@ -80,12 +80,8 @@ const Status = React.createClass({ this.props.dispatch(deleteStatus(status.get('id'))); }, - handleMentionClick (account) { - this.props.dispatch(mentionCompose(account)); - - if (isMobile(window.innerWidth)) { - this.context.router.push('/statuses/new'); - } + handleMentionClick (account, router) { + this.props.dispatch(mentionCompose(account, router)); }, handleOpenMedia (url) { -- cgit