index.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // jshint ignore:start
  2. import React from 'react';
  3. import Diff from './diff';
  4. import Footer from './footer';
  5. import Toolbar from './toolbar';
  6. import { hydrateEdit } from './utils';
  7. import Message from 'misago/components/modal-message';
  8. import Loader from 'misago/components/modal-loader';
  9. import * as post from 'misago/reducers/post';
  10. import ajax from 'misago/services/ajax';
  11. import modal from 'misago/services/modal';
  12. import snackbar from 'misago/services/snackbar';
  13. import store from 'misago/services/store';
  14. export default class extends React.Component {
  15. constructor(props) {
  16. super(props);
  17. this.state = {
  18. isReady: false,
  19. isBusy: true,
  20. canRevert: props.post.acl.can_edit,
  21. error: null,
  22. edit: null
  23. };
  24. }
  25. componentDidMount() {
  26. this.goToEdit();
  27. }
  28. goToEdit = (edit=null) => {
  29. this.setState({
  30. isBusy: true
  31. });
  32. let url = this.props.post.api.edits;
  33. if (edit !== null) {
  34. url += '?edit=' + edit;
  35. }
  36. ajax.get(url).then((data) => {
  37. this.setState({
  38. isReady: true,
  39. isBusy: false,
  40. edit: hydrateEdit(data)
  41. });
  42. }, (rejection) => {
  43. this.setState({
  44. isReady: true,
  45. isBusy: false,
  46. error: rejection.detail
  47. });
  48. });
  49. };
  50. revertEdit = (edit) => {
  51. if (this.state.isBusy) return;
  52. const confirmation = confirm(gettext("Are you sure you with to revert this post to the state from before this edit?"));
  53. if (!confirmation) return;
  54. this.setState({
  55. isBusy: true
  56. });
  57. const url = this.props.post.api.edits + '?edit=' + edit;
  58. ajax.post(url).then((data) => {
  59. const hydratedPost = post.hydrate(data);
  60. store.dispatch(post.patch(data, hydratedPost));
  61. snackbar.success(gettext("Post has been reverted to previous state."));
  62. modal.hide();
  63. }, (rejection) => {
  64. snackbar.apiError(rejection);
  65. this.setState({
  66. isBusy: false
  67. });
  68. });
  69. };
  70. render() {
  71. if (this.state.error) {
  72. return (
  73. <ModalDialog className="modal-dialog modal-message">
  74. <Message
  75. message={this.state.error}
  76. />
  77. </ModalDialog>
  78. );
  79. } else if (this.state.isReady) {
  80. return (
  81. <ModalDialog>
  82. <Toolbar
  83. canRevert={this.state.canRevert}
  84. disabled={this.state.isBusy}
  85. edit={this.state.edit}
  86. goToEdit={this.goToEdit}
  87. revertEdit={this.revertEdit}
  88. />
  89. <Diff diff={this.state.edit.diff} />
  90. <Footer
  91. canRevert={this.state.canRevert}
  92. disabled={this.state.isBusy}
  93. edit={this.state.edit}
  94. revertEdit={this.revertEdit}
  95. />
  96. </ModalDialog>
  97. );
  98. }
  99. return (
  100. <ModalDialog>
  101. <Loader />
  102. </ModalDialog>
  103. );
  104. }
  105. }
  106. export function ModalDialog(props) {
  107. return (
  108. <div
  109. className={props.className || "modal-dialog"}
  110. role="document"
  111. >
  112. <div className="modal-content">
  113. <div className="modal-header">
  114. <button
  115. aria-label={gettext("Close")}
  116. className="close"
  117. data-dismiss="modal"
  118. type="button"
  119. >
  120. <span aria-hidden="true">&times;</span>
  121. </button>
  122. <h4 className="modal-title">{gettext("Post edits history")}</h4>
  123. </div>
  124. {props.children}
  125. </div>
  126. </div>
  127. )
  128. }