PageStatusAlert.jsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import AppContainer from '~/client/services/AppContainer';
  5. import PageContainer from '~/client/services/PageContainer';
  6. import { withUnstatedContainers } from './UnstatedUtils';
  7. /**
  8. *
  9. * @author Yuki Takei <yuki@weseek.co.jp>
  10. *
  11. * @export
  12. * @class PageStatusAlert
  13. * @extends {React.Component}
  14. */
  15. class PageStatusAlert extends React.Component {
  16. constructor(props) {
  17. super(props);
  18. this.state = {
  19. };
  20. this.getContentsForSomeoneEditingAlert = this.getContentsForSomeoneEditingAlert.bind(this);
  21. this.getContentsForRevisionOutdated = this.getContentsForRevisionOutdated.bind(this);
  22. this.getContentsForDraftExistsAlert = this.getContentsForDraftExistsAlert.bind(this);
  23. this.getContentsForUpdatedAlert = this.getContentsForUpdatedAlert.bind(this);
  24. }
  25. refreshPage() {
  26. window.location.reload();
  27. }
  28. getContentsForSomeoneEditingAlert() {
  29. const { t } = this.props;
  30. return [
  31. ['bg-success', 'd-hackmd-none'],
  32. <>
  33. <i className="icon-fw icon-people"></i>
  34. {t('hackmd.someone_editing')}
  35. </>,
  36. <a href="#hackmd" className="btn btn-outline-white">
  37. <i className="fa fa-fw fa-file-text-o mr-1"></i>
  38. Open HackMD Editor
  39. </a>,
  40. ];
  41. }
  42. getContentsForRevisionOutdated() {
  43. const { t, pageContainer } = this.props;
  44. return [
  45. ['bg-warning', 'd-hackmd-none'],
  46. <>
  47. <i className="icon-fw icon-pencil"></i>
  48. {t('modal_resolve_conflict.file_conflicting_with_newer_remote')}
  49. </>,
  50. <>
  51. <button type="button" onClick={() => { window.location.href = pageContainer.state.path }} className="btn btn-outline-white mr-4">
  52. <i className="icon-fw icon-reload mr-1"></i>
  53. {t('modal_resolve_conflict.reload')}
  54. </button>
  55. <button type="button" onClick={() => pageContainer.setState({ isConflictDiffModalOpen: true })} className="btn btn-outline-white">
  56. <i className="fa fa-fw fa-file-text-o mr-1"></i>
  57. {t('modal_resolve_conflict.resolve_conflict')}
  58. </button>
  59. </>,
  60. ];
  61. }
  62. getContentsForDraftExistsAlert(isRealtime) {
  63. const { t } = this.props;
  64. return [
  65. ['bg-success', 'd-hackmd-none'],
  66. <>
  67. <i className="icon-fw icon-pencil"></i>
  68. {t('hackmd.this_page_has_draft')}
  69. </>,
  70. <a href="#hackmd" className="btn btn-outline-white">
  71. <i className="fa fa-fw fa-file-text-o mr-1"></i>
  72. Open HackMD Editor
  73. </a>,
  74. ];
  75. }
  76. getContentsForUpdatedAlert() {
  77. const { t } = this.props;
  78. const label1 = t('edited this page');
  79. const label2 = t('Load latest');
  80. return [
  81. ['bg-warning'],
  82. <>
  83. <i className="icon-fw icon-bulb"></i>
  84. {this.props.pageContainer.state.lastUpdateUsername} {label1}
  85. </>,
  86. <a href="#" className="btn btn-outline-white" onClick={this.refreshPage}>
  87. <i className="icon-fw icon-reload mr-1"></i>
  88. {label2}
  89. </a>,
  90. ];
  91. }
  92. render() {
  93. const {
  94. revisionId, revisionIdHackmdSynced, remoteRevisionId, hasDraftOnHackmd, isHackmdDraftUpdatingInRealtime, isConflictingOnSave,
  95. } = this.props.pageContainer.state;
  96. const isRevisionOutdated = revisionId !== remoteRevisionId;
  97. const isHackmdDocumentOutdated = revisionIdHackmdSynced !== remoteRevisionId;
  98. let getContentsFunc = null;
  99. console.log('isConflictingOnSave:', isConflictingOnSave);
  100. // when conflicting on save
  101. if (isConflictingOnSave) {
  102. getContentsFunc = this.getContentsForRevisionOutdated;
  103. }
  104. // when remote revision is newer than both
  105. else if (isHackmdDocumentOutdated && isRevisionOutdated) {
  106. getContentsFunc = this.getContentsForUpdatedAlert;
  107. }
  108. // when someone editing with HackMD
  109. else if (isHackmdDraftUpdatingInRealtime) {
  110. getContentsFunc = this.getContentsForSomeoneEditingAlert;
  111. }
  112. // when the draft of HackMD is newest
  113. else if (hasDraftOnHackmd) {
  114. getContentsFunc = this.getContentsForDraftExistsAlert;
  115. }
  116. // do not render anything
  117. else {
  118. return null;
  119. }
  120. const [additionalClasses, label, btn] = getContentsFunc();
  121. console.log('return:', additionalClasses, label, btn);
  122. this.props.pageContainer.setState({ isConflictDiffModalOpen: true });
  123. return (
  124. <div className={`card grw-page-status-alert text-white fixed-bottom animated fadeInUp faster ${additionalClasses.join(' ')}`}>
  125. <div className="card-body">
  126. <p className="card-text grw-card-label-container">
  127. {label}
  128. </p>
  129. <p className="card-text grw-card-btn-container">
  130. {btn}
  131. </p>
  132. </div>
  133. </div>
  134. );
  135. }
  136. }
  137. /**
  138. * Wrapper component for using unstated
  139. */
  140. const PageStatusAlertWrapper = withUnstatedContainers(PageStatusAlert, [AppContainer, PageContainer]);
  141. PageStatusAlert.propTypes = {
  142. t: PropTypes.func.isRequired, // i18next
  143. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  144. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  145. };
  146. export default withTranslation()(PageStatusAlertWrapper);