Skip to content

Commit

Permalink
Simplify upselling refs and upgrade navigation
Browse files Browse the repository at this point in the history
[IDTEAM-2511]
  • Loading branch information
edvincandon committed Dec 21, 2023
1 parent 9ab9906 commit deca57d
Show file tree
Hide file tree
Showing 30 changed files with 167 additions and 164 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState, type VFC } from 'react';
import { type VFC, useCallback, useEffect, useState } from 'react';

import { PauseListDropdown } from 'proton-pass-extension/app/content/injections/apps/common/PauseListDropdown';
import { useIFrameContext } from 'proton-pass-extension/app/content/injections/apps/context/IFrameContextProvider';
Expand All @@ -11,14 +11,13 @@ import { c } from 'ttag';
import { CircleLoader } from '@proton/atoms/CircleLoader';
import { AliasPreview } from '@proton/pass/components/Alias/legacy/Alias.preview';
import { SubTheme } from '@proton/pass/components/Layout/Theme/types';
import { PASS_EOY_PATH, PASS_REF_EXTENSION_ALIAS, PASS_UPGRADE_PATH } from '@proton/pass/constants';
import { UpsellRef } from '@proton/pass/constants';
import { useEnsureMounted } from '@proton/pass/hooks/useEnsureMounted';
import { useNavigateToUpgrade } from '@proton/pass/hooks/useNavigateToUpgrade';
import { contentScriptMessage, sendMessage } from '@proton/pass/lib/extension/message';
import { isEOY } from '@proton/pass/lib/onboarding/utils';
import { createTelemetryEvent } from '@proton/pass/lib/telemetry/event';
import type { AliasOptions, AliasState } from '@proton/pass/store/reducers';
import { WorkerMessageType, type MaybeNull } from '@proton/pass/types';
import { type MaybeNull, WorkerMessageType } from '@proton/pass/types';
import { TelemetryEventName } from '@proton/pass/types/data/telemetry';
import { PASS_APP_NAME } from '@proton/shared/lib/constants';
import { wait } from '@proton/shared/lib/helpers/promise';
Expand All @@ -39,7 +38,7 @@ const getInitialLoadingText = (): string => c('Info').t`Generating alias...`;

export const AliasAutoSuggest: VFC<Props> = ({ hostname, prefix, visible, onClose, onMessage }) => {
const ensureMounted = useEnsureMounted();
const navigateToUpgrade = useNavigateToUpgrade(`${isEOY() ? PASS_EOY_PATH : PASS_UPGRADE_PATH }&${PASS_REF_EXTENSION_ALIAS}`);
const navigateToUpgrade = useNavigateToUpgrade({ upsellRef: UpsellRef.LIMIT_ALIAS });
const { userEmail } = useIFrameContext();
const [aliasOptions, setAliasOptions] = useState<MaybeNull<AliasState['aliasOptions']>>(null);
const [needsUpgrade, setNeedsUpgrade] = useState<boolean>(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import type { IFrameCloseOptions, IFrameMessage } from 'proton-pass-extension/ap
import { IFrameMessageType } from 'proton-pass-extension/app/content/types';
import { c } from 'ttag';

import { PASS_EOY_PATH, PASS_REF_EXTENSION_AUTOFILL } from '@proton/pass/constants';
import { UpsellRef } from '@proton/pass/constants';
import { useNavigateToUpgrade } from '@proton/pass/hooks/useNavigateToUpgrade';
import { contentScriptMessage, sendMessage } from '@proton/pass/lib/extension/message';
import { createTelemetryEvent } from '@proton/pass/lib/telemetry/event';
import { WorkerMessageType, type SafeLoginItem } from '@proton/pass/types';
import { type SafeLoginItem, WorkerMessageType } from '@proton/pass/types';
import { PassIconStatus } from '@proton/pass/types/data/pass-icon';
import { TelemetryEventName } from '@proton/pass/types/data/telemetry';
import { truthy } from '@proton/pass/utils/fp/predicates';
Expand All @@ -24,14 +24,14 @@ type Props = {
items: SafeLoginItem[];
hostname: string;
needsUpgrade: boolean;
ref?: string;
visible?: boolean;
onClose?: (options?: IFrameCloseOptions) => void;
onMessage?: (message: IFrameMessage) => void;
};

export const ItemsList: VFC<Props> = ({ hostname, items, needsUpgrade, ref, visible, onMessage, onClose }) => {
export const ItemsList: VFC<Props> = ({ hostname, items, needsUpgrade, visible, onMessage, onClose }) => {
const { settings } = useIFrameContext();
const navigateToUpgrade = useNavigateToUpgrade({ upsellRef: UpsellRef.LIMIT_AUTOFILL });

useEffect(() => {
if (visible) {
Expand All @@ -55,7 +55,7 @@ export const ItemsList: VFC<Props> = ({ hostname, items, needsUpgrade, ref, visi
icon="arrow-out-square"
title={c('Info').t`Upgrade ${PASS_APP_NAME}`}
subTitle={c('Warning').t`Your plan only allows you to autofill from your first two vaults`}
onClick={useNavigateToUpgrade(`${PASS_EOY_PATH}&ref=${PASS_REF_EXTENSION_AUTOFILL}`)}
onClick={navigateToUpgrade}
autogrow
/>
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { VFC } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState, type ComponentProps, type FC } from 'react';
import { type ComponentProps, type FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Provider as ReduxProvider, useSelector } from 'react-redux';
import { HashRouter, Route, Switch, useHistory } from 'react-router-dom';

Expand All @@ -16,14 +16,15 @@ import { Avatar } from '@proton/atoms/Avatar';
import { Icon, Tabs, useNotifications } from '@proton/components';
import { UpgradeButton } from '@proton/pass/components/Layout/Button/UpgradeButton';
import { LockConfirmContextProvider } from '@proton/pass/components/Lock/LockConfirmContextProvider';
import { UpsellRef } from '@proton/pass/constants';
import { pageMessage } from '@proton/pass/lib/extension/message';
import {
selectPassPlan,
selectPlanDisplayName,
selectTrialDaysRemaining,
selectUser,
} from '@proton/pass/store/selectors';
import { AppStatus, WorkerMessageType, type Unpack, type WorkerMessageWithSender } from '@proton/pass/types';
import { AppStatus, type Unpack, WorkerMessageType, type WorkerMessageWithSender } from '@proton/pass/types';
import { UserPassPlan } from '@proton/pass/types/api/plan';
import { PASS_APP_NAME } from '@proton/shared/lib/constants';

Expand All @@ -34,8 +35,6 @@ import { Import } from './Views/Import';
import { Security } from './Views/Security';
import { Support } from './Views/Support';

import { PASS_EOY_PATH, PASS_REF_EXTENSION_SETTINGS, PASS_UPGRADE_PATH } from '@proton/pass/constants';
import { isEOY } from '@proton/pass/lib/onboarding/utils';
import './Settings.scss';

type Tab = Unpack<Exclude<ComponentProps<typeof Tabs>['tabs'], undefined>>;
Expand Down Expand Up @@ -129,7 +128,7 @@ const SettingsTabs: FC<{ pathname: string }> = ({ pathname }) => {
)})`}
</span>
</span>
<UpgradeButton inline path={isEOY() ? PASS_EOY_PATH : PASS_UPGRADE_PATH} ref={PASS_REF_EXTENSION_SETTINGS} />
<UpgradeButton inline upsellRef={UpsellRef.SETTING} />
</>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ import { Submenu } from '@proton/pass/components/Menu/Submenu';
import { VaultMenu } from '@proton/pass/components/Menu/Vault/VaultMenu';
import { useVaultActions } from '@proton/pass/components/Vault/VaultActionsProvider';
import { VaultIcon } from '@proton/pass/components/Vault/VaultIcon';
import { PASS_EOY_PATH, PASS_REF_EXTENSION_MENU, PASS_UPGRADE_PATH } from '@proton/pass/constants';
import { UpsellRef } from '@proton/pass/constants';
import { useMenuItems } from '@proton/pass/hooks/useMenuItems';
import { isEOY } from '@proton/pass/lib/onboarding/utils';
import {
selectHasRegisteredLock,
selectPassPlan,
Expand Down Expand Up @@ -135,7 +134,7 @@ export const MenuDropdown: VFC = () => {

{passPlan !== UserPassPlan.PLUS && (
<div className="pb-2 px-4">
<UpgradeButton className="w-full" path={isEOY() ? PASS_EOY_PATH : PASS_UPGRADE_PATH} ref={PASS_REF_EXTENSION_MENU} />
<UpgradeButton className="w-full" upsellRef={UpsellRef.MENU} />
</div>
)}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo, type MouseEvent, type VFC } from 'react';
import { type MouseEvent, type VFC, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';

Expand All @@ -10,13 +10,11 @@ import { c } from 'ttag';
import { Button } from '@proton/atoms/Button';
import type { IconName } from '@proton/components/components';
import { Icon } from '@proton/components/components';
import { usePassCore } from '@proton/pass/components/Core/PassCoreProvider';
import { UpgradeButton } from '@proton/pass/components/Layout/Button/UpgradeButton';
import { Card } from '@proton/pass/components/Layout/Card/Card';
import { itemTypeToIconName } from '@proton/pass/components/Layout/Icon/ItemIcon';
import { SubTheme } from '@proton/pass/components/Layout/Theme/types';
import { PASS_EOY_PATH, PASS_REF_EXTENSION_VAULT, PASS_REF_WEB_VAULT, PASS_UPGRADE_PATH } from '@proton/pass/constants';
import { isEOY } from '@proton/pass/lib/onboarding/utils';
import { UpsellRef } from '@proton/pass/constants';
import { isWritableVault } from '@proton/pass/lib/vaults/vault.predicates';
import { selectAllVaults, selectOwnReadOnlyVaults, selectShare, selectVaultLimits } from '@proton/pass/store/selectors';
import type { ItemType } from '@proton/pass/types';
Expand All @@ -33,7 +31,6 @@ type QuickAction = {

export const ItemsListPlaceholder: VFC = () => {
const history = useHistory();
const {endpoint} = usePassCore();
const openSettings = useOpenSettingsTab();

const { isCreating } = useNavigationContext();
Expand Down Expand Up @@ -99,7 +96,7 @@ export const ItemsListPlaceholder: VFC = () => {
{c('Info')
.t`You have exceeded the number of vaults included in your subscription. New items can only be created in your first two vaults. To create new items in all vaults upgrade your subscription.`}
</Card>
<UpgradeButton path={isEOY() ? PASS_EOY_PATH : PASS_UPGRADE_PATH} ref={endpoint === 'web' ? PASS_REF_WEB_VAULT : PASS_REF_EXTENSION_VAULT} />
<UpgradeButton upsellRef={UpsellRef.LIMIT_VAULT} />
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { useEffect } from 'react';
import { useSelector } from 'react-redux';

import { useSpotlight } from '@proton/pass/components/Spotlight/SpotlightProvider';
import { UpsellRef } from '@proton/pass/constants';
import { useOnboardingMessages } from '@proton/pass/hooks/useOnboardingMessages';
import { popupMessage, sendMessage } from '@proton/pass/lib/extension/message';
import { isEOY } from '@proton/pass/lib/onboarding/upselling';
import { selectCreatedItemsCount } from '@proton/pass/store/selectors';
import type { WorkerMessageWithSender } from '@proton/pass/types';
import { OnboardingMessage, WorkerMessageType } from '@proton/pass/types';
Expand Down Expand Up @@ -36,7 +38,13 @@ export const useOnboardingListener = () => {
async ({ message }) => {
await wait(200);
if (message === OnboardingMessage.PENDING_SHARE_ACCESS) setPendingShareAccess(true);
if (message === OnboardingMessage.EARLY_ACCESS) setUpselling('early-access');
if (message === OnboardingMessage.EARLY_ACCESS) {
setUpselling({
type: 'early-access',
upsellRef: isEOY() ? UpsellRef.EOY_2023 : UpsellRef.EARLY_ACCESS,
});
}

setOnboardingMessage(message ? definitions[message] ?? null : null);
}
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useCallback, type VFC } from 'react';
import { type VFC, useCallback } from 'react';
import { useSelector } from 'react-redux';

import { UpsellRef } from '@proton/pass/constants';
import { selectExtraFieldLimits } from '@proton/pass/store/selectors';
import type { UnsafeItemExtraField } from '@proton/pass/types';
import { isEmptyString } from '@proton/pass/utils/string/is-empty-string';

import { PASS_REF_EXTENSION_EXTRA_FIELD } from '@proton/pass/constants';
import { TextAreaReadonly } from '../../legacy/TextAreaReadonly';
import { getExtraFieldOption } from '../ExtraFieldGroup/ExtraField';
import { FieldsetCluster } from '../Layout/FieldsetCluster';
Expand All @@ -28,7 +28,9 @@ export const ExtraFieldsControl: VFC<ExtraFieldsControlProps> = ({ extraFields,
const key = `${index}-${fieldName}`;

if (needsUpgrade) {
return <UpgradeControl icon={icon} key={key} label={fieldName} ref={PASS_REF_EXTENSION_EXTRA_FIELD} />;
return (
<UpgradeControl icon={icon} key={key} label={fieldName} upsellRef={UpsellRef.LIMIT_EXTRA_FIELD} />
);
}

switch (type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ import { type VFC } from 'react';

import { type IconName } from '@proton/components/components';
import { UpgradeButton } from '@proton/pass/components/Layout/Button/UpgradeButton';
import { type UpsellRef } from '@proton/pass/constants';

import { PASS_EOY_PATH, PASS_UPGRADE_PATH } from '@proton/pass/constants';
import { isEOY } from '@proton/pass/lib/onboarding/utils';
import { ValueControl } from './ValueControl';

type UpgradeControlProps = {
icon: IconName;
label: string;
ref: string;
upsellRef: UpsellRef;
};

export const UpgradeControl: VFC<UpgradeControlProps> = ({ icon, label, ref }) => (
export const UpgradeControl: VFC<UpgradeControlProps> = ({ icon, label, upsellRef }) => (
<ValueControl icon={icon} label={label}>
<UpgradeButton inline ref={ref} path={isEOY() ? PASS_EOY_PATH : PASS_UPGRADE_PATH} />
<UpgradeButton inline upsellRef={upsellRef} />
</ValueControl>
);
7 changes: 2 additions & 5 deletions packages/pass/components/Import/ImportVaultsPickerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Button } from '@proton/atoms/Button';
import { Card } from '@proton/atoms/Card';
import type { ModalProps } from '@proton/components/components';
import { ModalTwo, ModalTwoContent, ModalTwoFooter, ModalTwoHeader } from '@proton/components/components';
import { UpsellRef } from '@proton/pass/constants';
import { type ImportPayload, type ImportVault } from '@proton/pass/lib/import/types';
import {
selectDefaultVault,
Expand All @@ -19,9 +20,6 @@ import {
import { UserPassPlan } from '@proton/pass/types/api/plan';
import { omit } from '@proton/shared/lib/helpers/object';

import { usePassCore } from '@proton/pass/components/Core/PassCoreProvider';
import { PASS_EOY_PATH, PASS_REF_EXTENSION_IMPORT, PASS_REF_WEB_IMPORT, PASS_UPGRADE_PATH } from '@proton/pass/constants';
import { isEOY } from '@proton/pass/lib/onboarding/utils';
import { UpgradeButton } from '../Layout/Button/UpgradeButton';
import { ImportVaultPickerOption } from './ImportVaultsPickerOption';

Expand All @@ -40,7 +38,6 @@ export const ImportVaultsPickerModal: VFC<ImportVaultsPickerProps> = ({ payload,
const defaultVault = useSelector(selectDefaultVault);
const { vaultLimit, vaultTotalCount } = useSelector(selectVaultLimits);
const plan = useSelector(selectPassPlan);
const { endpoint } = usePassCore();

const handleSubmit = useCallback(
(values: VaultsPickerFormValues) =>
Expand Down Expand Up @@ -100,7 +97,7 @@ export const ImportVaultsPickerModal: VFC<ImportVaultsPickerProps> = ({ payload,
<>
{c('Warning')
.t`Your subscription does not allow you to create multiple vaults. All items will be imported to your first vault. To import into multiple vaults upgrade your subscription.`}
<UpgradeButton inline className="ml-1" path={isEOY() ? PASS_EOY_PATH : PASS_UPGRADE_PATH} ref={endpoint === 'web' ? PASS_REF_WEB_IMPORT : PASS_REF_EXTENSION_IMPORT} />
<UpgradeButton inline className="ml-1" upsellRef={UpsellRef.LIMIT_IMPORT} />
</>
) : (
c('Warning').t`You cannot create more vaults than your subscription allows.`
Expand Down
15 changes: 9 additions & 6 deletions packages/pass/components/Invite/VaultAccessManager.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useMemo, useState, type FC } from 'react';
import { type FC, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';

import { c, msgid } from 'ttag';

import { Button } from '@proton/atoms/Button';
import { Icon, Prompt } from '@proton/components/components';
import { usePassCore } from '@proton/pass/components/Core/PassCoreProvider';
import { useInviteContext } from '@proton/pass/components/Invite/InviteProvider';
import { UpgradeButton } from '@proton/pass/components/Layout/Button/UpgradeButton';
import { Card } from '@proton/pass/components/Layout/Card/Card';
Expand All @@ -15,9 +14,8 @@ import { PanelHeader } from '@proton/pass/components/Layout/Panel/PanelHeader';
import { ShareMember } from '@proton/pass/components/Share/ShareMember';
import { PendingExistingMember, PendingNewMember } from '@proton/pass/components/Share/SharePendingMember';
import { SharedVaultItem } from '@proton/pass/components/Vault/SharedVaultItem';
import { PASS_EOY_PATH, PASS_REF_EXTENSION_SHARE, PASS_REF_WEB_SHARE, PASS_UPGRADE_PATH } from '@proton/pass/constants';
import { UpsellRef } from '@proton/pass/constants';
import { useShareAccessOptionsPolling } from '@proton/pass/hooks/useShareAccessOptionsPolling';
import { isEOY } from '@proton/pass/lib/onboarding/utils';
import { isShareManageable } from '@proton/pass/lib/shares/share.predicates';
import { isVaultMemberLimitReached } from '@proton/pass/lib/vaults/vault.predicates';
import { selectOwnWritableVaults, selectPassPlan, selectShareOrThrow } from '@proton/pass/store/selectors';
Expand All @@ -40,7 +38,6 @@ export const VaultAccessManager: FC<Props> = ({ shareId }) => {
const canManage = isShareManageable(vault);
const hasMultipleOwnedWritableVaults = useSelector(selectOwnWritableVaults).length > 1;
const [limitModalOpen, setLimitModalOpen] = useState(false);
const { endpoint } = usePassCore();

const members = useMemo<ShareMemberType[]>(() => (vault.members ?? []).sort(sortOn('email', 'ASC')), [vault]);
const invites = useMemo<InviteListItem[]>(
Expand All @@ -64,7 +61,13 @@ export const VaultAccessManager: FC<Props> = ({ shareId }) => {

const warning = (() => {
if (canManage && memberLimitReached) {
const upgradeLink = <UpgradeButton inline label={c('Action').t`Upgrade now to share with more people`} path={isEOY() ? PASS_EOY_PATH : PASS_UPGRADE_PATH} ref={endpoint === 'web' ? PASS_REF_WEB_SHARE : PASS_REF_EXTENSION_SHARE} />;
const upgradeLink = (
<UpgradeButton
inline
label={c('Action').t`Upgrade now to share with more people`}
upsellRef={UpsellRef.LIMIT_SHARING}
/>
);
return plan === UserPassPlan.FREE
? c('Warning').jt`You have reached the limit of users in this vault. ${upgradeLink}`
: c('Warning').t`You have reached the limit of members who can access this vault.`;
Expand Down
Loading

0 comments on commit deca57d

Please sign in to comment.