route.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import React from 'react';
  2. import { Poll } from 'misago/components/poll'; // jshint ignore:line
  3. import PostsList from 'misago/components/posts-list'; // jshint ignore:line
  4. import Header from './header'; // jshint ignore:line
  5. import Paginator from './paginator'; // jshint ignore:line
  6. import ReplyButton from './reply-button'; // jshint ignore:line
  7. import Subscription from './subscription'; // jshint ignore:line
  8. import ToolbarTop from './toolbar-top'; // jshint ignore:line
  9. import PostsModeration from './moderation/posts'; // jshint ignore:line
  10. import * as poll from 'misago/reducers/poll'; // jshint ignore:line
  11. import * as posts from 'misago/reducers/posts';
  12. import * as thread from 'misago/reducers/thread'; // jshint ignore:line
  13. import ajax from 'misago/services/ajax';
  14. import polls from 'misago/services/polls';
  15. import snackbar from 'misago/services/snackbar';
  16. import posting from 'misago/services/posting'; // jshint ignore:line
  17. import store from 'misago/services/store';
  18. import title from 'misago/services/page-title';
  19. export default class extends React.Component {
  20. componentDidMount() {
  21. if (this.shouldFetchData()) {
  22. this.fetchData();
  23. this.setPageTitle();
  24. }
  25. this.startPollingApi();
  26. }
  27. componentDidUpdate() {
  28. if (this.shouldFetchData()) {
  29. this.fetchData();
  30. this.startPollingApi();
  31. this.setPageTitle();
  32. }
  33. }
  34. componentWillUnmount() {
  35. this.stopPollingApi();
  36. }
  37. shouldFetchData() {
  38. if (this.props.posts.isLoaded) {
  39. const page = (this.props.params.page || 1) * 1;
  40. return page != this.props.posts.page;
  41. } else {
  42. return false;
  43. }
  44. }
  45. fetchData() {
  46. store.dispatch(posts.unload());
  47. ajax.get(this.props.thread.api.posts.index, {
  48. page: this.props.params.page || 1
  49. }, 'posts').then((data) => {
  50. this.update(data);
  51. }, (rejection) => {
  52. snackbar.apiError(rejection);
  53. });
  54. }
  55. startPollingApi() {
  56. polls.start({
  57. poll: 'thread-posts',
  58. url: this.props.thread.api.posts.index,
  59. data: {
  60. page: this.props.params.page || 1
  61. },
  62. update: this.update,
  63. frequency: 120 * 1000,
  64. delayed: true
  65. });
  66. }
  67. stopPollingApi() {
  68. polls.stop('thread-posts');
  69. }
  70. setPageTitle() {
  71. title.set({
  72. title: this.props.thread.title,
  73. page: (this.props.params.page || 1) * 1
  74. });
  75. }
  76. /* jshint ignore:start */
  77. update = (data) => {
  78. store.dispatch(thread.replace(data));
  79. store.dispatch(posts.load(data.post_set));
  80. if (data.poll) {
  81. store.dispatch(poll.replace(data.poll));
  82. }
  83. this.setPageTitle();
  84. };
  85. openReplyForm = () => {
  86. posting.open({
  87. mode: 'REPLY',
  88. config: this.props.thread.api.editor,
  89. submit: this.props.thread.api.posts.index
  90. });
  91. };
  92. /* jshint ignore:end */
  93. render() {
  94. /* jshint ignore:start */
  95. return <div className="page page-thread">
  96. <Header {...this.props} />
  97. <div className="container">
  98. <ToolbarTop openReplyForm={this.openReplyForm} {...this.props} />
  99. <Poll
  100. poll={this.props.poll}
  101. thread={this.props.thread}
  102. user={this.props.user}
  103. />
  104. <PostsList {...this.props} />
  105. <div className="toolbar-bottom">
  106. <Paginator {...this.props} />
  107. <Reply onClick={this.openReplyForm} thread={this.props.thread} />
  108. <Subscription className="toolbar-right dropup" {...this.props} />
  109. <PostsModeration {...this.props} />
  110. <div className="clear-fix" />
  111. </div>
  112. </div>
  113. </div>;
  114. /* jshint ignore:end */
  115. }
  116. }
  117. export function Reply(props) {
  118. if (props.thread.acl.can_reply) {
  119. /* jshint ignore:start */
  120. return (
  121. <ReplyButton
  122. className="btn btn-success toolbar-right"
  123. onClick={props.onClick}
  124. />
  125. );
  126. /* jshint ignore:end */
  127. } else {
  128. return null;
  129. }
  130. }