1 import { c, msgid } from 'ttag';
3 import { PLANS } from '@proton/payments';
7 CALENDAR_SHORT_APP_NAME,
8 CONTACTS_SHORT_APP_NAME,
16 } from '@proton/shared/lib/constants';
17 import humanSize from '@proton/shared/lib/helpers/humanSize';
18 import { sizeUnits } from '@proton/shared/lib/helpers/size';
19 import type { FreePlanDefault, PlansMap } from '@proton/shared/lib/interfaces';
20 import { Audience } from '@proton/shared/lib/interfaces';
22 import type { PlanCardFeature, PlanCardFeatureDefinition } from './interface';
24 export const getFreeDriveStorageFeature = (freePlan: FreePlanDefault): PlanCardFeatureDefinition => {
25 const totalStorageSize = humanSize({ bytes: freePlan.MaxDriveRewardSpace, fraction: 0 });
27 text: c('storage_split: feature').t`Up to ${totalStorageSize} Drive storage`,
34 export const getFreeMailStorageFeature = (freePlan: FreePlanDefault): PlanCardFeatureDefinition => {
35 const totalStorageSize = humanSize({ bytes: freePlan.MaxBaseRewardSpace, fraction: 0 });
37 text: c('storage_split: feature').t`Up to ${totalStorageSize} Mail storage`,
38 tooltip: c('storage_split: feature')
39 .t`Storage for data generated by ${BRAND_NAME} ${MAIL_SHORT_APP_NAME}, ${CALENDAR_SHORT_APP_NAME}, ${CONTACTS_SHORT_APP_NAME}, and ${PASS_SHORT_APP_NAME}`,
45 export const getStorageFeature = (
48 freePlan: FreePlanDefault;
50 boldStorageSize?: boolean;
56 ): PlanCardFeatureDefinition => {
57 const { highlight = false, boldStorageSize = false } = options;
59 const freeBaseStorage = options.freePlan.MaxBaseRewardSpace;
60 const freeDriveStorage = options.freePlan.MaxDriveRewardSpace;
61 const driveStorageSize = humanSize({ bytes: freeDriveStorage, fraction: 0 });
62 const baseStorageSize = humanSize({ bytes: freeBaseStorage, fraction: 0 });
63 const totalStorageSize = humanSize({ bytes: freeDriveStorage + freeBaseStorage, fraction: 0 });
65 text: c('new_plans: feature').t`Up to ${totalStorageSize} storage`,
66 subtext: options.subtext
67 ? `${baseStorageSize} ${MAIL_SHORT_APP_NAME} + ${driveStorageSize} ${DRIVE_SHORT_APP_NAME}`
74 let humanReadableSize = humanSize({ bytes, fraction: 0, unitOptions: { max: 'TB' } });
75 // The storage for Duo is actually not 1 TB, it's slightly less, so we hardcode it to 1TB
77 humanReadableSize = humanSize({ bytes: sizeUnits.TB, fraction: 0, unitOptions: { max: 'TB' } });
80 const size = boldStorageSize ? <b key="bold-storage-size">{humanReadableSize}</b> : humanReadableSize;
81 const tooltip = options.family
82 ? c('new_plans: tooltip')
83 .t`Storage space is shared between users across ${MAIL_APP_NAME}, ${CALENDAR_APP_NAME}, ${DRIVE_APP_NAME}, and ${PASS_APP_NAME}`
84 : c('new_plans: tooltip')
85 .t`Storage space is shared across ${MAIL_APP_NAME}, ${CALENDAR_APP_NAME}, ${DRIVE_APP_NAME}, and ${PASS_APP_NAME}`;
88 text: c('new_plans: feature').jt`${size} storage`,
89 subtext: options.subtext ? c('storage_split: info').t`For all ${BRAND_NAME} services` : undefined,
97 export const getStorageBoostFeature = (bundleStorage: string): PlanCardFeatureDefinition => {
100 text: c('new_plans: Upsell attribute').t`Boost your storage space to ${bundleStorage} total`,
105 export const getStorageBoostFeatureB2B = (bundleStorage: string): PlanCardFeatureDefinition => {
108 text: c('new_plans: Upsell attribute').t`Boost your storage space to ${bundleStorage} per user`,
113 export const getStorageFeatureB2B = (
119 ): PlanCardFeatureDefinition => {
120 const size = humanSize({ bytes, fraction: 0, unitOptions: { max: 'TB' } });
123 text: c('new_plans: feature').t`${size} of secure storage per user`,
124 tooltip: c('new_plans: tooltip')
125 .t`Storage space is shared across ${MAIL_APP_NAME}, ${CALENDAR_APP_NAME}, and ${DRIVE_APP_NAME}. Administrators can allocate different storage amounts to users in their organization`,
126 subtext: options.subtext ? c('storage_split: info').t`For all ${BRAND_NAME} services` : undefined,
128 highlight: options.highlight,
133 export const getEndToEndEncryption = (): PlanCardFeatureDefinition => {
135 text: c('new_plans: feature').t`End-to-end encryption`,
140 export const getVersionHistory = (options?: 'generic' | 365 | '10y'): PlanCardFeatureDefinition => {
141 if (options === 365) {
143 text: c('new_plans: feature').ngettext(
144 msgid`${options}-day file version history`,
145 `${options}-day file version history`,
149 icon: 'clock-rotate-left',
153 if (options === '10y') {
155 text: c('new_plans: feature').t`10-year file version history`,
157 icon: 'clock-rotate-left',
162 text: c('new_plans: feature').t`Recover previous file versions`,
164 icon: 'clock-rotate-left',
168 export const getPremiumFeatures = (): PlanCardFeatureDefinition => {
170 text: c('new_plans: feature').t`All premium ${BRAND_NAME} services. One easy subscription`,
175 export const getBasicFeatures = (): PlanCardFeatureDefinition => {
177 text: c('new_plans: feature')
178 .t`All basic ${BRAND_NAME} services (${MAIL_SHORT_APP_NAME}, ${VPN_SHORT_APP_NAME}, ${PASS_SHORT_APP_NAME})`,
180 icon: 'brand-proton',
184 export const getDriveAppFeature = (options?: { family?: boolean; duo?: boolean }): PlanCardFeatureDefinition => {
185 let tooltip = c('new_plans: tooltip')
186 .t`${DRIVE_APP_NAME}: Secure your files with encrypted cloud storage. Includes automatic sync, encrypted file sharing, and more.`;
188 if (options?.duo || options?.family) {
189 tooltip = c('new_plans: tooltip')
190 .t`Secure your files with encrypted cloud storage. Includes automatic sync, encrypted file sharing, and more.`;
194 text: DRIVE_APP_NAME,
197 icon: 'brand-proton-drive',
201 const getShareFeature = (): PlanCardFeatureDefinition => {
203 text: c('new_plans: feature').t`Share files with no size limit`,
204 tooltip: c('new_plans: tooltip').t`Share your files or folders with anyone by using secure, shareable links`,
209 const getSyncAndBackupFeature = (): PlanCardFeatureDefinition => {
211 text: c('new_plans: feature').t`Sync and backup all your files across devices`,
216 export const getDocumentEditor = (): PlanCardFeatureDefinition => {
218 text: c('new_plans: feature').t`Online document editor`,
224 export const getCollaborate = (): PlanCardFeatureDefinition => {
226 text: c('new_plans: feature').t`Collaborate and share large files`,
228 icon: 'brand-proton-drive',
232 export const getStorage = (plansMap: PlansMap, freePlan: FreePlanDefault): PlanCardFeature => {
236 [PLANS.FREE]: getStorageFeature(-1, { subtext: true, freePlan }),
237 [PLANS.BUNDLE]: getStorageFeature(plansMap[PLANS.BUNDLE]?.MaxSpace ?? 536870912000, {
241 [PLANS.MAIL]: getStorageFeature(plansMap[PLANS.MAIL]?.MaxSpace ?? 16106127360, { subtext: true, freePlan }),
242 [PLANS.VPN]: getStorageFeature(-1, { subtext: true, freePlan }),
243 [PLANS.DRIVE]: getStorageFeature(plansMap[PLANS.DRIVE]?.MaxSpace ?? 214748364800, {
247 [PLANS.DRIVE_BUSINESS]: getStorageFeatureB2B(plansMap[PLANS.DRIVE_BUSINESS]?.MaxSpace ?? 1099511627776, {
250 [PLANS.PASS]: getStorageFeature(-1, { subtext: true, freePlan }),
251 [PLANS.PASS_FAMILY]: null,
252 [PLANS.WALLET]: getStorageFeature(-1, { subtext: true, freePlan }),
253 [PLANS.FAMILY]: getStorageFeature(plansMap[PLANS.FAMILY]?.MaxSpace ?? 2748779069440, {
258 [PLANS.DUO]: getStorageFeature(plansMap[PLANS.DUO]?.MaxSpace ?? 1099511627776, {
263 [PLANS.MAIL_PRO]: getStorageFeatureB2B(plansMap[PLANS.MAIL_PRO]?.MaxSpace ?? 16106127360, {
266 [PLANS.MAIL_BUSINESS]: getStorageFeatureB2B(plansMap[PLANS.MAIL_BUSINESS]?.MaxSpace ?? 53687091200, {
269 [PLANS.BUNDLE_PRO]: getStorageFeatureB2B(plansMap[PLANS.BUNDLE_PRO]?.MaxSpace ?? 536870912000, {
272 [PLANS.BUNDLE_PRO_2024]: getStorageFeatureB2B(plansMap[PLANS.BUNDLE_PRO_2024]?.MaxSpace ?? 1099511627776, {
275 [PLANS.PASS_PRO]: getStorageFeature(-1, { subtext: true, freePlan }),
276 [PLANS.PASS_BUSINESS]: getStorageFeature(-1, { subtext: true, freePlan }),
277 [PLANS.VPN_PRO]: null,
278 [PLANS.VPN_BUSINESS]: null,
283 export const getDriveFeatures = (plansMap: PlansMap, freePlan: FreePlanDefault): PlanCardFeature[] => {
285 getStorage(plansMap, freePlan),
287 name: 'version-history',
290 [PLANS.BUNDLE]: getVersionHistory('10y'),
291 [PLANS.MAIL]: getVersionHistory(),
292 [PLANS.VPN]: getVersionHistory(),
293 [PLANS.DRIVE]: getVersionHistory('10y'),
294 [PLANS.DRIVE_BUSINESS]: getVersionHistory(365),
295 [PLANS.PASS]: getVersionHistory(),
296 [PLANS.PASS_FAMILY]: getVersionHistory(),
297 [PLANS.WALLET]: getVersionHistory(),
298 [PLANS.FAMILY]: getVersionHistory('10y'),
299 [PLANS.DUO]: getVersionHistory('10y'),
300 [PLANS.MAIL_PRO]: getVersionHistory(),
301 [PLANS.MAIL_BUSINESS]: getVersionHistory(),
302 [PLANS.BUNDLE_PRO]: getVersionHistory('10y'),
303 [PLANS.BUNDLE_PRO_2024]: getVersionHistory('10y'),
304 [PLANS.PASS_PRO]: getVersionHistory(),
305 [PLANS.PASS_BUSINESS]: getVersionHistory(),
306 [PLANS.VPN_PRO]: getVersionHistory(),
307 [PLANS.VPN_BUSINESS]: getVersionHistory(),
313 [PLANS.FREE]: getEndToEndEncryption(),
314 [PLANS.BUNDLE]: getEndToEndEncryption(),
315 [PLANS.MAIL]: getEndToEndEncryption(),
316 [PLANS.VPN]: getEndToEndEncryption(),
317 [PLANS.DRIVE]: getEndToEndEncryption(),
318 [PLANS.DRIVE_BUSINESS]: getEndToEndEncryption(),
319 [PLANS.WALLET]: getEndToEndEncryption(),
320 [PLANS.PASS]: getEndToEndEncryption(),
321 [PLANS.PASS_FAMILY]: getEndToEndEncryption(),
322 [PLANS.FAMILY]: getEndToEndEncryption(),
323 [PLANS.DUO]: getEndToEndEncryption(),
324 [PLANS.MAIL_PRO]: getEndToEndEncryption(),
325 [PLANS.MAIL_BUSINESS]: getEndToEndEncryption(),
326 [PLANS.BUNDLE_PRO]: getEndToEndEncryption(),
327 [PLANS.BUNDLE_PRO_2024]: getEndToEndEncryption(),
328 [PLANS.PASS_PRO]: getEndToEndEncryption(),
329 [PLANS.PASS_BUSINESS]: getEndToEndEncryption(),
330 [PLANS.VPN_PRO]: null,
331 [PLANS.VPN_BUSINESS]: null,
335 name: 'document-editor',
336 target: Audience.B2B,
338 [PLANS.FREE]: getDocumentEditor(),
339 [PLANS.BUNDLE]: getDocumentEditor(),
340 [PLANS.MAIL]: getDocumentEditor(),
341 [PLANS.VPN]: getDocumentEditor(),
342 [PLANS.DRIVE]: getDocumentEditor(),
343 [PLANS.DRIVE_BUSINESS]: getDocumentEditor(),
344 [PLANS.PASS]: getDocumentEditor(),
345 [PLANS.PASS_FAMILY]: getDocumentEditor(),
346 [PLANS.WALLET]: getDocumentEditor(),
347 [PLANS.FAMILY]: getDocumentEditor(),
348 [PLANS.DUO]: getDocumentEditor(),
349 [PLANS.MAIL_PRO]: getDocumentEditor(),
350 [PLANS.MAIL_BUSINESS]: getDocumentEditor(),
351 [PLANS.BUNDLE_PRO]: getDocumentEditor(),
352 [PLANS.BUNDLE_PRO_2024]: getDocumentEditor(),
353 [PLANS.PASS_PRO]: getDocumentEditor(),
354 [PLANS.PASS_BUSINESS]: getDocumentEditor(),
355 [PLANS.VPN_PRO]: null,
356 [PLANS.VPN_BUSINESS]: null,
362 [PLANS.FREE]: getShareFeature(),
363 [PLANS.BUNDLE]: getShareFeature(),
364 [PLANS.MAIL]: getShareFeature(),
365 [PLANS.VPN]: getShareFeature(),
366 [PLANS.DRIVE]: getShareFeature(),
367 [PLANS.DRIVE_BUSINESS]: getShareFeature(),
368 [PLANS.PASS]: getShareFeature(),
369 [PLANS.PASS_FAMILY]: getShareFeature(),
370 [PLANS.WALLET]: getShareFeature(),
371 [PLANS.FAMILY]: getShareFeature(),
372 [PLANS.DUO]: getShareFeature(),
373 [PLANS.MAIL_PRO]: getShareFeature(),
374 [PLANS.MAIL_BUSINESS]: getShareFeature(),
375 [PLANS.BUNDLE_PRO]: getShareFeature(),
376 [PLANS.BUNDLE_PRO_2024]: getShareFeature(),
377 [PLANS.PASS_PRO]: getShareFeature(),
378 [PLANS.PASS_BUSINESS]: getShareFeature(),
379 [PLANS.VPN_PRO]: null,
380 [PLANS.VPN_BUSINESS]: null,
384 name: 'sync-and-backup',
386 [PLANS.FREE]: getSyncAndBackupFeature(),
387 [PLANS.BUNDLE]: getSyncAndBackupFeature(),
388 [PLANS.MAIL]: getSyncAndBackupFeature(),
389 [PLANS.VPN]: getSyncAndBackupFeature(),
390 [PLANS.DRIVE]: getSyncAndBackupFeature(),
391 [PLANS.DRIVE_BUSINESS]: getSyncAndBackupFeature(),
392 [PLANS.PASS]: getSyncAndBackupFeature(),
393 [PLANS.PASS_FAMILY]: getSyncAndBackupFeature(),
394 [PLANS.WALLET]: getSyncAndBackupFeature(),
395 [PLANS.FAMILY]: getSyncAndBackupFeature(),
396 [PLANS.DUO]: getSyncAndBackupFeature(),
397 [PLANS.MAIL_PRO]: getSyncAndBackupFeature(),
398 [PLANS.MAIL_BUSINESS]: getSyncAndBackupFeature(),
399 [PLANS.BUNDLE_PRO]: getSyncAndBackupFeature(),
400 [PLANS.BUNDLE_PRO_2024]: getSyncAndBackupFeature(),
401 [PLANS.PASS_PRO]: getSyncAndBackupFeature(),
402 [PLANS.PASS_BUSINESS]: getSyncAndBackupFeature(),
403 [PLANS.VPN_PRO]: null,
404 [PLANS.VPN_BUSINESS]: null,