UserGroupForm.tsx 5.6 KB

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