diff options
author | Eugen Rochko <eugen@zeonfederated.com> | 2017-01-30 21:40:55 +0100 |
---|---|---|
committer | Eugen Rochko <eugen@zeonfederated.com> | 2017-01-30 21:44:11 +0100 |
commit | f21e7d6ac06556671c2663ce2879442c60230b32 (patch) | |
tree | 68260b8383038daf6f315093064a2dbdd7b3944b /app/assets/javascripts/components/features | |
parent | a2a85e85491110461cbc938abd0f2687f0e51612 (diff) |
Make profile header scroll along with contents. AccountTimeline, Followers and Following are no longer
nested inside a common parent (<Account>), instead they all embed <HeaderContainer />
Diffstat (limited to 'app/assets/javascripts/components/features')
8 files changed, 182 insertions, 132 deletions
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 ( - <Column> - <LoadingIndicator /> - </Column> - ); - } - - return ( - <Column> - <ColumnBackButton /> - <Header account={account} me={me} onFollow={this.handleFollow} /> - <ActionBar account={account} me={me} onBlock={this.handleBlock} onMention={this.handleMention} /> - - {this.props.children} - </Column> - ); - } - -}); - -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 ( + <div> + <InnerHeader + account={account} + me={me} + onFollow={this.handleFollow} + /> + + <ActionBar + account={account} + me={me} + onBlock={this.handleBlock} + onMention={this.handleMention} + /> + </div> + ); + } +}); + +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 <LoadingIndicator />; + return ( + <Column> + <LoadingIndicator /> + </Column> + ); } - return <StatusList statusIds={statusIds} isLoading={isLoading} me={me} onScrollToBottom={this.handleScrollToBottom} /> + return ( + <Column> + <ColumnBackButton /> + + <StatusList + prepend={<HeaderContainer accountId={this.props.params.accountId} />} + statusIds={statusIds} + isLoading={isLoading} + me={me} + onScrollToBottom={this.handleScrollToBottom} + /> + </Column> + ); } }); 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 <LoadingIndicator />; + return ( + <Column> + <LoadingIndicator /> + </Column> + ); } return ( - <ScrollContainer scrollKey='followers'> - <div className='scrollable' onScroll={this.handleScroll}> - <div> - {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)} + <Column> + <ColumnBackButton /> + <ScrollContainer scrollKey='followers'> + <div className='scrollable' onScroll={this.handleScroll}> + <div> + <HeaderContainer accountId={this.props.params.accountId} /> + {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)} + <LoadMore onClick={this.handleLoadMore} /> + </div> </div> - </div> - </ScrollContainer> + </ScrollContainer> + </Column> ); } 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 <LoadingIndicator />; + return ( + <Column> + <LoadingIndicator /> + </Column> + ); } return ( - <ScrollContainer scrollKey='following'> - <div className='scrollable' onScroll={this.handleScroll}> - <div> - {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)} + <Column> + <ColumnBackButton /> + <ScrollContainer scrollKey='following'> + <div className='scrollable' onScroll={this.handleScroll}> + <div> + <HeaderContainer accountId={this.props.params.accountId} /> + {accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)} + <LoadMore onClick={this.handleLoadMore} /> + </div> </div> - </div> - </ScrollContainer> + </ScrollContainer> + </Column> ); } 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) { |