Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / shared / lib / helpers / newsletter.ts
bloba5430a2f8a1092205dd35f0eb6adc3ef98c8504a
1 import isNumber from 'lodash/isNumber';
3 import { clearBit, hasBit, setBit } from './bitset';
5 export enum NEWSLETTER_SUBSCRIPTIONS {
6     ANNOUNCEMENTS = 'Announcements',
7     /** not displayed anymore, turning on one product news should turn it on as well */
8     FEATURES = 'Features',
9     NEWSLETTER = 'Newsletter',
10     BETA = 'Beta',
11     BUSINESS = 'Business',
12     OFFERS = 'Offers',
13     /** used in `Messages & Composing` */
14     NEW_EMAIL_NOTIF = 'NewEmailNotif',
15     ONBOARDING = 'Onboarding',
16     USER_SURVEY = 'UserSurveys',
17     INBOX_NEWS = 'InboxNews',
18     VPN_NEWS = 'VpnNews',
19     DRIVE_NEWS = 'DriveNews',
20     PASS_NEWS = 'PassNews',
21     WALLET_NEWS = 'WalletNews',
22     IN_APP_NOTIFICATIONS = 'InAppNotifications',
25 export enum NEWSLETTER_SUBSCRIPTIONS_BITS {
26     ANNOUNCEMENTS = 1 << 0,
27     FEATURES = 1 << 1,
28     NEWSLETTER = 1 << 2,
29     BETA = 1 << 3,
30     BUSINESS = 1 << 4,
31     OFFERS = 1 << 5,
32     /** used in `Messages & Composing` */
33     NEW_EMAIL_NOTIF = 1 << 6,
34     ONBOARDING = 1 << 7,
35     USER_SURVEY = 1 << 8,
36     INBOX_NEWS = 1 << 9,
37     VPN_NEWS = 1 << 10,
38     DRIVE_NEWS = 1 << 11,
39     PASS_NEWS = 1 << 12,
40     WALLET_NEWS = 1 << 13,
41     IN_APP_NOTIFICATIONS = 1 << 14,
44 export const NEWSLETTER_SUBSCRIPTIONS_BY_BITS: Record<NEWSLETTER_SUBSCRIPTIONS_BITS, NEWSLETTER_SUBSCRIPTIONS> = {
45     [NEWSLETTER_SUBSCRIPTIONS_BITS.ANNOUNCEMENTS]: NEWSLETTER_SUBSCRIPTIONS.ANNOUNCEMENTS,
46     [NEWSLETTER_SUBSCRIPTIONS_BITS.FEATURES]: NEWSLETTER_SUBSCRIPTIONS.FEATURES,
47     [NEWSLETTER_SUBSCRIPTIONS_BITS.NEWSLETTER]: NEWSLETTER_SUBSCRIPTIONS.NEWSLETTER,
48     [NEWSLETTER_SUBSCRIPTIONS_BITS.BETA]: NEWSLETTER_SUBSCRIPTIONS.BETA,
49     [NEWSLETTER_SUBSCRIPTIONS_BITS.BUSINESS]: NEWSLETTER_SUBSCRIPTIONS.BUSINESS,
50     [NEWSLETTER_SUBSCRIPTIONS_BITS.OFFERS]: NEWSLETTER_SUBSCRIPTIONS.OFFERS,
51     [NEWSLETTER_SUBSCRIPTIONS_BITS.NEW_EMAIL_NOTIF]: NEWSLETTER_SUBSCRIPTIONS.NEW_EMAIL_NOTIF,
52     [NEWSLETTER_SUBSCRIPTIONS_BITS.ONBOARDING]: NEWSLETTER_SUBSCRIPTIONS.ONBOARDING,
53     [NEWSLETTER_SUBSCRIPTIONS_BITS.USER_SURVEY]: NEWSLETTER_SUBSCRIPTIONS.USER_SURVEY,
54     [NEWSLETTER_SUBSCRIPTIONS_BITS.INBOX_NEWS]: NEWSLETTER_SUBSCRIPTIONS.INBOX_NEWS,
55     [NEWSLETTER_SUBSCRIPTIONS_BITS.VPN_NEWS]: NEWSLETTER_SUBSCRIPTIONS.VPN_NEWS,
56     [NEWSLETTER_SUBSCRIPTIONS_BITS.DRIVE_NEWS]: NEWSLETTER_SUBSCRIPTIONS.DRIVE_NEWS,
57     [NEWSLETTER_SUBSCRIPTIONS_BITS.PASS_NEWS]: NEWSLETTER_SUBSCRIPTIONS.PASS_NEWS,
58     [NEWSLETTER_SUBSCRIPTIONS_BITS.WALLET_NEWS]: NEWSLETTER_SUBSCRIPTIONS.WALLET_NEWS,
59     [NEWSLETTER_SUBSCRIPTIONS_BITS.IN_APP_NOTIFICATIONS]: NEWSLETTER_SUBSCRIPTIONS.IN_APP_NOTIFICATIONS,
62 export const NEWSLETTER_SUBSCRIPTIONS_BY_KEY: Record<NEWSLETTER_SUBSCRIPTIONS, NEWSLETTER_SUBSCRIPTIONS_BITS> = {
63     [NEWSLETTER_SUBSCRIPTIONS.ANNOUNCEMENTS]: NEWSLETTER_SUBSCRIPTIONS_BITS.ANNOUNCEMENTS,
64     [NEWSLETTER_SUBSCRIPTIONS.FEATURES]: NEWSLETTER_SUBSCRIPTIONS_BITS.FEATURES,
65     [NEWSLETTER_SUBSCRIPTIONS.NEWSLETTER]: NEWSLETTER_SUBSCRIPTIONS_BITS.NEWSLETTER,
66     [NEWSLETTER_SUBSCRIPTIONS.BETA]: NEWSLETTER_SUBSCRIPTIONS_BITS.BETA,
67     [NEWSLETTER_SUBSCRIPTIONS.BUSINESS]: NEWSLETTER_SUBSCRIPTIONS_BITS.BUSINESS,
68     [NEWSLETTER_SUBSCRIPTIONS.OFFERS]: NEWSLETTER_SUBSCRIPTIONS_BITS.OFFERS,
69     [NEWSLETTER_SUBSCRIPTIONS.NEW_EMAIL_NOTIF]: NEWSLETTER_SUBSCRIPTIONS_BITS.NEW_EMAIL_NOTIF,
70     [NEWSLETTER_SUBSCRIPTIONS.ONBOARDING]: NEWSLETTER_SUBSCRIPTIONS_BITS.ONBOARDING,
71     [NEWSLETTER_SUBSCRIPTIONS.USER_SURVEY]: NEWSLETTER_SUBSCRIPTIONS_BITS.USER_SURVEY,
72     [NEWSLETTER_SUBSCRIPTIONS.INBOX_NEWS]: NEWSLETTER_SUBSCRIPTIONS_BITS.INBOX_NEWS,
73     [NEWSLETTER_SUBSCRIPTIONS.VPN_NEWS]: NEWSLETTER_SUBSCRIPTIONS_BITS.VPN_NEWS,
74     [NEWSLETTER_SUBSCRIPTIONS.DRIVE_NEWS]: NEWSLETTER_SUBSCRIPTIONS_BITS.DRIVE_NEWS,
75     [NEWSLETTER_SUBSCRIPTIONS.PASS_NEWS]: NEWSLETTER_SUBSCRIPTIONS_BITS.PASS_NEWS,
76     [NEWSLETTER_SUBSCRIPTIONS.WALLET_NEWS]: NEWSLETTER_SUBSCRIPTIONS_BITS.WALLET_NEWS,
77     [NEWSLETTER_SUBSCRIPTIONS.IN_APP_NOTIFICATIONS]: NEWSLETTER_SUBSCRIPTIONS_BITS.IN_APP_NOTIFICATIONS,
80 export type NewsletterSubscriptionUpdateData = Partial<Record<NEWSLETTER_SUBSCRIPTIONS, boolean>>;
82 /**
83  * if we have new value, we return it, else we return old value, if it is undefined we return null
84  */
85 const isProductNewsEnabled = (
86     flag: NEWSLETTER_SUBSCRIPTIONS_BITS,
87     currentNews: NewsletterSubscriptionUpdateData | number,
88     updatedNews?: NewsletterSubscriptionUpdateData | number
89 ) => {
90     const strFlag = NEWSLETTER_SUBSCRIPTIONS_BY_BITS[flag];
91     const currentValue = isNumber(currentNews) ? hasBit(currentNews, flag) : currentNews[strFlag];
92     const updatedValue = isNumber(updatedNews) ? hasBit(updatedNews, flag) : updatedNews?.[strFlag];
93     return updatedValue ?? currentValue ?? null;
96 /**
97  * If one of the product newsletter (Inbox/Drive/Pass/VPN) is enabled, then returns true
98  */
99 export const isGlobalFeatureNewsEnabled = (
100     currentNews: NewsletterSubscriptionUpdateData | number,
101     updatedNews?: NewsletterSubscriptionUpdateData | number
102 ) => {
103     return Boolean(
104         isProductNewsEnabled(NEWSLETTER_SUBSCRIPTIONS_BITS.INBOX_NEWS, currentNews, updatedNews) ||
105             isProductNewsEnabled(NEWSLETTER_SUBSCRIPTIONS_BITS.DRIVE_NEWS, currentNews, updatedNews) ||
106             isProductNewsEnabled(NEWSLETTER_SUBSCRIPTIONS_BITS.PASS_NEWS, currentNews, updatedNews) ||
107             isProductNewsEnabled(NEWSLETTER_SUBSCRIPTIONS_BITS.VPN_NEWS, currentNews, updatedNews)
108     );
111 export const getUpdatedNewsBitmap = (news: number, data: NewsletterSubscriptionUpdateData) => {
112     return Object.entries(data).reduce((acc, [key, value]) => {
113         const flag = NEWSLETTER_SUBSCRIPTIONS_BY_KEY[key as NEWSLETTER_SUBSCRIPTIONS];
114         if (value) {
115             return setBit(acc, flag);
116         } else {
117             return clearBit(acc, flag);
118         }
119     }, news ?? 0);
122 export const getSubscriptionPatchUpdate = ({
123     currentNews,
124     diff,
125 }: {
126     currentNews: number;
127     diff: NewsletterSubscriptionUpdateData;
128 }) => {
129     const update = {
130         ...diff,
131     };
133     // Until clients support sending the new flags, we propagate the unsubscription from the old one to the specific
134     // flags of the currently used products
135     // TODO: Should this be removed?
136     const newFeaturesValue = isGlobalFeatureNewsEnabled(currentNews, update);
137     if (newFeaturesValue !== hasBit(currentNews, NEWSLETTER_SUBSCRIPTIONS_BITS.FEATURES)) {
138         update[NEWSLETTER_SUBSCRIPTIONS.FEATURES] = newFeaturesValue;
139     }
141     return update;