1 import type { JSXElementConstructor, ReactNode } from 'react';
3 import type { ButtonLikeShape, ButtonLikeSize } from '@proton/atoms';
4 import type { IconName, IconSize } from '@proton/components';
5 import type { FeatureCode } from '@proton/features';
6 import type { PlanIDs } from '@proton/payments';
7 import { type Currency } from '@proton/payments';
8 import type { COUPON_CODES, CYCLE } from '@proton/shared/lib/constants';
9 import type { Optional } from '@proton/shared/lib/interfaces';
12 // This offer runs all the time and is used to remind users to upgrade once their account is old enough
13 | 'subscription-reminder'
14 | 'duo-plan-2024-yearly'
15 | 'duo-plan-2024-two-years'
19 | 'pass-family-plan-2024-yearly'
20 | 'black-friday-2024-inbox-free'
21 | 'black-friday-2024-pass-free'
22 | 'black-friday-2024-drive-free'
23 | 'black-friday-2024-vpn-free'
24 | 'black-friday-2024-inbox-free-yearly'
25 | 'black-friday-2024-drive-free-yearly'
26 | 'black-friday-2024-vpn-free-yearly'
27 | 'black-friday-2024-pass-plus'
28 | 'black-friday-2024-plus'
29 | 'black-friday-2024-vpn-monthly'
30 | 'black-friday-2024-unlimited'
31 | 'black-friday-2024-duo';
33 export type OfferGlobalFeatureCodeValue = Record<OfferId, boolean>;
35 export enum OfferUserFeatureCodeValue {
41 export interface OfferProps {
44 onChangeCurrency: (currency: Currency) => void;
45 onSelectDeal: (offer: Offer, deal: Deal, current: Currency) => void;
46 onCloseModal: () => void;
49 export type OfferLayoutProps = Optional<OfferProps, 'offer'>;
51 export interface Operation {
56 isUsingMoreThan80PercentStorage?: boolean;
59 export interface OfferImages {
63 bannerImage2x?: string;
66 export interface OfferConfig {
68 featureCode: FeatureCode;
69 autoPopUp?: 'each-time' | 'one-time';
70 canBeDisabled?: boolean;
72 layout: JSXElementConstructor<OfferLayoutProps>;
73 /** Displays countdown if present */
76 shape?: ButtonLikeShape;
78 iconGradient?: boolean;
81 getCTAContent?: () => string;
85 darkBackground?: boolean; // Will use a light close button if true (ghost button with white text)
86 enableCycleSelector?: boolean; // Allow the selection of cycles if true in the checkout process
87 /** only make sense for 1 plan offer and IF the plan title is above the plan card */
88 hideDealTitle?: boolean;
89 /** if you want to hide all "save xx%"" in the bubble on top of all plans */
90 hideDiscountBubble?: boolean;
91 hideDealPriceInfos?: boolean;
94 export interface Feature {
102 export interface Deal {
103 couponCode?: COUPON_CODES;
106 isLifeTime?: boolean;
107 features?: () => Feature[];
108 getCTAContent?: () => string;
109 buttonSize?: ButtonLikeSize;
110 planIDs: PlanIDs; // planIDs used to subscribe
111 dealName: string; // most of the time we show the plan name of the deal
112 popular?: number; // 1 = most popular, 2 = second most popular, etc.
113 mobileOrder?: number; // 1 = most popular, 2 = second most popular, etc. if using this, please specify it for all plans to avoid issues
114 header?: () => string | ReactNode;
116 isGuaranteed?: boolean;
117 dealSuffixPrice?: () => string;
118 suffixOnNewLine?: boolean;
119 /** to replace "Save xxx%", better use a short text */
123 export interface Prices {
125 withoutCoupon: number;
126 withoutCouponMonthly: number;
129 export type DealWithPrices = Deal & { prices: Prices };
131 export interface Offer extends OfferConfig {
132 deals: DealWithPrices[];
135 export interface DealProps extends Required<OfferProps> {
136 deal: Offer['deals'][number];