index.js 3.2 KB

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