PageComments.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import Comment from './PageComment/Comment';
  4. import DeleteCommentModal from './PageComment/DeleteCommentModal';
  5. /**
  6. * Load data of comments and render the list of <Comment />
  7. *
  8. * @author Yuki Takei <yuki@weseek.co.jp>
  9. *
  10. * @export
  11. * @class PageComments
  12. * @extends {React.Component}
  13. */
  14. export default class PageComments extends React.Component {
  15. constructor(props) {
  16. super(props);
  17. this.state = {
  18. comments: [],
  19. // for deleting comment
  20. commentToDelete: undefined,
  21. isDeleteConfirmModalShown: false,
  22. errorMessageForDeleting: undefined,
  23. };
  24. this.init = this.init.bind(this);
  25. this.confirmToDeleteComment = this.confirmToDeleteComment.bind(this);
  26. this.deleteComment = this.deleteComment.bind(this);
  27. this.showDeleteConfirmModal = this.showDeleteConfirmModal.bind(this);
  28. this.closeDeleteConfirmModal = this.closeDeleteConfirmModal.bind(this);
  29. }
  30. componentWillMount() {
  31. const pageId = this.props.pageId;
  32. if (pageId) {
  33. this.init();
  34. }
  35. }
  36. init() {
  37. if (!this.props.pageId) {
  38. return ;
  39. }
  40. const pageId = this.props.pageId;
  41. this.props.crowi.apiGet('/comments.get', {page_id: pageId})
  42. .then(res => {
  43. if (res.ok) {
  44. this.setState({comments: res.comments});
  45. }
  46. }).catch(err => {
  47. });
  48. }
  49. confirmToDeleteComment(comment) {
  50. this.setState({commentToDelete: comment});
  51. this.showDeleteConfirmModal();
  52. }
  53. deleteComment() {
  54. const comment = this.state.commentToDelete;
  55. this.props.crowi.apiPost('/comments.remove', {comment_id: comment._id})
  56. .then(res => {
  57. if (res.ok) {
  58. this.findAndSplice(comment);
  59. }
  60. this.closeDeleteConfirmModal();
  61. }).catch(err => {
  62. this.setState({errorMessageForDeleting: err.message});
  63. });
  64. }
  65. findAndSplice(comment) {
  66. let comments = this.state.comments;
  67. const index = comments.indexOf(comment);
  68. if (index < 0) {
  69. return;
  70. }
  71. comments.splice(index, 1);
  72. this.setState({comments});
  73. }
  74. showDeleteConfirmModal() {
  75. this.setState({isDeleteConfirmModalShown: true});
  76. }
  77. closeDeleteConfirmModal() {
  78. this.setState({
  79. commentToDelete: undefined,
  80. isDeleteConfirmModalShown: false,
  81. errorMessageForDeleting: undefined,
  82. });
  83. }
  84. /**
  85. * generate Elements of Comment
  86. *
  87. * @param {any} comments Array of Comment Model Obj
  88. *
  89. * @memberOf PageComments
  90. */
  91. generateCommentElements(comments) {
  92. return comments.map((comment) => {
  93. return (
  94. <Comment key={comment._id} comment={comment}
  95. currentUserId={this.props.crowi.me}
  96. currentRevisionId={this.props.revisionId}
  97. deleteBtnClicked={this.confirmToDeleteComment} />
  98. );
  99. });
  100. }
  101. render() {
  102. let currentComments = [];
  103. let newerComments = [];
  104. let olderComments = [];
  105. // divide by revisionId and createdAt
  106. const revisionId = this.props.revisionId;
  107. const revisionCreatedAt = this.props.revisionCreatedAt;
  108. this.state.comments.forEach((comment) => {
  109. if (comment.revision == revisionId) {
  110. currentComments.push(comment);
  111. }
  112. else if (Date.parse(comment.createdAt)/1000 > revisionCreatedAt) {
  113. newerComments.push(comment);
  114. }
  115. else {
  116. olderComments.push(comment);
  117. }
  118. });
  119. // generate elements
  120. let currentElements = this.generateCommentElements(currentComments);
  121. let newerElements = this.generateCommentElements(newerComments);
  122. let olderElements = this.generateCommentElements(olderComments);
  123. let toggleNewer = (newerElements.length === 0)
  124. ? <div></div>
  125. : (
  126. <a className="page-comments-list-toggle-newer text-center" data-toggle="collapse" href="#page-comments-list-newer">
  127. <i className="fa fa-angle-double-up"></i> Comments for Newer Revision <i className="fa fa-angle-double-up"></i>
  128. </a>
  129. )
  130. let toggleOlder = (olderElements.length === 0)
  131. ? <div></div>
  132. : (
  133. <a className="page-comments-list-toggle-older text-center" data-toggle="collapse" href="#page-comments-list-older">
  134. <i className="fa fa-angle-double-down"></i> Comments for Older Revision <i className="fa fa-angle-double-down"></i>
  135. </a>
  136. )
  137. return (
  138. <div>
  139. <div className="page-comments-list-newer collapse" id="page-comments-list-newer">
  140. {newerElements}
  141. </div>
  142. {toggleNewer}
  143. <div className="page-comments-list-current" id="page-comments-list-current">
  144. {currentElements}
  145. </div>
  146. {toggleOlder}
  147. <div className="page-comments-list-older collapse in" id="page-comments-list-older">
  148. {olderElements}
  149. </div>
  150. <DeleteCommentModal
  151. isShown={this.state.isDeleteConfirmModalShown}
  152. comment={this.state.commentToDelete}
  153. errorMessage={this.state.errorMessageForDeleting}
  154. cancel={this.closeDeleteConfirmModal}
  155. confirmedToDelete={this.deleteComment}
  156. />
  157. </div>
  158. );
  159. }
  160. }
  161. PageComments.propTypes = {
  162. pageId: PropTypes.string,
  163. revisionId: PropTypes.string,
  164. revisionCreatedAt: PropTypes.number,
  165. crowi: PropTypes.object.isRequired,
  166. };