PageDeleteModal.jsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import React, { useState } from 'react';
  2. import PropTypes from 'prop-types';
  3. import {
  4. Modal, ModalHeader, ModalBody, ModalFooter,
  5. } from 'reactstrap';
  6. import { withTranslation } from 'react-i18next';
  7. import { apiPost } from '~/client/util/apiv1-client';
  8. import ApiErrorMessageList from './PageManagement/ApiErrorMessageList';
  9. const deleteIconAndKey = {
  10. completely: {
  11. color: 'danger',
  12. icon: 'fire',
  13. translationKey: 'completely',
  14. },
  15. temporary: {
  16. color: 'primary',
  17. icon: 'trash',
  18. translationKey: 'page',
  19. },
  20. };
  21. const PageDeleteModal = (props) => {
  22. const {
  23. t, isOpen, onClose, isDeleteCompletelyModal, pageId, revisionId, path, isAbleToDeleteCompletely,
  24. } = props;
  25. const [isDeleteRecursively, setIsDeleteRecursively] = useState(true);
  26. const [isDeleteCompletely, setIsDeleteCompletely] = useState(isDeleteCompletelyModal && isAbleToDeleteCompletely);
  27. const deleteMode = isDeleteCompletely ? 'completely' : 'temporary';
  28. const [errs, setErrs] = useState(null);
  29. function changeIsDeleteRecursivelyHandler() {
  30. setIsDeleteRecursively(!isDeleteRecursively);
  31. }
  32. function changeIsDeleteCompletelyHandler() {
  33. if (!isAbleToDeleteCompletely) {
  34. return;
  35. }
  36. setIsDeleteCompletely(!isDeleteCompletely);
  37. }
  38. async function deletePage() {
  39. setErrs(null);
  40. try {
  41. // control flag
  42. // If is it not true, Request value must be `null`.
  43. const recursively = isDeleteRecursively ? true : null;
  44. const completely = isDeleteCompletely ? true : null;
  45. const response = await apiPost('/pages.remove', {
  46. page_id: pageId,
  47. revision_id: revisionId,
  48. recursively,
  49. completely,
  50. });
  51. const trashPagePath = response.page.path;
  52. window.location.href = encodeURI(trashPagePath);
  53. }
  54. catch (err) {
  55. setErrs(err);
  56. }
  57. }
  58. async function deleteButtonHandler() {
  59. deletePage();
  60. }
  61. function renderDeleteRecursivelyForm() {
  62. return (
  63. <div className="custom-control custom-checkbox custom-checkbox-warning">
  64. <input
  65. className="custom-control-input"
  66. id="deleteRecursively"
  67. type="checkbox"
  68. checked={isDeleteRecursively}
  69. onChange={changeIsDeleteRecursivelyHandler}
  70. />
  71. <label className="custom-control-label" htmlFor="deleteRecursively">
  72. { t('modal_delete.delete_recursively') }
  73. <p className="form-text text-muted mt-0"><code>{path}</code> { t('modal_delete.recursively') }</p>
  74. </label>
  75. </div>
  76. );
  77. }
  78. // DeleteCompletely is currently disabled
  79. // TODO1 : Retrive isAbleToDeleteCompleltly state everywhere in the system via swr.
  80. // Story: https://redmine.weseek.co.jp/issues/82222
  81. // TODO2 : use toaster
  82. // TASK : https://redmine.weseek.co.jp/issues/82299
  83. function renderDeleteCompletelyForm() {
  84. return (
  85. <div className="custom-control custom-checkbox custom-checkbox-danger">
  86. <input
  87. className="custom-control-input"
  88. name="completely"
  89. id="deleteCompletely"
  90. type="checkbox"
  91. disabled
  92. checked={isDeleteCompletely}
  93. onChange={changeIsDeleteCompletelyHandler}
  94. />
  95. <label className="custom-control-label text-danger" htmlFor="deleteCompletely">
  96. { t('modal_delete.delete_completely')}
  97. <p className="form-text text-muted mt-0"> { t('modal_delete.completely') }</p>
  98. </label>
  99. {!isAbleToDeleteCompletely
  100. && (
  101. <p className="alert alert-warning p-2 my-0">
  102. <i className="icon-ban icon-fw"></i>{ t('modal_delete.delete_completely_restriction') }
  103. </p>
  104. )}
  105. </div>
  106. );
  107. }
  108. return (
  109. <Modal size="lg" isOpen={isOpen} toggle={onClose} className="grw-create-page">
  110. <ModalHeader tag="h4" toggle={onClose} className={`bg-${deleteIconAndKey[deleteMode].color} text-light`}>
  111. <i className={`icon-fw icon-${deleteIconAndKey[deleteMode].icon}`}></i>
  112. { t(`modal_delete.delete_${deleteIconAndKey[deleteMode].translationKey}`) }
  113. </ModalHeader>
  114. <ModalBody>
  115. <div className="form-group">
  116. <label>{ t('modal_delete.deleting_page') }:</label><br />
  117. <code>{ path }</code>
  118. </div>
  119. {renderDeleteRecursivelyForm()}
  120. {!isDeleteCompletelyModal && renderDeleteCompletelyForm()}
  121. </ModalBody>
  122. <ModalFooter>
  123. <ApiErrorMessageList errs={errs} />
  124. <button type="button" className={`btn btn-${deleteIconAndKey[deleteMode].color}`} onClick={deleteButtonHandler}>
  125. <i className={`icon-${deleteIconAndKey[deleteMode].icon}`} aria-hidden="true"></i>
  126. { t(`modal_delete.delete_${deleteIconAndKey[deleteMode].translationKey}`) }
  127. </button>
  128. </ModalFooter>
  129. </Modal>
  130. );
  131. };
  132. PageDeleteModal.propTypes = {
  133. t: PropTypes.func.isRequired, // i18next
  134. isOpen: PropTypes.bool.isRequired,
  135. onClose: PropTypes.func.isRequired,
  136. pageId: PropTypes.string.isRequired,
  137. revisionId: PropTypes.string.isRequired,
  138. path: PropTypes.string.isRequired,
  139. isDeleteCompletelyModal: PropTypes.bool,
  140. isAbleToDeleteCompletely: PropTypes.bool,
  141. };
  142. PageDeleteModal.defaultProps = {
  143. isDeleteCompletelyModal: false,
  144. };
  145. export default withTranslation()(PageDeleteModal);