UserMenu.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import React, { useState, useCallback } from 'react';
  2. import { type IUserHasId, USER_STATUS } from '@growi/core';
  3. import { useTranslation } from 'next-i18next';
  4. import {
  5. UncontrolledDropdown, DropdownToggle, DropdownMenu,
  6. } from 'reactstrap';
  7. import AdminUsersContainer from '~/client/services/AdminUsersContainer';
  8. import { withUnstatedContainers } from '../../UnstatedUtils';
  9. import GrantAdminButton from './GrantAdminButton';
  10. import GrantReadOnlyButton from './GrantReadOnlyButton';
  11. import RevokeAdminMenuItem from './RevokeAdminMenuItem';
  12. import RevokeReadOnlyMenuItem from './RevokeReadOnlyMenuItem';
  13. import SendInvitationEmailButton from './SendInvitationEmailButton';
  14. import StatusActivateButton from './StatusActivateButton';
  15. import StatusSuspendedMenuItem from './StatusSuspendMenuItem';
  16. import UserRemoveButton from './UserRemoveButton';
  17. import styles from './UserMenu.module.scss';
  18. type UserMenuProps = {
  19. adminUsersContainer: AdminUsersContainer,
  20. user: IUserHasId,
  21. }
  22. const UserMenu = (props: UserMenuProps) => {
  23. const { t } = useTranslation('admin');
  24. const { adminUsersContainer, user } = props;
  25. const [isInvitationEmailSended, setIsInvitationEmailSended] = useState<boolean>(user.isInvitationEmailSended);
  26. const onClickPasswordResetHandler = useCallback(async() => {
  27. await adminUsersContainer.showPasswordResetModal(user);
  28. }, [adminUsersContainer, user]);
  29. const onSuccessfullySentInvitationEmailHandler = useCallback(() => {
  30. setIsInvitationEmailSended(true);
  31. }, []);
  32. const renderEditMenu = useCallback(() => {
  33. return (
  34. <>
  35. <li className="dropdown-divider"></li>
  36. <li className="dropdown-header">{t('user_management.user_table.edit_menu')}</li>
  37. <li>
  38. <button className="dropdown-item d-flex align-items-center" type="button" onClick={onClickPasswordResetHandler}>
  39. <span className="material-symbols-outlined me-1">key</span>{ t('user_management.reset_password') }
  40. </button>
  41. </li>
  42. </>
  43. );
  44. }, [onClickPasswordResetHandler, t]);
  45. const renderStatusMenu = useCallback(() => {
  46. return (
  47. <>
  48. <li className="dropdown-divider"></li>
  49. <li className="dropdown-header">{t('user_management.status')}</li>
  50. <li>
  51. {(user.status === USER_STATUS.REGISTERED || user.status === USER_STATUS.SUSPENDED) && <StatusActivateButton user={user} />}
  52. {user.status === USER_STATUS.ACTIVE && <StatusSuspendedMenuItem user={user} />}
  53. {user.status === USER_STATUS.INVITED && (
  54. <SendInvitationEmailButton
  55. user={user}
  56. isInvitationEmailSended={isInvitationEmailSended}
  57. onSuccessfullySentInvitationEmail={onSuccessfullySentInvitationEmailHandler}
  58. />
  59. )}
  60. {(user.status === USER_STATUS.REGISTERED || user.status === USER_STATUS.SUSPENDED || user.status === USER_STATUS.INVITED)
  61. && <UserRemoveButton user={user} />}
  62. </li>
  63. </>
  64. );
  65. }, [isInvitationEmailSended, onSuccessfullySentInvitationEmailHandler, t, user]);
  66. const renderAdminMenu = useCallback(() => {
  67. return (
  68. <>
  69. <li className="dropdown-divider ps-0"></li>
  70. <li className="dropdown-header">{t('user_management.user_table.administrator_menu')}</li>
  71. <li>
  72. {user.admin ? <RevokeAdminMenuItem user={user} /> : <GrantAdminButton user={user} />}
  73. </li>
  74. <li>
  75. {user.readOnly ? <RevokeReadOnlyMenuItem user={user} /> : <GrantReadOnlyButton user={user} />}
  76. </li>
  77. </>
  78. );
  79. }, [t, user]);
  80. return (
  81. <UncontrolledDropdown id="userMenu" size="sm">
  82. <DropdownToggle caret color="secondary" outline>
  83. <i className="icon-settings" />
  84. {(user.status === USER_STATUS.INVITED && !isInvitationEmailSended)
  85. && <i className={`fa fa-circle text-danger grw-usermenu-notification-icon ${styles['grw-usermenu-notification-icon']}`} />}
  86. </DropdownToggle>
  87. <DropdownMenu strategy="fixed">
  88. {renderEditMenu()}
  89. {user.status !== USER_STATUS.DELETED && renderStatusMenu()}
  90. {user.status === USER_STATUS.ACTIVE && renderAdminMenu()}
  91. </DropdownMenu>
  92. </UncontrolledDropdown>
  93. );
  94. };
  95. /**
  96. * Wrapper component for using unstated
  97. */
  98. // eslint-disable-next-line max-len
  99. const UserMenuWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(UserMenu, [AdminUsersContainer]);
  100. export default UserMenuWrapper;