PageStatusAlert.jsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import AppContainer from '../services/AppContainer';
  5. import PageContainer from '../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.renderSomeoneEditingAlert = this.renderSomeoneEditingAlert.bind(this);
  21. this.renderDraftExistsAlert = this.renderDraftExistsAlert.bind(this);
  22. this.renderUpdatedAlert = this.renderUpdatedAlert.bind(this);
  23. }
  24. refreshPage() {
  25. window.location.reload();
  26. }
  27. renderSomeoneEditingAlert() {
  28. const { t } = this.props;
  29. return (
  30. <div className="card grw-page-status-alert text-white bg-success d-hackmd-none fixed-bottom">
  31. <div className="card-body">
  32. <p className="card-text grw-card-label-container">
  33. <i className="icon-fw icon-people"></i>
  34. {t('hackmd.someone_editing')}
  35. </p>
  36. <p className="card-text grw-card-btn-container">
  37. <a href="#hackmd" className="btn btn-outline-white">
  38. <i className="fa fa-fw fa-file-text-o"></i>
  39. Open HackMD Editor
  40. </a>
  41. </p>
  42. </div>
  43. </div>
  44. );
  45. }
  46. renderDraftExistsAlert(isRealtime) {
  47. const { t } = this.props;
  48. return (
  49. <div className="card grw-page-status-alert text-white bg-success d-hackmd-none fixed-bottom">
  50. <div className="card-body">
  51. <p className="card-text grw-card-label-container">
  52. <i className="icon-fw icon-pencil"></i>
  53. {t('hackmd.this_page_has_draft')}
  54. </p>
  55. <p className="card-text grw-card-btn-container">
  56. <a href="#hackmd" className="btn btn-outline-white">
  57. <i className="fa fa-fw fa-file-text-o"></i>
  58. Open HackMD Editor
  59. </a>
  60. </p>
  61. </div>
  62. </div>
  63. );
  64. }
  65. renderUpdatedAlert() {
  66. const { t } = this.props;
  67. const label1 = t('edited this page');
  68. const label2 = t('Load latest');
  69. return (
  70. <div className="card grw-page-status-alert text-white bg-warning fixed-bottom">
  71. <div className="card-body">
  72. <p className="card-text grw-card-label-container">
  73. <i className="icon-fw icon-bulb"></i>
  74. {this.props.pageContainer.state.lastUpdateUsername} {label1}
  75. </p>
  76. <p className="card-text grw-card-btn-container">
  77. <a href="#" className="btn btn-outline-white" onClick={this.refreshPage}>
  78. <i className="icon-fw icon-reload"></i>
  79. {label2}
  80. </a>
  81. </p>
  82. </div>
  83. </div>
  84. );
  85. }
  86. render() {
  87. let content = <React.Fragment></React.Fragment>;
  88. const {
  89. revisionId, revisionIdHackmdSynced, remoteRevisionId, hasDraftOnHackmd, isHackmdDraftUpdatingInRealtime,
  90. } = this.props.pageContainer.state;
  91. const isRevisionOutdated = revisionId !== remoteRevisionId;
  92. const isHackmdDocumentOutdated = revisionIdHackmdSynced !== remoteRevisionId;
  93. // when remote revision is newer than both
  94. if (isHackmdDocumentOutdated && isRevisionOutdated) {
  95. content = this.renderUpdatedAlert();
  96. }
  97. // when someone editing with HackMD
  98. else if (isHackmdDraftUpdatingInRealtime) {
  99. content = this.renderSomeoneEditingAlert();
  100. }
  101. // when the draft of HackMD is newest
  102. else if (hasDraftOnHackmd) {
  103. content = this.renderDraftExistsAlert();
  104. }
  105. content = this.renderUpdatedAlert();
  106. return content;
  107. }
  108. }
  109. /**
  110. * Wrapper component for using unstated
  111. */
  112. const PageStatusAlertWrapper = withUnstatedContainers(PageStatusAlert, [AppContainer, PageContainer]);
  113. PageStatusAlert.propTypes = {
  114. t: PropTypes.func.isRequired, // i18next
  115. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  116. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  117. };
  118. export default withTranslation()(PageStatusAlertWrapper);