You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.2 KiB

  1. import { connect } from 'react-redux';
  2. import PureRenderMixin from 'react-addons-pure-render-mixin';
  3. import ImmutablePropTypes from 'react-immutable-proptypes';
  4. import { fetchStatus } from '../../actions/statuses';
  5. import Immutable from 'immutable';
  6. import EmbeddedStatus from '../../components/status';
  7. import LoadingIndicator from '../../components/loading_indicator';
  8. import DetailedStatus from './components/detailed_status';
  9. import ActionBar from './components/action_bar';
  10. import Column from '../ui/components/column';
  11. import { favourite, reblog } from '../../actions/interactions';
  12. import { replyCompose } from '../../actions/compose';
  13. import { selectStatus } from '../../reducers/timelines';
  14. function selectStatuses(state, ids) {
  15. return ids.map(id => selectStatus(state, id)).filterNot(status => status === null);
  16. };
  17. const mapStateToProps = (state, props) => ({
  18. status: selectStatus(state, Number(props.params.statusId)),
  19. ancestors: selectStatuses(state, state.getIn(['timelines', 'ancestors', Number(props.params.statusId)], Immutable.OrderedSet())),
  20. descendants: selectStatuses(state, state.getIn(['timelines', 'descendants', Number(props.params.statusId)], Immutable.OrderedSet())),
  21. me: state.getIn(['timelines', 'me'])
  22. });
  23. const Status = React.createClass({
  24. propTypes: {
  25. params: React.PropTypes.object.isRequired,
  26. dispatch: React.PropTypes.func.isRequired,
  27. status: ImmutablePropTypes.map,
  28. ancestors: ImmutablePropTypes.orderedSet.isRequired,
  29. descendants: ImmutablePropTypes.orderedSet.isRequired
  30. },
  31. mixins: [PureRenderMixin],
  32. componentWillMount () {
  33. this.props.dispatch(fetchStatus(Number(this.props.params.statusId)));
  34. },
  35. componentWillReceiveProps (nextProps) {
  36. if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
  37. this.props.dispatch(fetchStatus(Number(nextProps.params.statusId)));
  38. }
  39. },
  40. handleFavouriteClick (status) {
  41. this.props.dispatch(favourite(status));
  42. },
  43. handleReplyClick (status) {
  44. this.props.dispatch(replyCompose(status));
  45. },
  46. handleReblogClick (status) {
  47. this.props.dispatch(reblog(status));
  48. },
  49. renderChildren (list) {
  50. return list.map(s => <EmbeddedStatus status={s} me={this.props.me} key={s.get('id')} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} />);
  51. },
  52. render () {
  53. const { status, ancestors, descendants, me } = this.props;
  54. if (status === null) {
  55. return (
  56. <Column>
  57. <LoadingIndicator />
  58. </Column>
  59. );
  60. }
  61. const account = status.get('account');
  62. return (
  63. <Column>
  64. <div style={{ overflowY: 'scroll', flex: '1 1 auto' }} className='scrollable'>
  65. <div>{this.renderChildren(ancestors)}</div>
  66. <DetailedStatus status={status} me={me} />
  67. <ActionBar status={status} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} />
  68. <div>{this.renderChildren(descendants)}</div>
  69. </div>
  70. </Column>
  71. );
  72. }
  73. });
  74. export default connect(mapStateToProps)(Status);