jam411 3 năm trước cách đây
mục cha
commit
14e52c911d

+ 2 - 1
packages/app/src/components/Admin/Users/GiveAdminButton.tsx

@@ -39,6 +39,7 @@ const GiveAdminButton = (props: GiveAdminButtonProps): JSX.Element => {
 /**
  * Wrapper component for using unstated
  */
-const GiveAdminButtonWrapper = withUnstatedContainers(GiveAdminButton, [AdminUsersContainer]);
+// eslint-disable-next-line max-len
+const GiveAdminButtonWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(GiveAdminButton, [AdminUsersContainer]);
 
 export default GiveAdminButtonWrapper;

+ 2 - 1
packages/app/src/components/Admin/Users/RemoveAdminMenuItem.tsx

@@ -58,6 +58,7 @@ const RemoveAdminMenuItem = (props: Props): JSX.Element => {
 /**
 * Wrapper component for using unstated
 */
-const RemoveAdminMenuItemWrapper = withUnstatedContainers(RemoveAdminMenuItem, [AdminUsersContainer]);
+// eslint-disable-next-line max-len
+const RemoveAdminMenuItemWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(RemoveAdminMenuItem, [AdminUsersContainer]);
 
 export default RemoveAdminMenuItemWrapper;

+ 2 - 1
packages/app/src/components/Admin/Users/StatusSuspendMenuItem.tsx

@@ -56,6 +56,7 @@ const StatusSuspendMenuItem = (props: Props): JSX.Element => {
 /**
  * Wrapper component for using unstated
  */
-const StatusSuspendMenuItemWrapper = withUnstatedContainers(StatusSuspendMenuItem, [AdminUsersContainer]);
+// eslint-disable-next-line max-len
+const StatusSuspendMenuItemWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(StatusSuspendMenuItem, [AdminUsersContainer]);
 
 export default StatusSuspendMenuItemWrapper;

+ 0 - 132
packages/app/src/components/Admin/Users/UserMenu.jsx

@@ -1,132 +0,0 @@
-import React, { Fragment } from 'react';
-
-import { useTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
-import {
-  UncontrolledDropdown, DropdownToggle, DropdownMenu,
-} from 'reactstrap';
-
-import AdminUsersContainer from '~/client/services/AdminUsersContainer';
-
-import { withUnstatedContainers } from '../../UnstatedUtils';
-
-import GiveAdminButton from './GiveAdminButton';
-import RemoveAdminMenuItem from './RemoveAdminMenuItem';
-import SendInvitationEmailButton from './SendInvitationEmailButton';
-import StatusActivateButton from './StatusActivateButton';
-import StatusSuspendedMenuItem from './StatusSuspendMenuItem';
-import UserRemoveButton from './UserRemoveButton';
-
-
-class UserMenu extends React.Component {
-
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      isInvitationEmailSended: this.props.user.isInvitationEmailSended,
-    };
-
-    this.onPasswordResetClicked = this.onPasswordResetClicked.bind(this);
-    this.onSuccessfullySentInvitationEmail = this.onSuccessfullySentInvitationEmail.bind(this);
-  }
-
-  onPasswordResetClicked() {
-    this.props.adminUsersContainer.showPasswordResetModal(this.props.user);
-  }
-
-  onSuccessfullySentInvitationEmail() {
-    this.setState({ isInvitationEmailSended: true });
-  }
-
-  renderEditMenu() {
-    const { t } = this.props;
-
-    return (
-      <Fragment>
-        <li className="dropdown-divider"></li>
-        <li className="dropdown-header">{t('admin:user_management.user_table.edit_menu')}</li>
-        <li>
-          <button className="dropdown-item" type="button" onClick={this.onPasswordResetClicked}>
-            <i className="icon-fw icon-key"></i>{ t('admin:user_management.reset_password') }
-          </button>
-        </li>
-      </Fragment>
-    );
-  }
-
-  renderStatusMenu() {
-    const { t, user } = this.props;
-    const { isInvitationEmailSended } = this.state;
-
-    return (
-      <Fragment>
-        <li className="dropdown-divider"></li>
-        <li className="dropdown-header">{t('user_management.status')}</li>
-        <li>
-          {(user.status === 1 || user.status === 3) && <StatusActivateButton user={user} />}
-          {user.status === 2 && <StatusSuspendedMenuItem user={user} />}
-          {user.status === 5 && (
-            <SendInvitationEmailButton
-              user={user}
-              isInvitationEmailSended={isInvitationEmailSended}
-              onSuccessfullySentInvitationEmail={this.onSuccessfullySentInvitationEmail}
-            />
-          )}
-          {(user.status === 1 || user.status === 3 || user.status === 5) && <UserRemoveButton user={user} />}
-        </li>
-      </Fragment>
-    );
-  }
-
-  renderAdminMenu() {
-    const { t, user } = this.props;
-
-    return (
-      <Fragment>
-        <li className="dropdown-divider pl-0"></li>
-        <li className="dropdown-header">{t('admin:user_management.user_table.administrator_menu')}</li>
-        <li>
-          {user.admin === true && <RemoveAdminMenuItem user={user} />}
-          {user.admin === false && <GiveAdminButton user={user} />}
-        </li>
-      </Fragment>
-    );
-  }
-
-  render() {
-    const { user } = this.props;
-    const { isInvitationEmailSended } = this.state;
-
-    return (
-      <UncontrolledDropdown id="userMenu" size="sm">
-        <DropdownToggle caret color="secondary" outline>
-          <i className="icon-settings" />
-          {(user.status === 5 && !isInvitationEmailSended) && <i className="fa fa-circle text-danger grw-usermenu-notification-icon" />}
-        </DropdownToggle>
-        <DropdownMenu positionFixed>
-          {this.renderEditMenu()}
-          {user.status !== 4 && this.renderStatusMenu()}
-          {user.status === 2 && this.renderAdminMenu()}
-        </DropdownMenu>
-      </UncontrolledDropdown>
-    );
-  }
-
-}
-
-const UserMenuWrapperFC = (props) => {
-  const { t } = useTranslation('admin');
-  return <UserMenu t={t} {...props} />;
-};
-
-const UserMenuWrapper = withUnstatedContainers(UserMenuWrapperFC, [AdminUsersContainer]);
-
-UserMenu.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  adminUsersContainer: PropTypes.instanceOf(AdminUsersContainer).isRequired,
-
-  user: PropTypes.object.isRequired,
-};
-
-export default UserMenuWrapper;

+ 5 - 0
packages/app/src/components/Admin/Users/UserMenu.module.scss

@@ -0,0 +1,5 @@
+.grw-usermenu-notification-icon :global {
+  position: absolute;
+  top: -4px;
+  left: 30px;
+}

+ 113 - 0
packages/app/src/components/Admin/Users/UserMenu.tsx

@@ -0,0 +1,113 @@
+import React, { useState } from 'react';
+
+import { IUserHasId } from '@growi/core';
+import { useTranslation } from 'next-i18next';
+import {
+  UncontrolledDropdown, DropdownToggle, DropdownMenu,
+} from 'reactstrap';
+
+import AdminUsersContainer from '~/client/services/AdminUsersContainer';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
+
+import GiveAdminButton from './GiveAdminButton';
+import RemoveAdminMenuItem from './RemoveAdminMenuItem';
+import SendInvitationEmailButton from './SendInvitationEmailButton';
+import StatusActivateButton from './StatusActivateButton';
+import StatusSuspendedMenuItem from './StatusSuspendMenuItem';
+import UserRemoveButton from './UserRemoveButton';
+
+import styles from './UserMenu.module.scss';
+
+type UserMenuProps = {
+  adminUsersContainer: AdminUsersContainer,
+  user: IUserHasId,
+}
+
+const UserMenu = (props: UserMenuProps) => {
+  const { t } = useTranslation('admin');
+
+  const { adminUsersContainer, user } = props;
+
+  const [isInvitationEmailSended, setIsInvitationEmailSended] = useState<boolean>(user.isInvitationEmailSended);
+
+  const onClickPasswordResetHandler = async() => {
+    await adminUsersContainer.showPasswordResetModal(user);
+  };
+
+  const onSuccessfullySentInvitationEmailHandler = () => {
+    setIsInvitationEmailSended(true);
+  };
+
+  const renderEditMenu = () => {
+    return (
+      <>
+        <li className="dropdown-divider"></li>
+        <li className="dropdown-header">{t('admin:user_management.user_table.edit_menu')}</li>
+        <li>
+          <button className="dropdown-item" type="button" onClick={onClickPasswordResetHandler}>
+            <i className="icon-fw icon-key"></i>{ t('admin:user_management.reset_password') }
+          </button>
+        </li>
+      </>
+    );
+  };
+
+  const renderStatusMenu = () => {
+    return (
+      <>
+        <li className="dropdown-divider"></li>
+        <li className="dropdown-header">{t('user_management.status')}</li>
+        <li>
+          {(user.status === 1 || user.status === 3) && <StatusActivateButton user={user} />}
+          {user.status === 2 && <StatusSuspendedMenuItem user={user} />}
+          {user.status === 5 && (
+            <SendInvitationEmailButton
+              user={user}
+              isInvitationEmailSended={isInvitationEmailSended}
+              onSuccessfullySentInvitationEmail={onSuccessfullySentInvitationEmailHandler}
+            />
+          )}
+          {(user.status === 1 || user.status === 3 || user.status === 5) && <UserRemoveButton user={user} />}
+        </li>
+      </>
+    );
+  };
+
+  const renderAdminMenu = () => {
+    return (
+      <>
+        <li className="dropdown-divider pl-0"></li>
+        <li className="dropdown-header">{t('admin:user_management.user_table.administrator_menu')}</li>
+        <li>
+          {user.admin === true && <RemoveAdminMenuItem user={user} />}
+          {user.admin === false && <GiveAdminButton user={user} />}
+        </li>
+      </>
+    );
+  };
+
+  return (
+    <UncontrolledDropdown id="userMenu" size="sm">
+      <DropdownToggle caret color="secondary" outline>
+        <i className="icon-settings" />
+        {(user.status === 5 && !isInvitationEmailSended)
+        && <i className={`fa fa-circle text-danger grw-usermenu-notification-icon ${styles['grw-usermenu-notification-icon']}`} />}
+      </DropdownToggle>
+      <DropdownMenu positionFixed>
+        {renderEditMenu}
+        {user.status !== 4 && renderStatusMenu}
+        {user.status === 2 && renderAdminMenu}
+      </DropdownMenu>
+    </UncontrolledDropdown>
+  );
+
+};
+
+/**
+* Wrapper component for using unstated
+*/
+// eslint-disable-next-line max-len
+const UserMenuWrapper: React.ForwardRefExoticComponent<Pick<any, string | number | symbol> & React.RefAttributes<any>> = withUnstatedContainers(UserMenu, [AdminUsersContainer]);
+
+export default UserMenuWrapper;

+ 6 - 5
packages/app/src/styles/_user.scss

@@ -8,11 +8,12 @@ $easeInOutCubic: cubic-bezier(0.65, 0, 0.35, 1);
 /*
  * Styles
  */
-.grw-usermenu-notification-icon {
-  position: absolute;
-  top: -4px;
-  left: 30px;
-}
+// move to UserMenu.module.scss
+// .grw-usermenu-notification-icon {
+//   position: absolute;
+//   top: -4px;
+//   left: 30px;
+// }
 
 .draft-list-item {
   .icon-container {

+ 1 - 0
packages/core/src/interfaces/user.ts

@@ -15,6 +15,7 @@ export type IUser = {
   admin: boolean,
   apiToken?: string,
   isEmailPublished: boolean,
+  isInvitationEmailSended: boolean,
   lang: Lang,
   slackMemberId?: string,
   createdAt: Date,