UserGroupForm.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import type { FC } from 'react';
  2. import React, { useCallback, useEffect, useState } from 'react';
  3. import type { IUserGroupHasId } from '@growi/core';
  4. import { format as dateFnsFormat } from 'date-fns/format';
  5. import { useTranslation } from 'next-i18next';
  6. type Props = {
  7. userGroup: IUserGroupHasId,
  8. parentUserGroup?: IUserGroupHasId,
  9. selectableParentUserGroups?: IUserGroupHasId[],
  10. submitButtonLabel: string;
  11. onSubmit: (targetGroup: IUserGroupHasId, userGroupData: Partial<IUserGroupHasId>) => Promise<void>
  12. isExternalGroup?: boolean
  13. };
  14. export const UserGroupForm: FC<Props> = (props: Props) => {
  15. const { t } = useTranslation('admin');
  16. const {
  17. userGroup, parentUserGroup, selectableParentUserGroups, submitButtonLabel, onSubmit, isExternalGroup = false,
  18. } = props;
  19. /*
  20. * State
  21. */
  22. const [currentName, setName] = useState<string>(userGroup.name);
  23. const [currentDescription, setDescription] = useState<string>(userGroup.description);
  24. const [selectedParent, setSelectedParent] = useState<IUserGroupHasId | undefined>();
  25. /*
  26. * Function
  27. */
  28. const onChangeNameHandler = useCallback((e) => {
  29. setName(e.target.value);
  30. }, []);
  31. const onChangeDescriptionHandler = useCallback((e) => {
  32. setDescription(e.target.value);
  33. }, []);
  34. const onChangeParentButtonHandler = useCallback((userGroup: IUserGroupHasId) => {
  35. if (userGroup._id !== selectedParent?._id) {
  36. setSelectedParent(userGroup);
  37. }
  38. }, [selectedParent, setSelectedParent]);
  39. useEffect(() => {
  40. setSelectedParent(parentUserGroup);
  41. }, [parentUserGroup]);
  42. const isSelectableParentUserGroups = selectableParentUserGroups != null && selectableParentUserGroups.length > 0;
  43. const isChildUserGroup = parentUserGroup !== undefined;
  44. const messageAtReleaseParentGroup = isChildUserGroup ? t('user_group_management.release_parent_group') : t('user_group_management.select_parent_group');
  45. return (
  46. <form onSubmit={(e) => {
  47. e.preventDefault();
  48. onSubmit(props.userGroup, {
  49. name: currentName,
  50. description: currentDescription,
  51. parent: selectedParent,
  52. });
  53. }}
  54. >
  55. <fieldset>
  56. <h2 className="admin-setting-header">{t('user_group_management.basic_info')}</h2>
  57. {isExternalGroup
  58. && (
  59. <div className="mb-3">
  60. <small className="text-muted">{t('external_user_group.only_description_edit_allowed')}</small>
  61. </div>
  62. )}
  63. {
  64. userGroup?.createdAt != null && (
  65. <div className="row mb-3">
  66. <p className="col-md-2 col-form-label">{t('Created')}</p>
  67. <p className="col-md-6 my-auto">{dateFnsFormat(userGroup.createdAt, 'yyyy-MM-dd')}</p>
  68. </div>
  69. )
  70. }
  71. <div className="row mb-3">
  72. <label htmlFor="name" className="col-md-2 col-form-label">
  73. {t('user_group_management.group_name')}
  74. </label>
  75. <div className="col-md-6 my-auto">
  76. <input
  77. className="form-control"
  78. type="text"
  79. name="name"
  80. placeholder={t('user_group_management.group_example')}
  81. value={currentName}
  82. onChange={onChangeNameHandler}
  83. required
  84. disabled={isExternalGroup}
  85. />
  86. </div>
  87. </div>
  88. <div className="row mb-3">
  89. <label htmlFor="description" className="col-md-2 col-form-label">
  90. {t('Description')}
  91. </label>
  92. <div className="col-md-6">
  93. <textarea className="form-control" name="description" value={currentDescription} onChange={onChangeDescriptionHandler} />
  94. </div>
  95. </div>
  96. <div className="row mb-3">
  97. <label htmlFor="parent" className="col-md-2 col-form-label">
  98. {t('user_group_management.parent_group')}
  99. </label>
  100. <div className="dropdown col-md-6">
  101. <button
  102. type="button"
  103. id="dropdownMenuButton"
  104. data-bs-toggle="dropdown"
  105. className="btn btn-outline-secondary dropdown-toggle mb-3"
  106. disabled={isExternalGroup || !isSelectableParentUserGroups}
  107. >
  108. {selectedParent?.name ?? messageAtReleaseParentGroup}
  109. </button>
  110. <div className="dropdown-menu" aria-labelledby="dropdownMenuButton">
  111. {
  112. isSelectableParentUserGroups && (
  113. <>
  114. {
  115. selectableParentUserGroups.map(userGroup => (
  116. <button
  117. key={userGroup._id}
  118. type="button"
  119. className={`dropdown-item ${selectedParent?._id === userGroup._id ? 'active' : ''}`}
  120. onClick={() => onChangeParentButtonHandler(userGroup)}
  121. >
  122. {userGroup.name}
  123. </button>
  124. ))
  125. }
  126. </>
  127. )
  128. }
  129. <div className="dropdown-divider" />
  130. <button
  131. className="dropdown-item"
  132. type="button"
  133. onClick={() => { setSelectedParent(undefined) }}
  134. >{t('user_group_management.release_parent_group')}
  135. </button>
  136. </div>
  137. </div>
  138. </div>
  139. <div className="row mb-5">
  140. <div className="offset-md-2 col-md-10">
  141. <button type="submit" className="btn btn-primary">
  142. {submitButtonLabel}
  143. </button>
  144. </div>
  145. </div>
  146. </fieldset>
  147. </form>
  148. );
  149. };