post-likes.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // jshint ignore:start
  2. import React from 'react';
  3. import moment from 'moment';
  4. import Message from 'misago/components/modal-message';
  5. import Loader from 'misago/components/modal-loader';
  6. import ajax from 'misago/services/ajax';
  7. export default class extends React.Component {
  8. constructor(props) {
  9. super(props);
  10. this.state = {
  11. isReady: false,
  12. error: null,
  13. likes: []
  14. };
  15. }
  16. componentDidMount() {
  17. ajax.get(this.props.post.api.likes).then((data) => {
  18. this.setState({
  19. isReady: true,
  20. likes: data.map(hydrateLike)
  21. });
  22. }, (rejection) => {
  23. this.setState({
  24. isReady: true,
  25. error: rejection.detail
  26. });
  27. });
  28. };
  29. render() {
  30. if (this.state.error) {
  31. return (
  32. <ModalDialog className="modal-message">
  33. <Message
  34. message={this.state.error}
  35. />
  36. </ModalDialog>
  37. );
  38. } else if (this.state.isReady) {
  39. if (this.state.likes.length) {
  40. return (
  41. <ModalDialog>
  42. <LikesList
  43. likes={this.state.likes}
  44. />
  45. </ModalDialog>
  46. );
  47. }
  48. return (
  49. <ModalDialog className="modal-message">
  50. <Message
  51. message={gettext("No users have liked this post.")}
  52. />
  53. </ModalDialog>
  54. );
  55. }
  56. return (
  57. <ModalDialog>
  58. <Loader />
  59. </ModalDialog>
  60. );
  61. }
  62. }
  63. export function hydrateLike(data) {
  64. return Object.assign({}, data, {
  65. liked_on: moment(data.liked_on)
  66. });
  67. }
  68. export function ModalDialog(props) {
  69. return (
  70. <div
  71. className={"modal-dialog modal-sm " + (props.className || '')}
  72. role="document"
  73. >
  74. <div className="modal-content">
  75. <div className="modal-header">
  76. <button
  77. aria-label={gettext("Close")}
  78. className="close"
  79. data-dismiss="modal"
  80. type="button"
  81. >
  82. <span aria-hidden="true">&times;</span>
  83. </button>
  84. <h4 className="modal-title">{gettext("Post Likes")}</h4>
  85. </div>
  86. {props.children}
  87. </div>
  88. </div>
  89. )
  90. }
  91. export function LikesList(props) {
  92. return (
  93. <table className="table">
  94. <tbody>
  95. {props.likes.map((like) => {
  96. return (
  97. <LikeDetails
  98. key={like.id}
  99. {...like}
  100. />
  101. );
  102. })}
  103. </tbody>
  104. </table>
  105. );
  106. }
  107. export function LikeDetails(props) {
  108. if (props.url) {
  109. return (
  110. <tr>
  111. <td className="col-md-6">
  112. <a
  113. className="item-title"
  114. href={props.url}
  115. >
  116. {props.username}
  117. </a>
  118. </td>
  119. <LikeDate likedOn={props.liked_on} />
  120. </tr>
  121. );
  122. }
  123. return (
  124. <tr>
  125. <td className="col-md-6">
  126. <strong>{props.username}</strong>
  127. </td>
  128. <LikeDate likedOn={props.liked_on} />
  129. </tr>
  130. );
  131. }
  132. export function LikeDate(props) {
  133. return (
  134. <td className="col-md-6">
  135. <abbr
  136. className="text-muted"
  137. title={props.likedOn.format('LLL')}
  138. >
  139. {props.likedOn.fromNow()}
  140. </abbr>
  141. </td>
  142. );
  143. }