UserGroupDeleteModal.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import type { FC } from 'react';
  2. import React, { useCallback, useState, useMemo } from 'react';
  3. import {
  4. getIdStringForRef, isPopulated, type IGrantedGroup, type IUserGroupHasId,
  5. } from '@growi/core';
  6. import { useTranslation } from 'next-i18next';
  7. import {
  8. Modal, ModalHeader, ModalBody, ModalFooter,
  9. } from 'reactstrap';
  10. import { PageActionOnGroupDelete } from '~/interfaces/user-group';
  11. /**
  12. * Delete User Group Select component
  13. *
  14. * @export
  15. * @class GrantSelector
  16. * @extends {React.Component}
  17. */
  18. type Props = {
  19. userGroups: IGrantedGroup[],
  20. deleteUserGroup?: IUserGroupHasId,
  21. onDelete?: (deleteGroupId: string, actionName: PageActionOnGroupDelete, transferToUserGroup: IGrantedGroup | null) => Promise<void> | void,
  22. isShow: boolean,
  23. onHide?: () => Promise<void> | void,
  24. };
  25. type AvailableOption = {
  26. id: number,
  27. actionForPages: PageActionOnGroupDelete,
  28. label: string,
  29. };
  30. export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
  31. const { t } = useTranslation();
  32. const {
  33. onHide, onDelete, userGroups, deleteUserGroup,
  34. } = props;
  35. const availableOptions = useMemo<AvailableOption[]>(() => {
  36. return [
  37. {
  38. id: 1,
  39. actionForPages: PageActionOnGroupDelete.publicize,
  40. label: t('admin:user_group_management.delete_modal.publish_pages'),
  41. },
  42. {
  43. id: 2,
  44. actionForPages: PageActionOnGroupDelete.delete,
  45. label: t('admin:user_group_management.delete_modal.delete_pages'),
  46. },
  47. {
  48. id: 3,
  49. actionForPages: PageActionOnGroupDelete.transfer,
  50. label: t('admin:user_group_management.delete_modal.transfer_pages'),
  51. },
  52. ];
  53. }, [t]);
  54. /*
  55. * State
  56. */
  57. const [actionName, setActionName] = useState<PageActionOnGroupDelete | null>(null);
  58. const [transferToUserGroup, setTransferToUserGroup] = useState<IGrantedGroup | null>(null);
  59. /*
  60. * Function
  61. */
  62. const resetStates = useCallback(() => {
  63. setActionName(null);
  64. setTransferToUserGroup(null);
  65. }, []);
  66. const toggleHandler = useCallback(() => {
  67. if (onHide == null) {
  68. return;
  69. }
  70. resetStates();
  71. onHide();
  72. }, [onHide, resetStates]);
  73. const handleActionChange = useCallback((e) => {
  74. const actionName = e.target.value;
  75. setActionName(actionName);
  76. }, [setActionName]);
  77. const handleGroupChange = useCallback((e) => {
  78. const transferToUserGroupId: string = e.target.value;
  79. const selectedGroup = userGroups.find(group => getIdStringForRef(group.item) === transferToUserGroupId) ?? null;
  80. setTransferToUserGroup(selectedGroup);
  81. }, [userGroups]);
  82. const handleSubmit = useCallback((e) => {
  83. if (onDelete == null || deleteUserGroup == null || actionName == null) {
  84. return;
  85. }
  86. e.preventDefault();
  87. onDelete(
  88. deleteUserGroup._id,
  89. actionName,
  90. transferToUserGroup,
  91. );
  92. }, [onDelete, deleteUserGroup, actionName, transferToUserGroup]);
  93. const renderPageActionSelector = useCallback(() => {
  94. const options = availableOptions.map((opt) => {
  95. return <option key={opt.id} value={opt.actionForPages}>{opt.label}</option>;
  96. });
  97. // TODO: Use GROWI original dropdown.
  98. // refs: https://redmine.weseek.co.jp/issues/142614
  99. return (
  100. <select
  101. name="actionName"
  102. className="form-control"
  103. placeholder="select"
  104. value={actionName ?? ''}
  105. onChange={handleActionChange}
  106. >
  107. <option value="" disabled>{t('admin:user_group_management.delete_modal.dropdown_desc')}</option>
  108. {options}
  109. </select>
  110. );
  111. }, [availableOptions, actionName, handleActionChange, t]);
  112. const renderGroupSelector = useCallback(() => {
  113. if (deleteUserGroup == null) {
  114. return;
  115. }
  116. const groups = userGroups.filter((group) => {
  117. return getIdStringForRef(group.item) !== deleteUserGroup._id;
  118. });
  119. const options = groups.map((group) => {
  120. const groupId = getIdStringForRef(group.item);
  121. const groupName = isPopulated(group.item) ? group.item.name : null;
  122. return { id: groupId, name: groupName };
  123. }).filter(obj => obj.name != null)
  124. .map(obj => <option key={obj.id} value={obj.id}>{obj.name}</option>);
  125. const defaultOptionText = groups.length === 0 ? t('admin:user_group_management.delete_modal.no_groups')
  126. : t('admin:user_group_management.delete_modal.select_group');
  127. return (
  128. <select
  129. name="transferToUserGroup"
  130. className={`form-control ${actionName === PageActionOnGroupDelete.transfer ? '' : 'd-none'}`}
  131. value={transferToUserGroup != null ? getIdStringForRef(transferToUserGroup.item) : ''}
  132. onChange={handleGroupChange}
  133. >
  134. <option value="" disabled>{defaultOptionText}</option>
  135. {options}
  136. </select>
  137. );
  138. }, [deleteUserGroup, userGroups, t, actionName, transferToUserGroup, handleGroupChange]);
  139. const validateForm = useCallback(() => {
  140. let isValid = true;
  141. if (actionName === null) {
  142. isValid = false;
  143. }
  144. else if (actionName === PageActionOnGroupDelete.transfer) {
  145. isValid = transferToUserGroup != null;
  146. }
  147. return isValid;
  148. }, [actionName, transferToUserGroup]);
  149. return (
  150. <Modal className="modal-md" isOpen={props.isShow} toggle={toggleHandler}>
  151. <ModalHeader tag="h4" toggle={toggleHandler}>
  152. <span className="material-symbols-outlined">delete_forever</span> {t('admin:user_group_management.delete_modal.header')}
  153. </ModalHeader>
  154. <ModalBody>
  155. <div>
  156. <span className="fw-bold">{t('admin:user_group_management.group_name')}</span> : &quot;{props?.deleteUserGroup?.name || ''}&quot;
  157. </div>
  158. <div className="text-danger mt-3">
  159. {t('admin:user_group_management.delete_modal.desc')}
  160. </div>
  161. </ModalBody>
  162. <ModalFooter>
  163. <form className="d-flex justify-content-between w-100" onSubmit={handleSubmit}>
  164. <div className="d-flex mb-0 me-3">
  165. {renderPageActionSelector()}
  166. {renderGroupSelector()}
  167. </div>
  168. <button type="submit" value="" className="btn btn-sm btn-danger text-nowrap" disabled={!validateForm()}>
  169. <span className="material-symbols-outlined">delete_forever</span> {t('Delete')}
  170. </button>
  171. </form>
  172. {actionName === PageActionOnGroupDelete.publicize && (
  173. <div className="form-text text-muted">
  174. <small>{t('admin:user_group_management.delete_modal.option_explanation')}</small>
  175. </div>
  176. )}
  177. </ModalFooter>
  178. </Modal>
  179. );
  180. };