diff --git a/packages/client/src/HOCs/withPeopleContent.js b/packages/client/src/HOCs/withPeopleContent.js index 535abe09b3..ffd8f86693 100644 --- a/packages/client/src/HOCs/withPeopleContent.js +++ b/packages/client/src/HOCs/withPeopleContent.js @@ -1,5 +1,7 @@ import React, { useCallback } from "react"; import { inject, observer } from "mobx-react"; +import { useTranslation } from "react-i18next"; + import Link from "@docspace/components/link"; import LinkWithDropdown from "@docspace/components/link-with-dropdown"; import Avatar from "@docspace/components/avatar"; @@ -20,6 +22,7 @@ export default function withContent(WrappedContent) { deselectUser, isAdmin, theme, + getModel, } = props; const { userName, mobilePhone, email, role, displayName, avatar } = item; @@ -121,6 +124,20 @@ export default function withContent(WrappedContent) { const onPhoneClick = () => window.open(`sms:${mobilePhone}`); const onEmailClick = () => window.open(`mailto:${email}`); + const { t } = useTranslation([ + "People", + "Common", + "PeopleTranslations", + "DeleteProfileEverDialog", + "Translations", + "Files", + "ChangeUserTypeDialog", + ]); + + const contextOptionsProps = { + contextOptions: getModel(item, t), + }; + return ( ); @@ -141,7 +159,9 @@ export default function withContent(WrappedContent) { const { selectGroup } = peopleStore.selectedGroupStore; const { getTargetUser } = peopleStore.targetUserStore; - const { selectionStore } = peopleStore; + const { selectionStore, contextOptionsStore } = peopleStore; + + const { getModel } = contextOptionsStore; const { selection, @@ -158,10 +178,12 @@ export default function withContent(WrappedContent) { selectGroup, fetchProfile: getTargetUser, checked: selection.some((el) => el.id === item.id), + isSeveralSelection: selection.length > 1, isActive: bufferSelection?.id === item?.id, setBufferSelection, selectUser, deselectUser, + getModel, }; })(observer(WithContent)); } diff --git a/packages/client/src/HOCs/withPeopleContextOptions.js b/packages/client/src/HOCs/withPeopleContextOptions.js deleted file mode 100644 index 3fc2007799..0000000000 --- a/packages/client/src/HOCs/withPeopleContextOptions.js +++ /dev/null @@ -1,76 +0,0 @@ -import React from "react"; -import { inject, observer } from "mobx-react"; -import { useTranslation } from "react-i18next"; - -export default function withContextOptions(WrappedComponent) { - const WithContextOptions = (props) => { - const { - isAdmin, - item, - - getUserContextOptions, - } = props; - const { id, options, currentUserId } = item; - - const { t } = useTranslation([ - "People", - "Common", - "PeopleTranslations", - "DeleteProfileEverDialog", - "Translations", - ]); - - const showContextMenu = options && options.length > 0; - - const contextOptionsProps = - (isAdmin && showContextMenu) || (showContextMenu && id === currentUserId) - ? { - contextOptions: getUserContextOptions(t, options, item), - } - : {}; - - return ( - - ); - }; - - return inject(({ auth, peopleStore }) => { - const { isAdmin } = auth; - - const { - dialogStore, - targetUserStore, - usersStore, - contextOptionsStore, - } = peopleStore; - const { getTargetUser } = targetUserStore; - const { updateUserStatus } = usersStore; - const { - setDialogData, - closeDialogs, - setDeleteSelfProfileDialogVisible, - setChangePasswordDialogVisible, - setChangeEmailDialogVisible, - setDeleteProfileDialogVisible, - } = dialogStore; - - const { getUserContextOptions } = contextOptionsStore; - - return { - isAdmin, - fetchProfile: getTargetUser, - setDialogData, - closeDialogs, - setDeleteSelfProfileDialogVisible, - setChangePasswordDialogVisible, - setChangeEmailDialogVisible, - updateUserStatus, - setDeleteProfileDialogVisible, - getUserContextOptions, - }; - })(observer(WithContextOptions)); -} diff --git a/packages/client/src/pages/Accounts/Home/Section/Body/RowView/SimpleUserRow.js b/packages/client/src/pages/Accounts/Home/Section/Body/RowView/SimpleUserRow.js index 575034181b..a833a89b19 100644 --- a/packages/client/src/pages/Accounts/Home/Section/Body/RowView/SimpleUserRow.js +++ b/packages/client/src/pages/Accounts/Home/Section/Body/RowView/SimpleUserRow.js @@ -6,7 +6,6 @@ import { isMobile } from "react-device-detect"; import Row from "@docspace/components/row"; import { Base } from "@docspace/components/themes"; -import withContextOptions from "SRC_DIR/HOCs/withPeopleContextOptions"; import withContent from "SRC_DIR/HOCs/withPeopleContent"; import UserContent from "./userContent"; @@ -97,13 +96,17 @@ const SimpleUserRow = (props) => { element, setBufferSelection, isActive, + isSeveralSelection, } = props; const isChecked = checkedProps.checked; const userContextClick = React.useCallback(() => { + if (isSeveralSelection && isChecked) { + return; + } setBufferSelection(item); - }, [item, setBufferSelection]); + }, [isChecked, isSeveralSelection, item, setBufferSelection]); return ( { ); }; -export default withRouter(withContextOptions(withContent(SimpleUserRow))); +export default withRouter(withContent(SimpleUserRow)); diff --git a/packages/client/src/pages/Accounts/Home/Section/Body/TableView/TableRow.js b/packages/client/src/pages/Accounts/Home/Section/Body/TableView/TableRow.js index 512d5be68a..9106a76952 100644 --- a/packages/client/src/pages/Accounts/Home/Section/Body/TableView/TableRow.js +++ b/packages/client/src/pages/Accounts/Home/Section/Body/TableView/TableRow.js @@ -11,7 +11,6 @@ import Checkbox from "@docspace/components/checkbox"; import ComboBox from "@docspace/components/combobox"; import DropDownItem from "@docspace/components/drop-down-item"; -import withContextOptions from "SRC_DIR/HOCs/withPeopleContextOptions"; import withContent from "SRC_DIR/HOCs/withPeopleContent"; import Badges from "../Badges"; @@ -136,6 +135,7 @@ const PeopleTableRow = (props) => { userId, setBufferSelection, isActive, + isSeveralSelection, } = props; const { @@ -233,8 +233,12 @@ const PeopleTableRow = (props) => { const isChecked = checkedProps.checked; const userContextClick = React.useCallback(() => { + if (isSeveralSelection && isChecked) { + return; + } + setBufferSelection(item); - }, [item, setBufferSelection]); + }, [isSeveralSelection, isChecked, item, setBufferSelection]); return ( { }; export default withTranslation(["People", "Common", "Settings"])( - withRouter(withContextOptions(withContent(PeopleTableRow))) + withRouter(withContent(PeopleTableRow)) ); diff --git a/packages/client/src/store/AccountsContextOptionsStore.js b/packages/client/src/store/AccountsContextOptionsStore.js index f2e88101e5..7222805efc 100644 --- a/packages/client/src/store/AccountsContextOptionsStore.js +++ b/packages/client/src/store/AccountsContextOptionsStore.js @@ -18,27 +18,14 @@ const PROFILE_SELF_URL = combineUrl(PROXY_HOMEPAGE_URL, "/accounts/view/@self"); class AccountsContextOptionsStore { authStore = null; - dialogStore = null; - targetUserStore = null; - usersStore = null; - selectionStore = null; - infoPanelStore = null; - constructor( - authStore, - dialogStore, - targetUserStore, - usersStore, - selectionStore, - infoPanelStore - ) { + peopleStore = null; + + constructor(authStore, peopleStore) { makeAutoObservable(this); this.authStore = authStore; - this.dialogStore = dialogStore; - this.targetUserStore = targetUserStore; - this.usersStore = usersStore; - this.selectionStore = selectionStore; - this.infoPanelStore = infoPanelStore; + + this.peopleStore = peopleStore; } getUserContextOptions = (t, options, item) => { @@ -155,12 +142,135 @@ class AccountsContextOptionsStore { return contextMenu; }; + getUserGroupContextOptions = (t) => { + const { onChangeType } = this.peopleStore; + + const { + hasUsersToMakeEmployees, + hasUsersToActivate, + hasUsersToDisable, + hasUsersToInvite, + hasUsersToRemove, + } = this.peopleStore.selectionStore; + const { + setActiveDialogVisible, + setDisableDialogVisible, + setSendInviteDialogVisible, + setDeleteDialogVisible, + } = this.peopleStore.dialogStore; + + const { isAdmin, isOwner } = this.authStore.userStore.user; + + const { setVisible, isVisible } = this.peopleStore.infoPanelStore; + + const options = []; + + const adminOption = { + id: "context-menu_administrator", + className: "context-menu_drop-down", + label: t("Administrator"), + title: t("Administrator"), + onClick: (e) => onChangeType(e, t), + action: "admin", + key: "cm-administrator", + }; + const managerOption = { + id: "context-menu_manager", + className: "context-menu_drop-down", + label: t("Manager"), + title: t("Manager"), + onClick: (e) => onChangeType(e, t), + action: "manager", + key: "cm-manager", + }; + const userOption = { + id: "context-menu_user", + className: "context-menu_drop-down", + label: t("Common:User"), + title: t("Common:User"), + onClick: (e) => onChangeType(e, t), + action: "user", + key: "cm-user", + }; + + isOwner && options.push(adminOption); + + isAdmin && options.push(managerOption); + + options.push(userOption); + + const headerMenu = [ + { + key: "cm-change-type", + label: t("ChangeUserTypeDialog:ChangeUserTypeButton"), + disabled: (isAdmin || isOwner) && !hasUsersToMakeEmployees, + icon: "/static/images/change.to.employee.react.svg", + items: options, + }, + { + key: "cm-info", + label: t("PeopleTranslations:Details"), + disabled: isVisible, + onClick: setVisible, + icon: "images/info.react.svg", + }, + { + key: "cm-invite", + label: t("Common:Invite"), + disabled: !hasUsersToInvite, + onClick: () => setSendInviteDialogVisible(true), + icon: "/static/images/invite.again.react.svg", + }, + { + key: "cm-enable", + label: t("Common:Enable"), + disabled: !hasUsersToActivate, + onClick: () => setActiveDialogVisible(true), + icon: "images/enable.react.svg", + }, + { + key: "cm-disable", + label: t("PeopleTranslations:DisableUserButton"), + disabled: !hasUsersToDisable, + onClick: () => setDisableDialogVisible(true), + icon: "images/disable.react.svg", + }, + { + key: "cm-delete", + label: t("Common:Delete"), + disabled: !hasUsersToRemove, + onClick: () => setDeleteDialogVisible(true), + icon: "/static/images/delete.react.svg", + }, + ]; + + return headerMenu; + }; + + getModel = (item, t) => { + const { selection } = this.peopleStore.selectionStore; + + const { options } = item; + + const contextOptionsProps = + options && options.length > 0 + ? selection.length > 1 + ? this.getUserGroupContextOptions(t) + : this.getUserContextOptions(t, options, item) + : []; + + return contextOptionsProps; + }; + onProfileClick = () => { history.push(PROFILE_SELF_URL); }; toggleChangeNameDialog = (item) => { - const { setDialogData, setChangeNameDialogVisible } = this.dialogStore; + const { + setDialogData, + setChangeNameDialogVisible, + } = this.peopleStore.dialogStore; const { id, firstName, lastName } = item; setDialogData({ id, firstName, lastName }); @@ -169,7 +279,10 @@ class AccountsContextOptionsStore { }; toggleChangeEmailDialog = (item) => { - const { setDialogData, setChangeEmailDialogVisible } = this.dialogStore; + const { + setDialogData, + setChangeEmailDialogVisible, + } = this.peopleStore.dialogStore; const { id, email } = item; setDialogData({ @@ -181,7 +294,10 @@ class AccountsContextOptionsStore { }; toggleChangePasswordDialog = (item) => { - const { setDialogData, setChangePasswordDialogVisible } = this.dialogStore; + const { + setDialogData, + setChangePasswordDialogVisible, + } = this.peopleStore.dialogStore; const { email } = item; setDialogData({ email, @@ -191,14 +307,14 @@ class AccountsContextOptionsStore { }; toggleChangeOwnerDialog = () => { - const { setChangeOwnerDialogVisible } = this.dialogStore; + const { setChangeOwnerDialogVisible } = this.peopleStore.dialogStore; setChangeOwnerDialogVisible(true); }; onEnableClick = (t, item) => { const { id } = item; - const { updateUserStatus } = this.usersStore; + const { updateUserStatus } = this.peopleStore.usersStore; updateUserStatus(EmployeeStatus.Active, [id], true) .then(() => @@ -209,7 +325,7 @@ class AccountsContextOptionsStore { onDisableClick = (t, item) => { const { id } = item; - const { updateUserStatus } = this.usersStore; + const { updateUserStatus } = this.peopleStore.usersStore; updateUserStatus(EmployeeStatus.Disabled, [id], true) .then(() => @@ -235,7 +351,10 @@ class AccountsContextOptionsStore { }; toggleDeleteProfileEverDialog = (item) => { - const { setDialogData, setDeleteProfileDialogVisible } = this.dialogStore; + const { + setDialogData, + setDeleteProfileDialogVisible, + } = this.peopleStore.dialogStore; const { id, displayName, userName } = item; closeDialogs(); @@ -250,7 +369,7 @@ class AccountsContextOptionsStore { }; onDetailsClick = () => { - const { setVisible } = this.infoPanelStore; + const { setVisible } = this.peopleStore.infoPanelStore; setVisible(); }; @@ -272,10 +391,10 @@ class AccountsContextOptionsStore { ) .catch((error) => toastr.error(error)); }; + + onResetAuth = (item) => { + console.log(item); + }; } -const onResetAuth = (item) => { - console.log(item); -}; - export default AccountsContextOptionsStore; diff --git a/packages/client/src/store/PeopleStore.js b/packages/client/src/store/PeopleStore.js index c6cf567cc8..250611e079 100644 --- a/packages/client/src/store/PeopleStore.js +++ b/packages/client/src/store/PeopleStore.js @@ -54,14 +54,7 @@ class PeopleStore { this.infoPanelStore = infoPanelStore; this.setupStore = setupStore; - this.contextOptionsStore = new AccountsContextOptionsStore( - authStore, - this.dialogStore, - this.targetUserStore, - this.usersStore, - this.selectionStore, - this.infoPanelStore - ); + this.contextOptionsStore = new AccountsContextOptionsStore(authStore, this); makeAutoObservable(this); } @@ -96,12 +89,12 @@ class PeopleStore { return getUsersList(newFilter); }; - onChangeType = (e) => { - const action = e.target.dataset.action; + onChangeType = (e, t) => { + const action = e?.action ? e.action : e?.target?.dataset?.action; const { getUsersToMakeEmployeesIds } = this.selectionStore; - this.changeType(action, getUsersToMakeEmployeesIds); + this.changeType(action, getUsersToMakeEmployeesIds, t); }; changeType = (type, users, t, needClearSelection = true) => { @@ -159,7 +152,7 @@ class PeopleStore { className: "group-menu_drop-down", label: t("Administrator"), title: t("Administrator"), - onClick: this.onChangeType, + onClick: (e) => this.onChangeType(e, t), "data-action": "admin", key: "administrator", }; @@ -168,7 +161,7 @@ class PeopleStore { className: "group-menu_drop-down", label: t("Manager"), title: t("Manager"), - onClick: this.onChangeType, + onClick: (e) => this.onChangeType(e, t), "data-action": "manager", key: "manager", }; @@ -177,7 +170,7 @@ class PeopleStore { className: "group-menu_drop-down", label: t("Common:User"), title: t("Common:User"), - onClick: this.onChangeType, + onClick: (e) => this.onChangeType(e, t), "data-action": "user", key: "user", }; @@ -190,6 +183,7 @@ class PeopleStore { const headerMenu = [ { + key: "change-user", label: t("ChangeUserTypeDialog:ChangeUserTypeButton"), disabled: (isAdmin || isOwner) && !hasUsersToMakeEmployees, iconUrl: "/static/images/change.to.employee.react.svg", @@ -197,30 +191,35 @@ class PeopleStore { options: options, }, { + key: "info", label: t("PeopleTranslations:Details"), disabled: isVisible, onClick: setVisible, iconUrl: "images/info.react.svg", }, { + key: "invite", label: t("Common:Invite"), disabled: !hasUsersToInvite, onClick: () => setSendInviteDialogVisible(true), iconUrl: "/static/images/invite.again.react.svg", }, { + key: "enable", label: t("Common:Enable"), disabled: !hasUsersToActivate, onClick: () => setActiveDialogVisible(true), iconUrl: "images/enable.react.svg", }, { + key: "disable", label: t("PeopleTranslations:DisableUserButton"), disabled: !hasUsersToDisable, onClick: () => setDisableDialogVisible(true), iconUrl: "images/disable.react.svg", }, { + key: "delete", label: t("Common:Delete"), disabled: !hasUsersToRemove, onClick: () => setDeleteDialogVisible(true),