start removing account
[ProtonMail-WebClient.git] / packages / components / containers / payments / subscription / YourPlanSection.tsx
blob20ea5a4eea4078e6a56e1923eb8361e483de9beb
1 import Loader from '@proton/components/components/loader/Loader';
2 import MozillaInfoPanel from '@proton/components/containers/account/MozillaInfoPanel';
3 import SettingsSectionExtraWide from '@proton/components/containers/account/SettingsSectionExtraWide';
4 import SettingsSectionWide from '@proton/components/containers/account/SettingsSectionWide';
5 import type { APP_NAMES } from '@proton/shared/lib/constants';
6 import { APPS, ORGANIZATION_STATE } from '@proton/shared/lib/constants';
7 import { pick } from '@proton/shared/lib/helpers/object';
8 import { getCanSubscriptionAccessDuoPlan, getHasVpnB2BPlan, isTrial } from '@proton/shared/lib/helpers/subscription';
9 import { FREE_PLAN } from '@proton/shared/lib/subscription/freePlans';
10 import clsx from '@proton/utils/clsx';
12 import {
13     useAddresses,
14     useCalendars,
15     useLoad,
16     useOrganization,
17     usePendingUserInvitations,
18     usePlans,
19     usePreferredPlansMap,
20     useSubscription,
21     useUser,
22     useVPNServersCount,
23 } from '../../../hooks';
24 import { useSubscriptionModal } from './SubscriptionModalProvider';
25 import { resolveUpsellsToDisplay } from './helpers';
26 import { SubscriptionPanel, UpsellPanels, UsagePanel } from './panels';
27 import PendingInvitationsPanel from './panels/PendingInvitationsPanel';
29 import './YourPlanSection.scss';
31 interface Props {
32     app: APP_NAMES;
35 const YourPlanSection = ({ app }: Props) => {
36     const [user] = useUser();
37     const [plansResult, loadingPlans] = usePlans();
38     const plans = plansResult?.plans;
39     const freePlan = plansResult?.freePlan || FREE_PLAN;
40     const [addresses] = useAddresses();
41     const [calendars] = useCalendars();
42     const [subscription, loadingSubscription] = useSubscription();
43     const [organization, loadingOrganization] = useOrganization();
44     const [serversCount, serversCountLoading] = useVPNServersCount();
45     const [invites = []] = usePendingUserInvitations();
46     const [openSubscriptionModal] = useSubscriptionModal();
47     const canAccessDuoPlan = getCanSubscriptionAccessDuoPlan(subscription);
48     const { plansMap } = usePreferredPlansMap();
50     useLoad();
52     const loading = loadingSubscription || loadingOrganization || loadingPlans || serversCountLoading;
54     if (!subscription || !plans || loading) {
55         return <Loader />;
56     }
58     const { isManagedByMozilla } = subscription;
59     if (isManagedByMozilla) {
60         return <MozillaInfoPanel />;
61     }
63     const upsells = resolveUpsellsToDisplay({
64         app,
65         subscription,
66         plansMap,
67         freePlan,
68         serversCount,
69         openSubscriptionModal,
70         canAccessDuoPlan,
71         ...pick(user, ['canPay', 'isFree', 'hasPaidMail']),
72     });
74     const isVpnB2b = getHasVpnB2BPlan(subscription);
75     const isWalletEA = app === APPS.PROTONWALLET;
76     // Subscription panel is displayed for user with a free or paid plan and not in a trial
77     const shouldRenderSubscription = user.canPay || (subscription && !isTrial(subscription));
78     const shouldRenderPendingInvitation = !!invites.length;
79     // Upsell panel if the user has a subscription and is not vpn or wallet
80     const shouldRenderUpsells = !isVpnB2b && !isWalletEA && shouldRenderSubscription;
81     // Usage panel is displayed for members of B2B plans except VPN B2B
82     const shouldRenderUsagePanel =
83         (organization?.UsedMembers || 0) > 1 && !isVpnB2b && organization?.State === ORGANIZATION_STATE.ACTIVE;
85     // By default, for style consistency, we display every setting in `SettingsSectionWide`
86     // But since 3 panels don't fit in this section (or are too tightly packed),
87     // we use the extra wide one when we have > 2 panels to display
88     const panelCount = [shouldRenderSubscription, shouldRenderPendingInvitation, shouldRenderUsagePanel].filter(
89         Boolean
90     ).length;
91     const shouldRenderInLargeSection = panelCount + upsells.length > 2;
92     const SettingsSection = shouldRenderInLargeSection ? SettingsSectionExtraWide : SettingsSectionWide;
94     return (
95         <SettingsSection>
96             <div
97                 className={clsx(
98                     shouldRenderInLargeSection ? 'grid-column-3' : 'grid-column-2',
99                     'your-plan-section-container gap-8 pt-4'
100                 )}
101                 data-testid="dashboard-panels-container"
102             >
103                 {/* Subcription details */}
104                 {shouldRenderSubscription && (
105                     <SubscriptionPanel
106                         app={app}
107                         subscription={subscription}
108                         organization={organization}
109                         user={user}
110                         addresses={addresses}
111                         vpnServers={serversCount}
112                         upsells={shouldRenderUpsells ? upsells : []}
113                     />
114                 )}
116                 {/* Usage for plans with >1 Members except VPN B2B */}
117                 {shouldRenderUsagePanel && (
118                     <UsagePanel addresses={addresses} calendars={calendars} organization={organization} user={user} />
119                 )}
120                 {shouldRenderUpsells && <UpsellPanels upsells={upsells} subscription={subscription} />}
121                 {shouldRenderPendingInvitation && <PendingInvitationsPanel invites={invites} />}
122             </div>
123         </SettingsSection>
124     );
126 export default YourPlanSection;