Преглед изворни кода

Merge pull request #6928 from weseek/fix/styles-unsend-email-notification

fix: Unsend Email notification styles
Ryoji Shimizu пре 3 година
родитељ
комит
056cfc0b46

+ 13 - 11
packages/app/src/components/Admin/Security/ShareLinkSetting.tsx

@@ -134,19 +134,21 @@ const ShareLinkSetting = (props: ShareLinkSettingProps) => {
         </div>
       </div>
       <h4>{t('security_settings.all_share_links')}</h4>
-      <Pager
-        activePage={shareLinksActivePage}
-        pagingHandler={getShareLinkList}
-        totalLinks={totalshareLinks}
-        limit={shareLinksPagingLimit}
-      />
 
       {(shareLinks.length !== 0) ? (
-        <ShareLinkList
-          shareLinks={shareLinks}
-          onClickDeleteButton={deleteLinkById}
-          isAdmin
-        />
+        <>
+          <Pager
+            activePage={shareLinksActivePage}
+            pagingHandler={getShareLinkList}
+            totalLinks={totalshareLinks}
+            limit={shareLinksPagingLimit}
+          />
+          <ShareLinkList
+            shareLinks={shareLinks}
+            onClickDeleteButton={deleteLinkById}
+            isAdmin
+          />
+        </>
       )
         : (<p className="text-center">{t('security_settings.No_share_links')}</p>
         )

+ 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;
+}

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

@@ -0,0 +1,114 @@
+import React, { useState, useCallback } from 'react';
+
+import { IUserHasId, USER_STATUS } 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 = useCallback(async() => {
+    await adminUsersContainer.showPasswordResetModal(user);
+  }, [adminUsersContainer, user]);
+
+  const onSuccessfullySentInvitationEmailHandler = useCallback(() => {
+    setIsInvitationEmailSended(true);
+  }, []);
+
+  const renderEditMenu = useCallback(() => {
+    return (
+      <>
+        <li className="dropdown-divider"></li>
+        <li className="dropdown-header">{t('user_management.user_table.edit_menu')}</li>
+        <li>
+          <button className="dropdown-item" type="button" onClick={onClickPasswordResetHandler}>
+            <i className="icon-fw icon-key"></i>{ t('user_management.reset_password') }
+          </button>
+        </li>
+      </>
+    );
+  }, [onClickPasswordResetHandler, t]);
+
+  const renderStatusMenu = useCallback(() => {
+    return (
+      <>
+        <li className="dropdown-divider"></li>
+        <li className="dropdown-header">{t('user_management.status')}</li>
+        <li>
+          {(user.status === USER_STATUS.REGISTERED || user.status === USER_STATUS.SUSPENDED) && <StatusActivateButton user={user} />}
+          {user.status === USER_STATUS.ACTIVE && <StatusSuspendedMenuItem user={user} />}
+          {user.status === USER_STATUS.INVITED && (
+            <SendInvitationEmailButton
+              user={user}
+              isInvitationEmailSended={isInvitationEmailSended}
+              onSuccessfullySentInvitationEmail={onSuccessfullySentInvitationEmailHandler}
+            />
+          )}
+          {(user.status === USER_STATUS.REGISTERED || user.status === USER_STATUS.SUSPENDED || user.status === USER_STATUS.INVITED)
+          && <UserRemoveButton user={user} />}
+        </li>
+      </>
+    );
+  }, [isInvitationEmailSended, onSuccessfullySentInvitationEmailHandler, t, user]);
+
+  const renderAdminMenu = useCallback(() => {
+    return (
+      <>
+        <li className="dropdown-divider pl-0"></li>
+        <li className="dropdown-header">{t('user_management.user_table.administrator_menu')}</li>
+        <li>
+          {user.admin === true && <RemoveAdminMenuItem user={user} />}
+          {user.admin === false && <GiveAdminButton user={user} />}
+        </li>
+      </>
+    );
+  }, [t, user]);
+
+  return (
+    <UncontrolledDropdown id="userMenu" size="sm">
+      <DropdownToggle caret color="secondary" outline>
+        <i className="icon-settings" />
+        {(user.status === USER_STATUS.INVITED && !isInvitationEmailSended)
+        && <i className={`fa fa-circle text-danger grw-usermenu-notification-icon ${styles['grw-usermenu-notification-icon']}`} />}
+      </DropdownToggle>
+      <DropdownMenu positionFixed>
+        {renderEditMenu()}
+        {user.status !== USER_STATUS.DELETED && renderStatusMenu()}
+        {user.status === USER_STATUS.ACTIVE && 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;

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

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

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

@@ -15,12 +15,13 @@ export type IUser = {
   admin: boolean,
   apiToken?: string,
   isEmailPublished: boolean,
+  isInvitationEmailSended: boolean,
   lang: Lang,
   slackMemberId?: string,
   createdAt: Date,
   lastLoginAt?: Date,
   introduction: string,
-  status: number,
+  status: IUserStatus,
 }
 
 export type IUserGroupRelation = {
@@ -36,6 +37,15 @@ export type IUserGroup = {
   parent: Ref<IUserGroupHasId> | null;
 }
 
+export const USER_STATUS = {
+  REGISTERED: 1,
+  ACTIVE: 2,
+  SUSPENDED: 3,
+  DELETED: 4,
+  INVITED: 5,
+} as const;
+export type IUserStatus = typeof USER_STATUS[keyof typeof USER_STATUS]
+
 export type IUserHasId = IUser & HasObjectId;
 export type IUserGroupHasId = IUserGroup & HasObjectId;
 export type IUserGroupRelationHasId = IUserGroupRelation & HasObjectId;