From f8f40f15dafca65dc07d5c5c19fb9a9dc3473dd6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 24 Oct 2016 17:11:02 +0200 Subject: Move status components inside individual containers. We still need to select all statuses/accounts to assemble, but at least lists don't have to be re-rendered all the time now. Also add "mention" dropdown option --- .../features/account/components/action_bar.jsx | 19 ++++---- .../components/features/account/index.jsx | 7 ++- .../components/features/account_timeline/index.jsx | 46 ++++-------------- .../features/status/components/action_bar.jsx | 3 ++ .../components/features/status/index.jsx | 55 +++++++++++++++------- .../ui/containers/compose_form_container.jsx | 22 +++++---- .../ui/containers/status_list_container.jsx | 48 ++----------------- 7 files changed, 86 insertions(+), 114 deletions(-) (limited to 'app/assets/javascripts/components/features') 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 0f26b1e5a..195b143af 100644 --- a/app/assets/javascripts/components/features/account/components/action_bar.jsx +++ b/app/assets/javascripts/components/features/account/components/action_bar.jsx @@ -8,7 +8,8 @@ const ActionBar = React.createClass({ account: ImmutablePropTypes.map.isRequired, me: React.PropTypes.number.isRequired, onFollow: React.PropTypes.func.isRequired, - onBlock: React.PropTypes.func.isRequired + onBlock: React.PropTypes.func.isRequired, + onMention: React.PropTypes.func.isRequired }, mixins: [PureRenderMixin], @@ -18,6 +19,8 @@ const ActionBar = React.createClass({ let menu = []; + menu.push({ text: 'Mention', action: this.props.onMention }); + if (account.get('id') === me) { menu.push({ text: 'Edit profile', href: '/settings/profile' }); } else if (account.getIn(['relationship', 'blocking'])) { @@ -32,26 +35,26 @@ const ActionBar = React.createClass({ return (
+
+ +
+
-
+
Posts {account.get('statuses_count')}
-
+
Follows {account.get('following_count')}
-
+
Followers {account.get('followers_count')}
- -
- -
); }, diff --git a/app/assets/javascripts/components/features/account/index.jsx b/app/assets/javascripts/components/features/account/index.jsx index 83770eb74..76d69f751 100644 --- a/app/assets/javascripts/components/features/account/index.jsx +++ b/app/assets/javascripts/components/features/account/index.jsx @@ -10,6 +10,7 @@ import { fetchAccountTimeline, expandAccountTimeline } from '../../actions/accounts'; +import { mentionCompose } from '../../actions/compose'; import Header from './components/header'; import { getAccountTimeline, @@ -62,6 +63,10 @@ const Account = React.createClass({ } }, + handleMention () { + this.props.dispatch(mentionCompose(this.props.account)); + }, + render () { const { account, me } = this.props; @@ -78,7 +83,7 @@ const Account = React.createClass({
- + {this.props.children} diff --git a/app/assets/javascripts/components/features/account_timeline/index.jsx b/app/assets/javascripts/components/features/account_timeline/index.jsx index 0b3d641d5..f79570361 100644 --- a/app/assets/javascripts/components/features/account_timeline/index.jsx +++ b/app/assets/javascripts/components/features/account_timeline/index.jsx @@ -1,23 +1,15 @@ import { connect } from 'react-redux'; import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { getAccountTimeline } from '../../selectors'; import { fetchAccountTimeline, expandAccountTimeline } from '../../actions/accounts'; -import { deleteStatus } from '../../actions/statuses'; -import { replyCompose } from '../../actions/compose'; -import { - favourite, - reblog, - unreblog, - unfavourite -} from '../../actions/interactions'; import StatusList from '../../components/status_list'; +import LoadingIndicator from '../../components/loading_indicator'; const mapStateToProps = (state, props) => ({ - statuses: getAccountTimeline(state, Number(props.params.accountId)), + statusIds: state.getIn(['timelines', 'accounts_timelines', Number(props.params.accountId)]), me: state.getIn(['timelines', 'me']) }); @@ -26,7 +18,7 @@ const AccountTimeline = React.createClass({ propTypes: { params: React.PropTypes.object.isRequired, dispatch: React.PropTypes.func.isRequired, - statuses: ImmutablePropTypes.list + statusIds: ImmutablePropTypes.list }, mixins: [PureRenderMixin], @@ -41,38 +33,18 @@ const AccountTimeline = React.createClass({ } }, - handleReply (status) { - this.props.dispatch(replyCompose(status)); - }, - - handleReblog (status) { - if (status.get('reblogged')) { - this.props.dispatch(unreblog(status)); - } else { - this.props.dispatch(reblog(status)); - } - }, - - handleFavourite (status) { - if (status.get('favourited')) { - this.props.dispatch(unfavourite(status)); - } else { - this.props.dispatch(favourite(status)); - } - }, - - handleDelete (status) { - this.props.dispatch(deleteStatus(status.get('id'))); - }, - handleScrollToBottom () { this.props.dispatch(expandAccountTimeline(Number(this.props.params.accountId))); }, render () { - const { statuses, me } = this.props; + const { statusIds, me } = this.props; + + if (!statusIds) { + return ; + } - return + return } }); 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 6d6aa87fc..d0cae4557 100644 --- a/app/assets/javascripts/components/features/status/components/action_bar.jsx +++ b/app/assets/javascripts/components/features/status/components/action_bar.jsx @@ -11,6 +11,7 @@ const ActionBar = React.createClass({ onReblog: React.PropTypes.func.isRequired, onFavourite: React.PropTypes.func.isRequired, onDelete: React.PropTypes.func.isRequired, + onMention: React.PropTypes.func.isRequired, me: React.PropTypes.number.isRequired }, @@ -23,6 +24,8 @@ const ActionBar = React.createClass({ if (me === status.getIn(['account', 'id'])) { menu.push({ text: 'Delete', action: () => this.props.onDelete(status) }); + } else { + menu.push({ text: 'Mention', action: () => this.props.onMention(status.get('account')) }); } return ( diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx index c51fb5d31..f4ca8ff92 100644 --- a/app/assets/javascripts/components/features/status/index.jsx +++ b/app/assets/javascripts/components/features/status/index.jsx @@ -9,22 +9,32 @@ import DetailedStatus from './components/detailed_status'; import ActionBar from './components/action_bar'; import Column from '../ui/components/column'; import { favourite, reblog } from '../../actions/interactions'; -import { replyCompose } from '../../actions/compose'; +import { + replyCompose, + mentionCompose +} from '../../actions/compose'; import { deleteStatus } from '../../actions/statuses'; import { - getStatus, + makeGetStatus, getStatusAncestors, getStatusDescendants } from '../../selectors'; import { ScrollContainer } from 'react-router-scroll'; import ColumnBackButton from '../../components/column_back_button'; +import StatusContainer from '../../containers/status_container'; -const mapStateToProps = (state, props) => ({ - status: getStatus(state, Number(props.params.statusId)), - ancestors: getStatusAncestors(state, Number(props.params.statusId)), - descendants: getStatusDescendants(state, Number(props.params.statusId)), - me: state.getIn(['timelines', 'me']) -}); +const makeMapStateToProps = () => { + const getStatus = makeGetStatus(); + + const mapStateToProps = (state, props) => ({ + status: getStatus(state, Number(props.params.statusId)), + ancestorsIds: state.getIn(['timelines', 'ancestors', Number(props.params.statusId)]), + descendantsIds: state.getIn(['timelines', 'descendants', Number(props.params.statusId)]), + me: state.getIn(['timelines', 'me']) + }); + + return mapStateToProps; +}; const Status = React.createClass({ @@ -32,8 +42,8 @@ const Status = React.createClass({ params: React.PropTypes.object.isRequired, dispatch: React.PropTypes.func.isRequired, status: ImmutablePropTypes.map, - ancestors: ImmutablePropTypes.orderedSet.isRequired, - descendants: ImmutablePropTypes.orderedSet.isRequired + ancestorsIds: ImmutablePropTypes.orderedSet, + descendantsIds: ImmutablePropTypes.orderedSet }, mixins: [PureRenderMixin], @@ -64,12 +74,17 @@ const Status = React.createClass({ this.props.dispatch(deleteStatus(status.get('id'))); }, + handleMentionClick (account) { + this.props.dispatch(mentionCompose(account)); + }, + renderChildren (list) { - return list.map(s => ); + return list.map(id => ); }, render () { - const { status, ancestors, descendants, me } = this.props; + let ancestors, descendants; + const { status, ancestorsIds, descendantsIds, me } = this.props; if (status === null) { return ( @@ -81,18 +96,26 @@ const Status = React.createClass({ const account = status.get('account'); + if (ancestorsIds) { + ancestors =
{this.renderChildren(ancestorsIds)}
; + } + + if (descendantsIds) { + descendants =
{this.renderChildren(descendantsIds)}
; + } + return (
-
{this.renderChildren(ancestors)}
+ {ancestors} - + -
{this.renderChildren(descendants)}
+ {descendants}
@@ -101,4 +124,4 @@ const Status = React.createClass({ }); -export default connect(mapStateToProps)(Status); +export default connect(makeMapStateToProps)(Status); diff --git a/app/assets/javascripts/components/features/ui/containers/compose_form_container.jsx b/app/assets/javascripts/components/features/ui/containers/compose_form_container.jsx index 747eb9691..163d6fa20 100644 --- a/app/assets/javascripts/components/features/ui/containers/compose_form_container.jsx +++ b/app/assets/javascripts/components/features/ui/containers/compose_form_container.jsx @@ -1,15 +1,21 @@ import { connect } from 'react-redux'; import ComposeForm from '../components/compose_form'; import { changeCompose, submitCompose, cancelReplyCompose } from '../../../actions/compose'; -import { getStatus } from '../../../selectors'; +import { makeGetStatus } from '../../../selectors'; -const mapStateToProps = function (state, props) { - return { - text: state.getIn(['compose', 'text']), - is_submitting: state.getIn(['compose', 'is_submitting']), - is_uploading: state.getIn(['compose', 'is_uploading']), - in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to'])) +const makeMapStateToProps = () => { + const getStatus = makeGetStatus(); + + const mapStateToProps = function (state, props) { + return { + text: state.getIn(['compose', 'text']), + is_submitting: state.getIn(['compose', 'is_submitting']), + is_uploading: state.getIn(['compose', 'is_uploading']), + in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to'])) + }; }; + + return mapStateToProps; }; const mapDispatchToProps = function (dispatch) { @@ -28,4 +34,4 @@ const mapDispatchToProps = function (dispatch) { } }; -export default connect(mapStateToProps, mapDispatchToProps)(ComposeForm); +export default connect(makeMapStateToProps, mapDispatchToProps)(ComposeForm); diff --git a/app/assets/javascripts/components/features/ui/containers/status_list_container.jsx b/app/assets/javascripts/components/features/ui/containers/status_list_container.jsx index 045cc59d1..213435a06 100644 --- a/app/assets/javascripts/components/features/ui/containers/status_list_container.jsx +++ b/app/assets/javascripts/components/features/ui/containers/status_list_container.jsx @@ -1,57 +1,17 @@ import { connect } from 'react-redux'; import StatusList from '../../../components/status_list'; -import { replyCompose } from '../../../actions/compose'; -import { - reblog, - favourite, - unreblog, - unfavourite -} from '../../../actions/interactions'; import { expandTimeline } from '../../../actions/timelines'; -import { makeGetTimeline } from '../../../selectors'; -import { deleteStatus } from '../../../actions/statuses'; -const makeMapStateToProps = () => { - const getTimeline = makeGetTimeline(); - - const mapStateToProps = (state, props) => ({ - statuses: getTimeline(state, props.type), - me: state.getIn(['timelines', 'me']) - }); - - return mapStateToProps; -}; +const mapStateToProps = (state, props) => ({ + statusIds: state.getIn(['timelines', props.type]) +}); const mapDispatchToProps = function (dispatch, props) { return { - onReply (status) { - dispatch(replyCompose(status)); - }, - - onFavourite (status) { - if (status.get('favourited')) { - dispatch(unfavourite(status)); - } else { - dispatch(favourite(status)); - } - }, - - onReblog (status) { - if (status.get('reblogged')) { - dispatch(unreblog(status)); - } else { - dispatch(reblog(status)); - } - }, - onScrollToBottom () { dispatch(expandTimeline(props.type)); - }, - - onDelete (status) { - dispatch(deleteStatus(status.get('id'))); } }; }; -export default connect(makeMapStateToProps, mapDispatchToProps)(StatusList); +export default connect(mapStateToProps, mapDispatchToProps)(StatusList); -- cgit