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 */
9 NEWSLETTER = 'Newsletter',
11 BUSINESS = 'Business',
13 /** used in `Messages & Composing` */
14 NEW_EMAIL_NOTIF = 'NewEmailNotif',
15 ONBOARDING = 'Onboarding',
16 USER_SURVEY = 'UserSurveys',
17 INBOX_NEWS = 'InboxNews',
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,
32 /** used in `Messages & Composing` */
33 NEW_EMAIL_NOTIF = 1 << 6,
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>>;
83 * if we have new value, we return it, else we return old value, if it is undefined we return null
85 const isProductNewsEnabled = (
86 flag: NEWSLETTER_SUBSCRIPTIONS_BITS,
87 currentNews: NewsletterSubscriptionUpdateData | number,
88 updatedNews?: NewsletterSubscriptionUpdateData | number
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;
97 * If one of the product newsletter (Inbox/Drive/Pass/VPN) is enabled, then returns true
99 export const isGlobalFeatureNewsEnabled = (
100 currentNews: NewsletterSubscriptionUpdateData | number,
101 updatedNews?: NewsletterSubscriptionUpdateData | number
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)
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];
115 return setBit(acc, flag);
117 return clearBit(acc, flag);
122 export const getSubscriptionPatchUpdate = ({
127 diff: NewsletterSubscriptionUpdateData;
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;