about summary refs log tree commit diff
path: root/app/assets/javascripts/components/features
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2017-01-30 21:40:55 +0100
committerEugen Rochko <eugen@zeonfederated.com>2017-01-30 21:44:11 +0100
commitf21e7d6ac06556671c2663ce2879442c60230b32 (patch)
tree68260b8383038daf6f315093064a2dbdd7b3944b /app/assets/javascripts/components/features
parenta2a85e85491110461cbc938abd0f2687f0e51612 (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')
-rw-r--r--app/assets/javascripts/components/features/account/index.jsx109
-rw-r--r--app/assets/javascripts/components/features/account_timeline/components/header.jsx59
-rw-r--r--app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx45
-rw-r--r--app/assets/javascripts/components/features/account_timeline/index.jsx23
-rw-r--r--app/assets/javascripts/components/features/followers/index.jsx32
-rw-r--r--app/assets/javascripts/components/features/following/index.jsx32
-rw-r--r--app/assets/javascripts/components/features/status/components/action_bar.jsx6
-rw-r--r--app/assets/javascripts/components/features/status/index.jsx8
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) {