1 import { format, fromUnixTime } from 'date-fns';
2 import { c } from 'ttag';
4 import { useSubscription } from '@proton/account/subscription/hooks';
5 import { useUser } from '@proton/account/user/hooks';
6 import { InlineLinkButton } from '@proton/atoms';
7 import SettingsLink from '@proton/components/components/link/SettingsLink';
8 import SubscriptionModalProvider, {
10 } from '@proton/components/containers/payments/subscription/SubscriptionModalProvider';
11 import { SUBSCRIPTION_STEPS } from '@proton/components/containers/payments/subscription/constants';
12 import useConfig from '@proton/components/hooks/useConfig';
13 import { PLANS, PLAN_NAMES } from '@proton/payments';
14 import type { APP_NAMES } from '@proton/shared/lib/constants';
19 OPEN_OFFER_MODAL_EVENT,
22 } from '@proton/shared/lib/constants';
29 } from '@proton/shared/lib/helpers/subscription';
30 import { addUpsellPath, getUpgradePath, getUpsellRefFromApp } from '@proton/shared/lib/helpers/upsell';
31 import { dateLocale } from '@proton/shared/lib/i18n';
33 import TopBanner from './TopBanner';
35 const ModalAction = ({ textAction, upsellRef }: { textAction: string; upsellRef: string | undefined }) => {
36 const [subscription] = useSubscription();
37 const [openSubscriptionModal] = useSubscriptionModal();
41 className="color-inherit"
43 openSubscriptionModal({
44 step: SUBSCRIPTION_STEPS.CHECKOUT,
46 planIDs: getPlanIDs(subscription),
59 const WrappedModalAction = ({
65 upsellRef: string | undefined;
68 <SubscriptionModalProvider app={fromApp}>
69 <ModalAction {...rest} />
70 </SubscriptionModalProvider>
74 const TrialEndsActionButton = ({
83 const { APP_NAME } = useConfig();
84 const [user] = useUser();
85 const [subscription, subscriptionLoading] = useSubscription();
86 if (subscriptionLoading) {
90 const upsellRef = getUpsellRefFromApp({
91 app: refApp ?? APP_NAME,
93 component: UPSELL_COMPONENT.BANNER,
94 feature: SHARED_UPSELL_PATHS.TRIAL_WILL_END,
97 // If that's already Account or VPN settings app then we render the buton that will open the subscription modal
99 if (APP_NAME === APPS.PROTONACCOUNT || APP_NAME === APPS.PROTONVPN_SETTINGS) {
100 return <WrappedModalAction upsellRef={upsellRef} fromApp={fromApp} textAction={textAction} />;
103 // For all other apps we render the button that will redirect to the account app
104 const upgradePath = addUpsellPath(getUpgradePath({ user, subscription, app: APP_NAME }), upsellRef);
106 <SettingsLink path={upgradePath} className="color-inherit">
113 * Mail and account apps have an upsell modal. It's triggered by the `OPEN_OFFER_MODAL_EVENT` event.
114 * The handler component must be rendered in DOM to handle the events.
116 const UpgradeBannerLink = ({ textAction }: { textAction: string }) => {
117 const handleClick = () => document.dispatchEvent(new CustomEvent(OPEN_OFFER_MODAL_EVENT));
120 <InlineLinkButton key="continue" className="color-inherit" onClick={handleClick}>
126 const TrialEndsActionButtonSwitcher = ({ fromApp }: { fromApp: APP_NAMES }) => {
127 const [subscription] = useSubscription();
129 if (isTrial(subscription, PLANS.MAIL)) {
130 const textAction = c('Button').t`Continue using ${MAIL_APP_NAME}.`;
131 return <UpgradeBannerLink textAction={textAction} />;
134 if (isTrial(subscription, PLANS.BUNDLE)) {
135 const planTitle = PLAN_NAMES[PLANS.BUNDLE];
136 const textAction = c('Button').t`Continue using ${planTitle}`;
137 return <TrialEndsActionButton fromApp={fromApp} textAction={textAction} />;
140 // a catch-all for all other cases
141 if (subscription && isTrial(subscription)) {
142 const planTitle = getPlanTitle(subscription);
143 let textAction = c('Button').t`Continue using ${planTitle}`;
145 textAction = c('Button').t`Continue your subscription`;
148 return <TrialEndsActionButton fromApp={fromApp} textAction={textAction} />;
154 const ReferralTopBanner = ({ fromApp }: { fromApp: APP_NAMES }) => {
155 const [subscription, loadingSubscription] = useSubscription();
156 const { APP_NAME } = useConfig();
157 const isVpn = APP_NAME === APPS.PROTONVPN_SETTINGS;
158 const trial = isTrial(subscription);
159 if (loadingSubscription || !trial || isVpn) {
163 const action = <TrialEndsActionButtonSwitcher key="trial-action-button" fromApp={fromApp} />;
164 const { PeriodEnd = 0 } = subscription || {};
165 const textDate = format(fromUnixTime(PeriodEnd), 'PPP', { locale: dateLocale });
167 // 1 week before the trial ends
168 const willExpire = willTrialExpire(subscription);
170 const message = c('Warning').jt`Your free trial ends on ${textDate}. ${action}`;
171 return <TopBanner className="bg-warning">{message}</TopBanner>;
175 const isExpired = isTrialExpired(subscription);
177 const message = c('Message')
178 .jt`Your free trial has ended. Access to your account will soon be disabled. ${action}`;
179 return <TopBanner className="bg-danger">{message}</TopBanner>;
186 export default ReferralTopBanner;