Client/Shared: Added a property that allows you not to change the selected item and display the toast.
This commit is contained in:
parent
f435cb71a7
commit
6e5dd2eccf
@ -52,6 +52,8 @@ interface AccessSelectorProps {
|
||||
isDisabled?: boolean;
|
||||
directionX?: string;
|
||||
directionY?: string;
|
||||
isSelectionDisabled?: boolean;
|
||||
selectionErrorText: React.ReactNode;
|
||||
}
|
||||
|
||||
const AccessSelector: React.FC<AccessSelectorProps> = ({
|
||||
@ -72,6 +74,8 @@ const AccessSelector: React.FC<AccessSelectorProps> = ({
|
||||
isDisabled,
|
||||
directionX = "right",
|
||||
directionY = "bottom",
|
||||
isSelectionDisabled,
|
||||
selectionErrorText,
|
||||
}) => {
|
||||
const [horizontalOrientation, setHorizontalOrientation] = useState(false);
|
||||
const [width, setWidth] = useState(manualWidth || 0);
|
||||
@ -133,6 +137,8 @@ const AccessSelector: React.FC<AccessSelectorProps> = ({
|
||||
setIsOpenItemAccess={setIsOpenItemAccess}
|
||||
hideMobileView={isMobileHorizontalOrientation}
|
||||
isDisabled={isDisabled}
|
||||
isSelectionDisabled={isSelectionDisabled}
|
||||
selectionErrorText={selectionErrorText}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -155,6 +161,8 @@ const AccessSelector: React.FC<AccessSelectorProps> = ({
|
||||
withBackground={!isMobileView}
|
||||
withBlur={isMobileView}
|
||||
isDisabled={isDisabled}
|
||||
isSelectionDisabled={isSelectionDisabled}
|
||||
selectionErrorText={selectionErrorText}
|
||||
/>
|
||||
)}
|
||||
</StyledAccessSelector>
|
||||
|
@ -31,9 +31,7 @@ import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { ChangeUserTypeDialog } from "../dialogs";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
import PaidQuotaLimitError from "../PaidQuotaLimitError";
|
||||
|
||||
const ChangeUserTypeEvent = ({
|
||||
setVisible,
|
||||
@ -46,7 +44,6 @@ const ChangeUserTypeEvent = ({
|
||||
getPeopleListItem,
|
||||
setInfoPanelSelection,
|
||||
needResetUserSelection,
|
||||
isRoomAdmin,
|
||||
}) => {
|
||||
const { toType, fromType, userIDs, successCallback, abortCallback } =
|
||||
peopleDialogData;
|
||||
@ -76,16 +73,6 @@ const ChangeUserTypeEvent = ({
|
||||
};
|
||||
}, [peopleDialogData]);
|
||||
|
||||
const onClickPayments = () => {
|
||||
const paymentPageUrl = combineUrl(
|
||||
"/portal-settings",
|
||||
"/payments/portal-payments",
|
||||
);
|
||||
|
||||
toastr.clear();
|
||||
navigate(paymentPageUrl);
|
||||
};
|
||||
|
||||
const onChangeUserType = () => {
|
||||
onClosePanel();
|
||||
updateUserType(toType, userIDs, peopleFilter, fromType)
|
||||
@ -101,20 +88,7 @@ const ChangeUserTypeEvent = ({
|
||||
successCallback && successCallback(users);
|
||||
})
|
||||
.catch((err) => {
|
||||
toastr.error(
|
||||
<>
|
||||
<Text>{t("Common:QuotaPaidUserLimitError")}</Text>
|
||||
{!isRoomAdmin && (
|
||||
<Link color="#5387AD" isHovered={true} onClick={onClickPayments}>
|
||||
{t("Common:PaymentsTitle")}
|
||||
</Link>
|
||||
)}
|
||||
</>,
|
||||
false,
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
toastr.error(<PaidQuotaLimitError />, false, 0, true, true);
|
||||
|
||||
abortCallback && abortCallback();
|
||||
})
|
||||
@ -170,7 +144,7 @@ export default inject(
|
||||
changeUserTypeDialogVisible: visible,
|
||||
setChangeUserTypeDialogVisible: setVisible,
|
||||
} = dialogsStore;
|
||||
const { isRoomAdmin } = authStore;
|
||||
|
||||
const { setInfoPanelSelection } = infoPanelStore;
|
||||
const { dialogStore, filterStore, usersStore } = peopleStore;
|
||||
|
||||
@ -180,7 +154,6 @@ export default inject(
|
||||
usersStore;
|
||||
const { setSelected } = peopleStore.selectionStore;
|
||||
return {
|
||||
isRoomAdmin,
|
||||
needResetUserSelection,
|
||||
getPeopleListItem,
|
||||
setInfoPanelSelection,
|
||||
|
78
packages/client/src/components/PaidQuotaLimitError/index.js
Normal file
78
packages/client/src/components/PaidQuotaLimitError/index.js
Normal file
@ -0,0 +1,78 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
|
||||
const PaidQuotaLimitError = ({
|
||||
isRoomAdmin,
|
||||
setInvitePanelOptions,
|
||||
invitePanelVisible,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onClickPayments = () => {
|
||||
const paymentPageUrl = combineUrl(
|
||||
"/portal-settings",
|
||||
"/payments/portal-payments",
|
||||
);
|
||||
|
||||
toastr.clear();
|
||||
window.DocSpace.navigate(paymentPageUrl);
|
||||
|
||||
invitePanelVisible &&
|
||||
setInvitePanelOptions({
|
||||
visible: false,
|
||||
hideSelector: false,
|
||||
defaultAccess: 1,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text>{t("Common:QuotaPaidUserLimitError")}</Text>
|
||||
{!isRoomAdmin && (
|
||||
<Link color="#5387AD" isHovered={true} onClick={onClickPayments}>
|
||||
{t("Common:PaymentsTitle")}
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ authStore, dialogsStore }) => {
|
||||
const { isRoomAdmin } = authStore;
|
||||
const { setInvitePanelOptions, invitePanelOptions } = dialogsStore;
|
||||
return {
|
||||
isRoomAdmin,
|
||||
setInvitePanelOptions,
|
||||
invitePanelVisible: invitePanelOptions.visible,
|
||||
};
|
||||
})(observer(PaidQuotaLimitError));
|
@ -30,7 +30,6 @@ import PropTypes from "prop-types";
|
||||
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
|
||||
import { Button } from "@docspace/shared/components/button";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
@ -41,6 +40,8 @@ import { EmployeeStatus } from "@docspace/shared/enums";
|
||||
import ModalDialogContainer from "../ModalDialogContainer";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import PaidQuotaLimitError from "SRC_DIR/components/PaidQuotaLimitError";
|
||||
|
||||
class ChangeUserStatusDialogComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -48,15 +49,6 @@ class ChangeUserStatusDialogComponent extends React.Component {
|
||||
this.state = { isRequestRunning: false };
|
||||
}
|
||||
|
||||
onClickPayments = () => {
|
||||
const paymentPageUrl = combineUrl(
|
||||
"/portal-settings",
|
||||
"/payments/portal-payments",
|
||||
);
|
||||
|
||||
toastr.clear();
|
||||
window.DocSpace.navigate(paymentPageUrl);
|
||||
};
|
||||
onChangeUserStatus = () => {
|
||||
const {
|
||||
updateUserStatus,
|
||||
@ -83,22 +75,7 @@ class ChangeUserStatusDialogComponent extends React.Component {
|
||||
toastr.success(t("PeopleTranslations:SuccessChangeUserStatus"));
|
||||
})
|
||||
.catch((err) => {
|
||||
toastr.error(
|
||||
<>
|
||||
<Text>{t("Common:QuotaPaidUserLimitError")}</Text>
|
||||
<Link
|
||||
color="#5387AD"
|
||||
isHovered={true}
|
||||
onClick={this.onClickPayments}
|
||||
>
|
||||
{t("Common:PaymentsTitle")}
|
||||
</Link>
|
||||
</>,
|
||||
false,
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
toastr.error(<PaidQuotaLimitError />, false, 0, true, true);
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({ isRequestRunning: false }, () => {
|
||||
|
@ -38,9 +38,12 @@ import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { DropDown } from "@docspace/shared/components/drop-down";
|
||||
import { DropDownItem } from "@docspace/shared/components/drop-down-item";
|
||||
import { getDefaultAccessUser } from "@docspace/shared/utils/getDefaultAccessUser";
|
||||
import { ShareAccessRights } from "@docspace/shared/enums";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
|
||||
import AccessSelector from "../../../AccessSelector";
|
||||
|
||||
import PaidQuotaLimitError from "../../../PaidQuotaLimitError";
|
||||
import {
|
||||
StyledBlock,
|
||||
StyledSubHeader,
|
||||
@ -50,6 +53,9 @@ import {
|
||||
StyledDescription,
|
||||
} from "../StyledInvitePanel";
|
||||
|
||||
import { getPaidQuotaLimitError } from "SRC_DIR/helpers/filesUtils";
|
||||
|
||||
|
||||
const ExternalLinks = ({
|
||||
t,
|
||||
roomId,
|
||||
@ -65,6 +71,7 @@ const ExternalLinks = ({
|
||||
activeLink,
|
||||
isMobileView,
|
||||
getPortalInviteLink,
|
||||
isPaidUserLimit,
|
||||
}) => {
|
||||
const [actionLinksVisible, setActionLinksVisible] = useState(false);
|
||||
|
||||
@ -114,14 +121,16 @@ const ExternalLinks = ({
|
||||
|
||||
const onSelectAccess = async (access) => {
|
||||
let link = null;
|
||||
if (roomId === -1) {
|
||||
link = shareLinks.find((l) => l.access === access.access);
|
||||
const selectedAccess = access.access;
|
||||
|
||||
link.shareLink = await getPortalInviteLink(access.access);
|
||||
if (roomId === -1) {
|
||||
link = shareLinks.find((l) => l.access === selectedAccess);
|
||||
|
||||
link.shareLink = await getPortalInviteLink(selectedAccess);
|
||||
|
||||
setActiveLink(link);
|
||||
} else {
|
||||
setInvitationLinks(roomId, "Invite", +access.access, shareLinks[0].id);
|
||||
setInvitationLinks(roomId, "Invite", +selectedAccess, shareLinks[0].id);
|
||||
|
||||
link = shareLinks[0];
|
||||
setActiveLink(shareLinks[0]);
|
||||
@ -255,6 +264,8 @@ const ExternalLinks = ({
|
||||
containerRef={inputsRef}
|
||||
isOwner={isOwner}
|
||||
isMobileView={isMobileView}
|
||||
isSelectionDisabled={isPaidUserLimit}
|
||||
selectionErrorText={<PaidQuotaLimitError />}
|
||||
/>
|
||||
</StyledInviteInputContainer>
|
||||
)}
|
||||
@ -263,12 +274,13 @@ const ExternalLinks = ({
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({ userStore, dialogsStore, filesStore, peopleStore }) => {
|
||||
({ userStore, dialogsStore, filesStore, peopleStore, currentQuotaStore }) => {
|
||||
const { isOwner } = userStore.user;
|
||||
const { invitePanelOptions } = dialogsStore;
|
||||
const { setInvitationLinks } = filesStore;
|
||||
const { roomId, hideSelector, defaultAccess } = invitePanelOptions;
|
||||
const { getPortalInviteLink } = peopleStore.inviteLinksStore;
|
||||
const { isPaidUserLimit } = currentQuotaStore;
|
||||
|
||||
return {
|
||||
setInvitationLinks,
|
||||
@ -277,6 +289,7 @@ export default inject(
|
||||
defaultAccess,
|
||||
isOwner,
|
||||
getPortalInviteLink,
|
||||
isPaidUserLimit,
|
||||
};
|
||||
},
|
||||
)(observer(ExternalLinks));
|
||||
|
@ -68,6 +68,7 @@ import {
|
||||
|
||||
import AtReactSvgUrl from "PUBLIC_DIR/images/@.react.svg?url";
|
||||
import ArrowIcon from "PUBLIC_DIR/images/arrow.right.react.svg";
|
||||
import PaidQuotaLimitError from "SRC_DIR/components/PaidQuotaLimitError";
|
||||
|
||||
const minSearchValue = 2;
|
||||
|
||||
@ -92,6 +93,7 @@ const InviteInput = ({
|
||||
i18n,
|
||||
setCultureKey,
|
||||
standalone,
|
||||
isPaidUserLimit,
|
||||
}) => {
|
||||
const isPublicRoomType = roomType === RoomsType.PublicRoom;
|
||||
|
||||
@ -551,6 +553,8 @@ const InviteInput = ({
|
||||
containerRef={inputsRef}
|
||||
isOwner={isOwner}
|
||||
isMobileView={isMobileView}
|
||||
isSelectionDisabled={isPaidUserLimit}
|
||||
selectionErrorText={<PaidQuotaLimitError />}
|
||||
/>
|
||||
|
||||
{!hideSelector && addUsersPanelVisible && (
|
||||
@ -578,31 +582,35 @@ const InviteInput = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ settingsStore, dialogsStore, userStore }) => {
|
||||
const { isOwner } = userStore.user;
|
||||
const {
|
||||
invitePanelOptions,
|
||||
setInviteItems,
|
||||
inviteItems,
|
||||
setInviteLanguage,
|
||||
culture,
|
||||
} = dialogsStore;
|
||||
export default inject(
|
||||
({ settingsStore, dialogsStore, userStore, currentQuotaStore }) => {
|
||||
const { isOwner } = userStore.user;
|
||||
const {
|
||||
invitePanelOptions,
|
||||
setInviteItems,
|
||||
inviteItems,
|
||||
setInviteLanguage,
|
||||
culture,
|
||||
} = dialogsStore;
|
||||
|
||||
const { culture: language, standalone } = settingsStore;
|
||||
const { culture: language, standalone } = settingsStore;
|
||||
const { isPaidUserLimit } = currentQuotaStore;
|
||||
|
||||
return {
|
||||
language,
|
||||
setInviteLanguage,
|
||||
setInviteItems,
|
||||
inviteItems,
|
||||
culture,
|
||||
roomId: invitePanelOptions.roomId,
|
||||
hideSelector: invitePanelOptions.hideSelector,
|
||||
defaultAccess: invitePanelOptions.defaultAccess,
|
||||
isOwner,
|
||||
standalone,
|
||||
};
|
||||
})(
|
||||
return {
|
||||
language,
|
||||
setInviteLanguage,
|
||||
setInviteItems,
|
||||
inviteItems,
|
||||
culture,
|
||||
roomId: invitePanelOptions.roomId,
|
||||
hideSelector: invitePanelOptions.hideSelector,
|
||||
defaultAccess: invitePanelOptions.defaultAccess,
|
||||
isOwner,
|
||||
standalone,
|
||||
isPaidUserLimit,
|
||||
};
|
||||
},
|
||||
)(
|
||||
withCultureNames(
|
||||
withTranslation(["InviteDialog", "Common", "Translations"])(
|
||||
observer(InviteInput),
|
||||
|
@ -29,6 +29,7 @@ import React, { useState, useEffect, useCallback } from "react";
|
||||
import { DropDownItem } from "../drop-down-item";
|
||||
import { Badge } from "../badge";
|
||||
import { TOption } from "../combobox";
|
||||
import { toastr } from "../toast";
|
||||
|
||||
import {
|
||||
StyledItemTitle,
|
||||
@ -46,6 +47,8 @@ export const AccessRightSelectPure = ({
|
||||
advancedOptions,
|
||||
selectedOption,
|
||||
className,
|
||||
isSelectionDisabled,
|
||||
selectionErrorText,
|
||||
...props
|
||||
}: AccessRightSelectProps) => {
|
||||
const [currentItem, setCurrentItem] = useState(selectedOption);
|
||||
@ -57,7 +60,13 @@ export const AccessRightSelectPure = ({
|
||||
const onSelectCurrentItem = useCallback(
|
||||
(option: TOption) => {
|
||||
if (option) {
|
||||
setCurrentItem(option);
|
||||
if (!isSelectionDisabled) setCurrentItem(option);
|
||||
|
||||
if (isSelectionDisabled && option.access !== selectedOption.access) {
|
||||
toastr.error(selectionErrorText);
|
||||
return;
|
||||
}
|
||||
|
||||
onSelect?.(option);
|
||||
}
|
||||
},
|
||||
|
@ -49,4 +49,6 @@ type PropsFromCombobox = Pick<
|
||||
export type AccessRightSelectProps = PropsFromCombobox & {
|
||||
/** List of access options */
|
||||
accessOptions: ComboboxProps["options"];
|
||||
isSelectionDisabled?: boolean;
|
||||
selectionErrorText?: React.ReactNode;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user