Client: Added dialogues if the limits for adding users and rooms have been reached.

This commit is contained in:
Tatiana Lopaeva 2024-08-15 15:45:24 +03:00
parent a19211f9a6
commit ec0dbf9518
10 changed files with 231 additions and 52 deletions

View File

@ -9,6 +9,8 @@
"BusinessSuggestion": "Customize your {{planName}} plan",
"BusinessTitle": "You are using {{planName}} plan",
"BusinessUpdated": "{{planName}} plan updated",
"CannotCreateNewRoom": "Cannot create new room.",
"CannotCreatePaidUsers": "Cannot add new paid users. ",
"ChooseNewPayer": "Choose a new Payer",
"ChooseNewPlan": "Would you like to choose a new pricing plan?",
"ContactUs": "For sales questions, contact us at",
@ -22,6 +24,8 @@
"InvalidEmailWithoutActiveSubscription": "We recommend choosing a new Payer who gets access to subscription settings in {{productName}}.",
"InvalidEmailWithoutActiveSubscriptionByAdmin": "We recommend contacting the {{productName}} owner to choose a new Payer.",
"ManagerTypesDescription": "Admin account types and their privileges",
"NewRoomWillExceedLimit": "Creating new room will exceed the maximum number of rooms allowed by your current pricing plan.",
"NewUsersWillExceedMembersLimit": "Adding new users will exceed the maximum number of portal paid members allowed by your current pricing plan.",
"Pay": "Pay",
"Payer": "Payer",
"PayerDescription": "This user has access to payment details and is the only user who can adjust the quota and make payments. The {{productName}} owner, as well as the paying manager themselves, can reassign the paying manager role using the Stripe customer portal.",

View File

@ -83,7 +83,7 @@ const withHotkeys = (Component) => {
isVisitor,
deleteRooms,
archiveRooms,
isGracePeriod,
isWarningRoomsDialog,
setInviteUsersWarningDialogVisible,
security,
@ -158,7 +158,7 @@ const withHotkeys = (Component) => {
const onCreateRoom = () => {
if (!isVisitor && isRoomsFolder && security?.Create) {
if (isGracePeriod) {
if (isWarningRoomsDialog) {
setInviteUsersWarningDialogVisible(true);
return;
}
@ -436,7 +436,7 @@ const withHotkeys = (Component) => {
treeFoldersStore,
selectedFolderStore,
userStore,
currentTariffStatusStore,
currentQuotaStore,
}) => {
const {
setSelected,
@ -487,7 +487,6 @@ const withHotkeys = (Component) => {
const { visible: mediaViewerIsVisible } = mediaViewerDataStore;
const { setHotkeyPanelVisible } = settingsStore;
const { isGracePeriod } = currentTariffStatusStore;
const isVisitor = userStore.user?.isVisitor;
@ -499,6 +498,8 @@ const withHotkeys = (Component) => {
isRoomsFolder,
} = treeFoldersStore;
const { isWarningRoomsDialog } = currentQuotaStore;
const security = selectedFolderStore.security;
const isFormRoom = selectedFolderStore.roomType === RoomsType.FormRoom;
const isParentFolderFormRoom =
@ -553,7 +554,7 @@ const withHotkeys = (Component) => {
deleteRooms,
archiveRooms,
isGracePeriod,
isWarningRoomsDialog,
setInviteUsersWarningDialogVisible,
security,

View File

@ -171,7 +171,6 @@ const ArticleMainButtonContent = (props) => {
copyPanelVisible,
security,
isGracePeriod,
setInviteUsersWarningDialogVisible,
currentDeviceType,
@ -181,6 +180,7 @@ const ArticleMainButtonContent = (props) => {
parentRoomType,
isFolder,
showWarningDialog,
isWarningRoomsDialog,
} = props;
const navigate = useNavigate();
@ -219,7 +219,7 @@ const ArticleMainButtonContent = (props) => {
);
const onCreateRoom = React.useCallback(() => {
if (isGracePeriod) {
if (isWarningRoomsDialog) {
setInviteUsersWarningDialogVisible(true);
return;
}
@ -940,8 +940,8 @@ export default inject(
const isFolder = selectedFolderStore.isFolder;
const { isAdmin, isOwner, isRoomAdmin } = userStore.user;
const { isGracePeriod } = currentTariffStatusStore;
const { showWarningDialog } = currentQuotaStore;
const { showWarningDialog, isWarningRoomsDialog } = currentQuotaStore;
const { setOformFromFolderId, oformsFilter } = oformsStore;
const { mainButtonItemsList } = pluginStore;
@ -949,7 +949,6 @@ export default inject(
const { frameConfig, isFrame } = settingsStore;
return {
isGracePeriod,
setInviteUsersWarningDialogVisible,
showText: settingsStore.showText,
isMobileArticle: settingsStore.isMobileArticle,
@ -1002,6 +1001,7 @@ export default inject(
setSelectFileFormRoomDialogVisible,
showWarningDialog,
isWarningRoomsDialog,
};
},
)(

View File

@ -79,7 +79,7 @@ const EmptyContainer = ({
};
const onCreateRoom = (e) => {
if (isGracePeriod) {
if (isWarningRoomsDialog) {
setInviteUsersWarningDialogVisible(true);
return;
}
@ -126,7 +126,7 @@ export default inject(
settingsStore,
filesStore,
dialogsStore,
currentQuotaStore,
selectedFolderStore,
clientLoadingStore,
currentTariffStatusStore,
@ -144,6 +144,7 @@ export default inject(
isFiltered === null && isErrorRoomNotAvailable;
const isRoot = selectedFolderStore.pathParts?.length === 1;
const { isWarningRoomsDialog } = currentQuotaStore;
return {
theme: settingsStore.theme,
@ -157,6 +158,7 @@ export default inject(
type: selectedFolderStore.type,
isRoot,
isPublicRoom,
isWarningRoomsDialog,
};
},
)(observer(EmptyContainer));

View File

@ -27,14 +27,16 @@
import React, { useState, useEffect } from "react";
import { inject, observer } from "mobx-react";
import { withTranslation, Trans } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { useNavigate, useLocation } from "react-router-dom";
import moment from "moment-timezone";
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
import { Button } from "@docspace/shared/components/button";
import { Text } from "@docspace/shared/components/text";
import { getDaysRemaining } from "@docspace/shared/utils/common";
import RoomsContent from "./sub-components/RoomsContent";
import UsersContent from "./sub-components/UsersContent";
const InviteUsersWarningDialog = (props) => {
const {
t,
@ -48,6 +50,8 @@ const InviteUsersWarningDialog = (props) => {
isGracePeriod,
currentTariffPlanTitle,
isPaymentPageAvailable,
isRoomsTariffLimit,
isUserTariffLimit,
} = props;
const navigate = useNavigate();
@ -84,6 +88,31 @@ const InviteUsersWarningDialog = (props) => {
navigate(paymentPageUrl);
};
const location = useLocation();
const isAccounts = location.pathname.includes("accounts/people");
const contentForGracePeriod = (
<>
<Text fontWeight={700} noSelect>
{t("BusinessPlanPaymentOverdue", {
planName: currentTariffPlanTitle,
})}
</Text>
<br />
<Text noSelect as="div">
<Trans t={t} i18nKey="GracePeriodActivatedInfo" ns="Payments">
Grace period activated
<strong>
from {{ fromDate }} to {{ byDate }}
</strong>
(days remaining: {{ delayDaysCount }})
</Trans>
</Text>
<br />
<Text>{t("GracePeriodActivatedDescription")}</Text>
</>
);
return (
<ModalDialog
isLarge={isGracePeriod}
@ -95,37 +124,24 @@ const InviteUsersWarningDialog = (props) => {
>
<ModalDialog.Header>{t("Common:Warning")}</ModalDialog.Header>
<ModalDialog.Body>
{isGracePeriod ? (
<>
<Text fontWeight={700} noSelect>
{t("BusinessPlanPaymentOverdue", {
planName: currentTariffPlanTitle,
})}
</Text>
<br />
<Text noSelect as="div">
<Trans t={t} i18nKey="GracePeriodActivatedInfo" ns="Payments">
Grace period activated
<strong>
from {{ fromDate }} to {{ byDate }}
</strong>
(days remaining: {{ delayDaysCount }})
</Trans>
</Text>
<br />
<Text>{t("GracePeriodActivatedDescription")}</Text>
</>
) : (
<>
<Text fontWeight={700} noSelect>
{t("PaymentOverdue")}
</Text>
<br />
<Text>{t("UpgradePlanInfo")}</Text>
<br />
<Text>{t("ChooseNewPlan")}</Text>
</>
)}
{
isGracePeriod ? (
contentForGracePeriod
) : isAccounts ? (
<UsersContent />
) : (
<RoomsContent />
)
// <>
// <Text fontWeight={700} noSelect>
// {t("PaymentOverdue")}
// </Text>
// <br />
// <Text>{t("UpgradePlanInfo")}</Text>
// <br />
// <Text>{t("ChooseNewPlan")}</Text>
// </>
}
</ModalDialog.Body>
<ModalDialog.Footer>
<Button
@ -161,7 +177,8 @@ export default inject(
}) => {
const { isPaymentPageAvailable } = authStore;
const { dueDate, delayDueDate, isGracePeriod } = currentTariffStatusStore;
const { currentTariffPlanTitle } = currentQuotaStore;
const { currentTariffPlanTitle, isRoomsTariffLimit, isUserTariffLimit } =
currentQuotaStore;
const {
inviteUsersWarningDialogVisible,
@ -177,6 +194,8 @@ export default inject(
dueDate,
delayDueDate,
isGracePeriod,
isRoomsTariffLimit,
isUserTariffLimit,
};
},
)(observer(withTranslation(["Payments", "Common"])(InviteUsersWarningDialog)));

View File

@ -0,0 +1,56 @@
// (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 { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
import { Text } from "@docspace/shared/components/text";
export interface RoomsContentProps {
isRoomsTariffLimit: boolean;
}
const RoomsContent = ({ isRoomsTariffLimit }: RoomsContentProps) => {
const { t } = useTranslation(["Payments", "Common"]);
if (isRoomsTariffLimit)
return (
<>
<Text fontWeight={600}>{t("CannotCreateNewRoom")}</Text>
<br />
<Text>{t("NewRoomWillExceedLimit")}</Text>
<br />
<Text>{t("ChooseNewPlan")}</Text>
</>
);
};
export default inject(({ currentQuotaStore }) => {
const { isRoomsTariffLimit } = currentQuotaStore;
return {
isRoomsTariffLimit,
};
})(observer(RoomsContent));

View File

@ -0,0 +1,82 @@
// (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
// (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 { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
import { Text } from "@docspace/shared/components/text";
export interface UsersContentProps {
isUserTariffLimit: boolean;
}
const UsersContent = ({ isUserTariffLimit }: UsersContentProps) => {
const { t } = useTranslation(["Payments", "Common"]);
if (isUserTariffLimit)
return (
<>
<Text fontWeight={600}>{t("CannotCreatePaidUsers")}</Text>
<br />
<Text>{t("NewUsersWillExceedMembersLimit")}</Text>
<br />
<Text>{t("ChooseNewPlan")}</Text>
</>
);
};
export default inject(({ currentQuotaStore }) => {
const { isUserTariffLimit } = currentQuotaStore;
return {
isUserTariffLimit,
};
})(observer(UsersContent));

View File

@ -886,14 +886,14 @@ class ContextOptionsStore {
onClickArchive = (e) => {
const data = (e.currentTarget && e.currentTarget.dataset) || e;
const { action } = data;
const { isGracePeriod } = this.currentTariffStatusStore;
const { isWarningRoomsDialog } = this.currentQuotaStore;
const {
setArchiveDialogVisible,
setRestoreRoomDialogVisible,
setInviteUsersWarningDialogVisible,
} = this.dialogsStore;
if (action === "unarchive" && isGracePeriod) {
if (action === "unarchive" && isWarningRoomsDialog) {
setInviteUsersWarningDialogVisible(true);
return;
}
@ -1117,7 +1117,7 @@ class ContextOptionsStore {
if (isExistActiveItems) return;
if (this.currentTariffStatusStore.isGracePeriod) {
if (this.currentQuotaStore.isWarningRoomsDialog) {
setInviteUsersWarningDialogVisible(true);
return;
}
@ -2138,7 +2138,7 @@ class ContextOptionsStore {
};
onCreateRoom = () => {
if (this.currentTariffStatusStore.isGracePeriod) {
if (this.currentQuotaStore.isWarningRoomsDialog) {
this.dialogsStore.setInviteUsersWarningDialogVisible(true);
return;
}

View File

@ -1799,9 +1799,10 @@ class FilesActionStore {
setInviteUsersWarningDialogVisible,
setRestoreRoomDialogVisible,
} = this.dialogsStore;
const { isGracePeriod } = this.currentTariffStatusStore;
if (action === "unarchive" && isGracePeriod) {
const { isWarningRoomsDialog } = this.currentQuotaStore;
if (action === "unarchive" && isWarningRoomsDialog) {
setInviteUsersWarningDialogVisible(true);
return;
}

View File

@ -259,6 +259,14 @@ class CurrentQuotasStore {
);
}
get isRoomsTariffLimit() {
return (
this.maxCountRoomsByQuota - this.usedRoomsCount <=
COUNT_FOR_SHOWING_BAR &&
this.usedRoomsCount >= this.maxCountRoomsByQuota
);
}
get isStorageTariffAlmostLimit() {
return (
(this.usedTotalStorageSizeCount / this.maxTotalSizeByQuota) * 100 >=
@ -326,6 +334,12 @@ class CurrentQuotasStore {
return this.currentTariffStatusStore?.isGracePeriod;
};
get isWarningRoomsDialog() {
return (
this.currentTariffStatusStore?.isGracePeriod || this.isRoomsTariffLimit
);
}
get isPersonalQuotaLimit() {
const personalQuotaLimitReached = this.userStore?.personalQuotaLimitReached;