UserGroupDeleteModal.tsx 6.2 KB

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