Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enterprise upgrade modal changes & fixes #946

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/src/i18n/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const en: BaseTranslation = {
enterprise: {
title: 'Upgrade to Enterprise',
//md
subTitle: `This functionality is an **enterprise feature** and requires purchasing a license to enable it.`,
subTitle: `This functionality is an **enterprise feature** and you've exceeded the user, device or network limits to use it. In order to use this feature, purchase an enterprise license or upgrade your existing one.`,
},
limit: {
title: 'Upgrade',
Expand Down
4 changes: 2 additions & 2 deletions web/src/i18n/i18n-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ type RootTranslation = {
*/
title: string
/**
* T​h​i​s​ ​f​u​n​c​t​i​o​n​a​l​i​t​y​ ​i​s​ ​a​n​ ​*​*​e​n​t​e​r​p​r​i​s​e​ ​f​e​a​t​u​r​e​*​*​ ​a​n​d​ ​r​e​q​u​i​r​e​s​ ​p​u​r​c​h​a​s​i​n​g​ ​a​ ​l​i​c​e​n​s​e​ ​t​o​ ​e​n​a​b​l​e​ ​i​t​.
* T​h​i​s​ ​f​u​n​c​t​i​o​n​a​l​i​t​y​ ​i​s​ ​a​n​ ​*​*​e​n​t​e​r​p​r​i​s​e​ ​f​e​a​t​u​r​e​*​*​ ​a​n​d​ ​y​o​u​'​v​e​ ​e​x​c​e​e​d​e​d​ ​t​h​e​ ​u​s​e​r​,​ ​d​e​v​i​c​e​ ​o​r​ ​n​e​t​w​o​r​k​ ​l​i​m​i​t​s​ ​t​o​ ​u​s​e​ ​i​t​.​ ​I​n​ ​o​r​d​e​r​ ​t​o​ ​u​s​e​ ​t​h​i​s​ ​f​e​a​t​u​r​e​,​ ​p​u​r​c​h​a​s​e​ ​a​n​ ​e​n​t​e​r​p​r​i​s​e​ ​l​i​c​e​n​s​e​ ​o​r​ ​u​p​g​r​a​d​e​ ​y​o​u​r​ ​e​x​i​s​t​i​n​g​ ​o​n​e​.
*/
subTitle: string
}
Expand Down Expand Up @@ -4969,7 +4969,7 @@ export type TranslationFunctions = {
*/
title: () => LocalizedString
/**
* This functionality is an **enterprise feature** and requires purchasing a license to enable it.
* This functionality is an **enterprise feature** and you've exceeded the user, device or network limits to use it. In order to use this feature, purchase an enterprise license or upgrade your existing one.
*/
subTitle: () => LocalizedString
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ import { useNavigate } from 'react-router';
import { shallow } from 'zustand/shallow';

import { useI18nContext } from '../../../../i18n/i18n-react';
import { useUpgradeLicenseModal } from '../../../../shared/components/Layout/UpgradeLicenseModal/store';
import { UpgradeLicenseModalVariant } from '../../../../shared/components/Layout/UpgradeLicenseModal/types';
import { DeviceConfigsCard } from '../../../../shared/components/network/DeviceConfigsCard/DeviceConfigsCard';
import { Card } from '../../../../shared/defguard-ui/components/Layout/Card/Card';
import { Input } from '../../../../shared/defguard-ui/components/Layout/Input/Input';
import { MessageBox } from '../../../../shared/defguard-ui/components/Layout/MessageBox/MessageBox';
import { MessageBoxType } from '../../../../shared/defguard-ui/components/Layout/MessageBox/types';
import { useAppStore } from '../../../../shared/hooks/store/useAppStore';
import { useAuthStore } from '../../../../shared/hooks/store/useAuthStore';
import { useEnterpriseUpgradeStore } from '../../../../shared/hooks/store/useEnterpriseUpgradeStore';
import useApi from '../../../../shared/hooks/useApi';
import { useAddDevicePageStore } from '../../hooks/useAddDevicePageStore';

Expand All @@ -31,7 +30,7 @@ export const AddDeviceConfigStep = () => {
const { getAppInfo } = useApi();
const isAdmin = useAuthStore((s) => s.user?.is_admin);
const setAppStore = useAppStore((s) => s.setState);
const openUpgradeLicenseModal = useUpgradeLicenseModal((s) => s.open, shallow);
const showUpgradeToast = useEnterpriseUpgradeStore((s) => s.show);

const [userData, device, publicKey, privateKey, networks] = useAddDevicePageStore(
(state) => [
Expand Down Expand Up @@ -63,9 +62,7 @@ export const AddDeviceConfigStep = () => {
void getAppInfo().then((response) => {
setAppStore({ appInfo: response });
if (response.license_info.any_limit_exceeded) {
openUpgradeLicenseModal({
modalVariant: UpgradeLicenseModalVariant.LICENSE_LIMIT,
});
showUpgradeToast();
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { useNavigate } from 'react-router';
import { shallow } from 'zustand/shallow';

import { useI18nContext } from '../../../../i18n/i18n-react';
import { useUpgradeLicenseModal } from '../../../../shared/components/Layout/UpgradeLicenseModal/store';
import { UpgradeLicenseModalVariant } from '../../../../shared/components/Layout/UpgradeLicenseModal/types';
import { ActionButton } from '../../../../shared/defguard-ui/components/Layout/ActionButton/ActionButton';
import { ActionButtonVariant } from '../../../../shared/defguard-ui/components/Layout/ActionButton/types';
import { Card } from '../../../../shared/defguard-ui/components/Layout/Card/Card';
Expand All @@ -17,6 +15,7 @@ import { MessageBox } from '../../../../shared/defguard-ui/components/Layout/Mes
import { MessageBoxType } from '../../../../shared/defguard-ui/components/Layout/MessageBox/types';
import { useAppStore } from '../../../../shared/hooks/store/useAppStore';
import { useAuthStore } from '../../../../shared/hooks/store/useAuthStore';
import { useEnterpriseUpgradeStore } from '../../../../shared/hooks/store/useEnterpriseUpgradeStore';
import useApi from '../../../../shared/hooks/useApi';
import { useClipboard } from '../../../../shared/hooks/useClipboard';
import { useAddDevicePageStore } from '../../hooks/useAddDevicePageStore';
Expand All @@ -28,7 +27,7 @@ export const AddDeviceTokenStep = () => {
const navigate = useNavigate();
const { getAppInfo } = useApi();
const setAppStore = useAppStore((s) => s.setState, shallow);
const openUpgradeLicenseModal = useUpgradeLicenseModal((s) => s.open, shallow);
const showUpgradeToast = useEnterpriseUpgradeStore((s) => s.show);
const isAdmin = useAuthStore((s) => s.user?.is_admin);

const userData = useAddDevicePageStore((state) => state.userData);
Expand Down Expand Up @@ -84,9 +83,7 @@ export const AddDeviceTokenStep = () => {
appInfo: response,
});
if (response.license_info.any_limit_exceeded) {
openUpgradeLicenseModal({
modalVariant: UpgradeLicenseModalVariant.LICENSE_LIMIT,
});
showUpgradeToast();
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { EditButton } from '../../../../../shared/defguard-ui/components/Layout/
import { EditButtonOption } from '../../../../../shared/defguard-ui/components/Layout/EditButton/EditButtonOption';
import { EditButtonOptionStyleVariant } from '../../../../../shared/defguard-ui/components/Layout/EditButton/types';
import { Label } from '../../../../../shared/defguard-ui/components/Layout/Label/Label';
import { LimitedText } from '../../../../../shared/defguard-ui/components/Layout/LimitedText/LimitedText';
import { NoData } from '../../../../../shared/defguard-ui/components/Layout/NoData/NoData';
import { useAppStore } from '../../../../../shared/hooks/store/useAppStore';
import { useUserProfileStore } from '../../../../../shared/hooks/store/useUserProfileStore';
Expand Down Expand Up @@ -107,21 +108,22 @@ export const DeviceCard = ({ device, modifiable }: Props) => {
<h3 data-testid="device-name">{device.name}</h3>
</header>
<div className="section-content">
<div>
<div className="limited">
<Label>{LL.userPage.devices.card.labels.publicIP()}</Label>
{latestLocation?.last_connected_ip && (
<p data-testid="device-last-connected-from">
{latestLocation.last_connected_ip}
</p>
<LimitedText
text={latestLocation.last_connected_ip}
testId="device-last-connected-from"
/>
)}
{!latestLocation?.last_connected_ip && (
<NoData customMessage={LL.userPage.devices.card.labels.noData()} />
)}
</div>
<div>
<div className="limited">
<Label>{LL.userPage.devices.card.labels.connectedThrough()}</Label>
{latestLocation && latestLocation.last_connected_at && (
<p>{latestLocation?.network_name}</p>
<LimitedText text={latestLocation?.network_name} />
)}
{!latestLocation?.last_connected_at && (
<NoData customMessage={LL.userPage.devices.card.labels.noData()} />
Expand Down Expand Up @@ -220,10 +222,10 @@ const DeviceLocation = ({
</div>
</header>
<div className="section-content">
<div>
<div className="limited">
<Label>{LL.userPage.devices.card.labels.lastLocation()}</Label>
{last_connected_ip && (
<p data-testid="device-last-connected-from">{last_connected_ip}</p>
<LimitedText text={last_connected_ip} testId="device-last-connected-from" />
)}
{!last_connected_ip && (
<NoData customMessage={LL.userPage.devices.card.labels.noData()} />
Expand All @@ -238,9 +240,9 @@ const DeviceLocation = ({
<NoData customMessage={LL.userPage.devices.card.labels.noData()} />
)}
</div>
<div>
<div className="limited">
<Label>{LL.userPage.devices.card.labels.assignedIp()}</Label>
<p data-testid="device-assigned-ip">{device_wireguard_ip}</p>
<LimitedText text={device_wireguard_ip} testId="device-assigned-ip" />
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
max-width: 100%;
}

.limited {
max-width: 120px;
}

.main-info {
& > header {
grid-template-rows: 40px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { z } from 'zod';
import { shallow } from 'zustand/shallow';

import { useI18nContext } from '../../../../../../../i18n/i18n-react';
import { useUpgradeLicenseModal } from '../../../../../../../shared/components/Layout/UpgradeLicenseModal/store';
import { UpgradeLicenseModalVariant } from '../../../../../../../shared/components/Layout/UpgradeLicenseModal/types';
import { FormCheckBox } from '../../../../../../../shared/defguard-ui/components/Form/FormCheckBox/FormCheckBox';
import { FormInput } from '../../../../../../../shared/defguard-ui/components/Form/FormInput/FormInput';
import { Button } from '../../../../../../../shared/defguard-ui/components/Layout/Button/Button';
Expand All @@ -20,6 +18,7 @@ import {
ButtonStyleVariant,
} from '../../../../../../../shared/defguard-ui/components/Layout/Button/types';
import { useAppStore } from '../../../../../../../shared/hooks/store/useAppStore';
import { useEnterpriseUpgradeStore } from '../../../../../../../shared/hooks/store/useEnterpriseUpgradeStore';
import useApi from '../../../../../../../shared/hooks/useApi';
import { useToaster } from '../../../../../../../shared/hooks/useToaster';
import {
Expand Down Expand Up @@ -140,7 +139,7 @@ export const AddUserForm = () => {

const setAppStore = useAppStore((s) => s.setState, shallow);

const openUpgradeLicenseModal = useUpgradeLicenseModal((s) => s.open, shallow);
const showUpgradeToast = useEnterpriseUpgradeStore((s) => s.show);

const toaster = useToaster();

Expand All @@ -158,11 +157,7 @@ export const AddUserForm = () => {
appInfo: response,
});
if (response.license_info.any_limit_exceeded) {
openUpgradeLicenseModal({
modalVariant: response.license_info.enterprise
? UpgradeLicenseModalVariant.LICENSE_LIMIT
: UpgradeLicenseModalVariant.ENTERPRISE_NOTICE,
});
showUpgradeToast();
}
});

Expand Down
9 changes: 3 additions & 6 deletions web/src/pages/wizard/components/WizardNav/WizardNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { useNavigate } from 'react-router';
import { shallow } from 'zustand/shallow';

import { useI18nContext } from '../../../../i18n/i18n-react';
import { useUpgradeLicenseModal } from '../../../../shared/components/Layout/UpgradeLicenseModal/store';
import { UpgradeLicenseModalVariant } from '../../../../shared/components/Layout/UpgradeLicenseModal/types';
import DefguardNoIcon from '../../../../shared/components/svg/DefguardNoIcon';
import SvgIconArrowGrayLeft from '../../../../shared/components/svg/IconArrowGrayLeft';
import SvgIconArrowGrayRight from '../../../../shared/components/svg/IconArrowGrayRight';
Expand All @@ -19,6 +17,7 @@ import {
import { Divider } from '../../../../shared/defguard-ui/components/Layout/Divider/Divider';
import { DividerDirection } from '../../../../shared/defguard-ui/components/Layout/Divider/types';
import { useAppStore } from '../../../../shared/hooks/store/useAppStore';
import { useEnterpriseUpgradeStore } from '../../../../shared/hooks/store/useEnterpriseUpgradeStore';
import useApi from '../../../../shared/hooks/useApi';
import { useToaster } from '../../../../shared/hooks/useToaster';
import { QueryKeys } from '../../../../shared/queries';
Expand All @@ -33,7 +32,6 @@ interface Props {

export const WizardNav = ({ title, lastStep, backDisabled = false }: Props) => {
const { getAppInfo } = useApi();
const openUpgradeLicenseModal = useUpgradeLicenseModal((s) => s.open, shallow);
const setAppState = useAppStore((s) => s.setState, shallow);
const queryClient = useQueryClient();
const { LL } = useI18nContext();
Expand All @@ -54,6 +52,7 @@ export const WizardNav = ({ title, lastStep, backDisabled = false }: Props) => {
],
shallow,
);
const showUpgradeToast = useEnterpriseUpgradeStore((s) => s.show);

useEffect(() => {
const sub = nextSubject.subscribe(() => {
Expand All @@ -64,9 +63,7 @@ export const WizardNav = ({ title, lastStep, backDisabled = false }: Props) => {
void getAppInfo().then((response) => {
setAppState({ appInfo: response });
if (response.license_info.any_limit_exceeded) {
openUpgradeLicenseModal({
modalVariant: UpgradeLicenseModalVariant.LICENSE_LIMIT,
});
showUpgradeToast();
}
});
navigate('/admin/overview', { replace: true });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import './style.scss';

import { useCallback } from 'react';

import { useI18nContext } from '../../../../i18n/i18n-react';
import { Badge } from '../../../defguard-ui/components/Layout/Badge/Badge';
import { BadgeStyleVariant } from '../../../defguard-ui/components/Layout/Badge/types';
import { ToastOptions } from '../../../defguard-ui/components/Layout/ToastManager/Toast/types';
import { useToastsStore } from '../../../defguard-ui/hooks/toasts/useToastStore';
import SvgIconX from '../../svg/IconX';

export const EnterpriseUpgradeToast = ({ id }: ToastOptions) => {
const removeToast = useToastsStore((s) => s.removeToast);
const { LL } = useI18nContext();

Check failure on line 14 in web/src/shared/components/Layout/EnterpriseUpgradeToast/EnterpriseUpgradeToast.tsx

View workflow job for this annotation

GitHub Actions / lint-web

'LL' is assigned a value but never used

const closeToast = useCallback(() => {
removeToast(id);
}, [id, removeToast]);

const handleDismiss = () => {
closeToast();
};

return (
<div className="enterprise-upgrade-toaster">
<div className="top">
<div className="heading">
<Badge
styleVariant={BadgeStyleVariant.PRIMARY}
icon={
<svg
width="8"
height="10"
viewBox="0 0 8 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.75294 0.891119C4.75294 0.553623 4.47935 0.280029 4.14185 0.280029C3.80436 0.280029 3.53076 0.553623 3.53076 0.891119V9.38893C3.53076 9.72642 3.80436 10 4.14185 10C4.47935 10 4.75294 9.72642 4.75294 9.38893V0.891119Z"
fill="white"
/>
<path
d="M4.54343 1.29638C4.78208 1.05773 4.78208 0.670812 4.54343 0.432167C4.30479 0.193521 3.91787 0.193521 3.67922 0.432167L1.51869 2.59269C1.28005 2.83134 1.28005 3.21826 1.5187 3.45691C1.75734 3.69555 2.14426 3.69555 2.38291 3.45691L4.54343 1.29638Z"
fill="white"
/>
<path
d="M4.5739 0.432152C4.33526 0.193507 3.94834 0.193507 3.70969 0.432152C3.47105 0.670798 3.47105 1.05772 3.70969 1.29636L5.87022 3.45689C6.10887 3.69554 6.49579 3.69554 6.73443 3.45689C6.97308 3.21825 6.97308 2.83132 6.73443 2.59268L4.5739 0.432152Z"
fill="white"
/>
</svg>
}
className="toaster-badge"
/>
<p>You've reached the enterprise functionality limit.</p>

Check failure on line 54 in web/src/shared/components/Layout/EnterpriseUpgradeToast/EnterpriseUpgradeToast.tsx

View workflow job for this annotation

GitHub Actions / lint-web

`'` can be escaped with `&apos;`, `&lsquo;`, `&#39;`, `&rsquo;`
</div>
<button className="dismiss" onClick={handleDismiss}>
<SvgIconX width={14} height={14} />
</button>
</div>
<div className="bottom">
<p>
You have exceeded the limit of your current Defguard plan and the enterprise
features will be disabled. Purchase an enterprise license or upgrade your
exsiting one to continue using these features.
</p>
<div className="upgrade-link-container">
<a
href="https://defguard.net/pricing/"
target="_blank"
rel="noreferrer noopener"
className="upgrade-link"
>
See all enterprise plans
</a>
</div>
</div>
</div>
);
};
Loading
Loading