Skip to content

Commit 5e35f3b

Browse files
Merge pull request #20404 from mozilla/FXA-12815
feat(settings): swap Monitor promo for VPN
2 parents ec1df80 + 85c4be4 commit 5e35f3b

17 files changed

Lines changed: 182 additions & 106 deletions

File tree

packages/fxa-settings/src/components/App/index.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ jest.mock('../../lib/glean', () => ({
120120
initialize: jest.fn(),
121121
getEnabled: jest.fn(),
122122
useGlean: jest.fn().mockReturnValue({ enabled: true }),
123-
accountPref: { view: jest.fn(), promoMonitorView: jest.fn() },
123+
accountPref: { view: jest.fn(), promoVpnView: jest.fn() },
124124
emailFirst: { view: jest.fn(), engage: jest.fn() },
125125
error: { view: jest.fn() },
126126
pageLoad: jest.fn(),

packages/fxa-settings/src/components/Settings/PageSettings/index.test.tsx

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jest.mock('../../../lib/glean', () => ({
3838
default: {
3939
accountPref: {
4040
view: jest.fn(),
41-
promoMonitorView: jest.fn(),
41+
promoVpnView: jest.fn(),
4242
},
4343
deleteAccount: {
4444
settingsSubmit: jest.fn(),
@@ -53,7 +53,6 @@ jest.mock('../../../lib/glean', () => ({
5353

5454
const mockGetProductPromoData = jest.fn().mockReturnValue({
5555
hidePromo: false,
56-
gleanEvent: { event: { reason: 'default' } },
5756
});
5857
jest.mock('../ProductPromo', () => ({
5958
__esModule: true,
@@ -155,10 +154,9 @@ describe('PageSettings', () => {
155154
});
156155

157156
describe('product promo event', () => {
158-
it('user does not have Monitor, promo is shown and glean metric is called', async () => {
157+
it('user does not have VPN, promo is shown and glean metric is called', async () => {
159158
mockGetProductPromoData.mockReturnValue({
160159
hidePromo: false,
161-
gleanEvent: { event: { reason: 'default' } },
162160
});
163161
renderWithRouter(
164162
<AppContext.Provider
@@ -168,16 +166,11 @@ describe('PageSettings', () => {
168166
</AppContext.Provider>
169167
);
170168
await waitFor(() =>
171-
expect(
172-
GleanMetrics.accountPref.promoMonitorView
173-
).toHaveBeenCalledTimes(1)
169+
expect(GleanMetrics.accountPref.promoVpnView).toHaveBeenCalledTimes(1)
174170
);
175-
expect(GleanMetrics.accountPref.promoMonitorView).toHaveBeenCalledWith({
176-
event: { reason: 'default' },
177-
});
178171
});
179172

180-
it('user has Monitor, promo is not shown and glean metric is not called', async () => {
173+
it('user has VPN, promo is not shown and glean metric is not called', async () => {
181174
mockGetProductPromoData.mockReturnValue({
182175
hidePromo: true,
183176
});
@@ -189,9 +182,7 @@ describe('PageSettings', () => {
189182
</AppContext.Provider>
190183
);
191184
await waitFor(() =>
192-
expect(
193-
GleanMetrics.accountPref.promoMonitorView
194-
).not.toHaveBeenCalled()
185+
expect(GleanMetrics.accountPref.promoVpnView).not.toHaveBeenCalled()
195186
);
196187
});
197188
});

packages/fxa-settings/src/components/Settings/PageSettings/index.tsx

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import DataCollection from '../DataCollection';
1717
import GleanMetrics from '../../../lib/glean';
1818
import ProductPromo, {
1919
getProductPromoData,
20-
MonitorPromoData,
20+
VpnPromoData,
2121
} from '../ProductPromo';
2222
import SideBar from '../Sidebar';
2323
import Head from 'fxa-react/components/Head';
@@ -59,9 +59,7 @@ export const PageSettings = ({
5959
GleanMetrics.accountPref.view();
6060
}, []);
6161

62-
const [monitorPromo, setMonitorPromo] = useState<MonitorPromoData | null>(
63-
null
64-
);
62+
const [vpnPromo, setVpnPromo] = useState<VpnPromoData | null>(null);
6563
const [productPromoGleanEventSent, setProductPromoGleanEventSent] =
6664
useState(false);
6765

@@ -98,32 +96,27 @@ export const PageSettings = ({
9896

9997
useEffect(() => {
10098
(async () => {
101-
if (monitorPromo !== null) {
99+
if (vpnPromo !== null) {
102100
return;
103101
}
104102

105103
const promoData = getProductPromoData(account.attachedClients);
106104

107-
setMonitorPromo(promoData);
105+
setVpnPromo(promoData);
108106
})();
109-
}, [account, monitorPromo]);
107+
}, [account, vpnPromo]);
110108

111109
// -- Relying party promotion checks --
112110
useEffect(() => {
113-
if (!monitorPromo) return;
111+
if (!vpnPromo) return;
114112
// We want this view event to fire whenever the account settings page view
115113
// event fires, if the user is shown the promo.
116-
if (!monitorPromo.hidePromo && !productPromoGleanEventSent) {
117-
GleanMetrics.accountPref.promoMonitorView(monitorPromo.gleanEvent);
114+
if (!vpnPromo.hidePromo && !productPromoGleanEventSent) {
115+
GleanMetrics.accountPref.promoVpnView();
118116
// Keep track of this because `attachedClients` can change on disconnect
119117
setProductPromoGleanEventSent(true);
120118
}
121-
}, [
122-
attachedClients,
123-
monitorPromo,
124-
subscriptions,
125-
productPromoGleanEventSent,
126-
]);
119+
}, [attachedClients, vpnPromo, subscriptions, productPromoGleanEventSent]);
127120

128121
useEffect(() => {
129122
const targetEmail = (() => {
@@ -187,7 +180,7 @@ export const PageSettings = ({
187180
connectedServicesRef,
188181
linkedAccountsRef,
189182
dataCollectionRef,
190-
monitorPromo,
183+
vpnPromo,
191184
}}
192185
/>
193186
</div>
@@ -211,8 +204,8 @@ export const PageSettings = ({
211204
</Link>
212205
</Localized>
213206
</div>
214-
{monitorPromo && !monitorPromo.hidePromo && (
215-
<ProductPromo type="settings" {...{ monitorPromo }} />
207+
{vpnPromo && !vpnPromo.hidePromo && (
208+
<ProductPromo type="settings" {...{ vpnPromo }} />
216209
)}
217210
</div>
218211
</div>

packages/fxa-settings/src/components/Settings/ProductPromo/en.ftl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,11 @@ product-promo-monitor =
55
product-promo-monitor-description-v2 = Find where your private info is exposed and take control
66
# Links out to the Monitor site
77
product-promo-monitor-cta = Get free scan
8+
9+
product-promo-vpn =
10+
.alt = { -product-mozilla-vpn }
11+
product-promo-vpn-description = Discover an added layer of anonymous browsing and protection.
12+
# Links out to the VPN site
13+
product-promo-vpn-cta = Get { -product-mozilla-vpn-short }
14+
15+
##

packages/fxa-settings/src/components/Settings/ProductPromo/index.stories.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ function storyWithProps(props: ProductPromoProps, storyName?: string) {
2828
export const MobilePromo = storyWithProps(
2929
{
3030
type: 'settings',
31-
monitorPromo: { hidePromo: false },
31+
vpnPromo: { hidePromo: false },
3232
},
33-
'Monitor promo - Banner - mobile only'
33+
'VPN promo - Banner - mobile only'
3434
);
3535
export const DesktopPromo = storyWithProps(
3636
{
3737
type: 'sidebar',
38-
monitorPromo: { hidePromo: false },
38+
vpnPromo: { hidePromo: false },
3939
},
40-
'Monitor promo - Sidebar - desktop'
40+
'VPN promo - Sidebar - desktop'
4141
);

packages/fxa-settings/src/components/Settings/ProductPromo/index.test.tsx

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ jest.mock('../../../lib/glean', () => ({
1515
__esModule: true,
1616
default: {
1717
accountPref: {
18-
promoMonitorView: jest.fn(),
19-
promoMonitorSubmit: jest.fn(),
18+
promoVpnView: jest.fn(),
19+
promoVpnSubmit: jest.fn(),
2020
},
2121
},
2222
}));
@@ -28,32 +28,30 @@ describe('ProductPromo', () => {
2828

2929
it('can hide the promo', async () => {
3030
renderWithLocalizationProvider(
31-
<ProductPromo type="settings" monitorPromo={{ hidePromo: true }} />
31+
<ProductPromo type="settings" vpnPromo={{ hidePromo: true }} />
3232
);
3333

3434
// nothing should render
3535
await waitFor(() =>
36-
expect(screen.queryByAltText('Mozilla Monitor')).toBeNull()
36+
expect(screen.queryByAltText('Mozilla VPN')).toBeNull()
3737
);
3838
});
3939

4040
it('can show promo', async () => {
4141
renderWithLocalizationProvider(
42-
<ProductPromo type="settings" monitorPromo={{ hidePromo: false }} />
42+
<ProductPromo type="settings" vpnPromo={{ hidePromo: false }} />
4343
);
4444

4545
await waitFor(() =>
4646
expect(
4747
screen.getByText(
48-
'Find where your private info is exposed and take control'
48+
'Discover an added layer of anonymous browsing and protection.'
4949
)
5050
).toBeVisible()
5151
);
52-
expect(
53-
screen.getByRole('link', { name: /Get free scan/i })
54-
).toHaveAttribute(
52+
expect(screen.getByRole('link', { name: /Get VPN/i })).toHaveAttribute(
5553
'href',
56-
'https://monitor.mozilla.org/?utm_source=moz-account&utm_medium=referral&utm_term=settings&utm_content=get-free-scan-global&utm_campaign=settings-promo'
54+
'https://vpn.mozilla.org/?utm_source=moz-account&utm_medium=mozilla-websites&utm_term=settings&utm_content=vpn&utm_campaign=settings-promo'
5755
);
5856
});
5957

@@ -62,59 +60,54 @@ describe('ProductPromo', () => {
6260
renderWithLocalizationProvider(
6361
<ProductPromo
6462
type="settings"
65-
monitorPromo={{
63+
vpnPromo={{
6664
hidePromo: false,
67-
gleanEvent: { event: { reason: 'default' } },
6865
}}
6966
/>
7067
);
7168

7269
await waitFor(() =>
7370
expect(
7471
screen.getByText(
75-
'Find where your private info is exposed and take control'
72+
'Discover an added layer of anonymous browsing and protection.'
7673
)
7774
).toBeVisible()
7875
);
7976
await user.click(
8077
screen.getByRole('link', {
81-
name: /Get free scan/i,
78+
name: /Get VPN/i,
8279
})
8380
);
8481
await waitFor(() => {
85-
expect(GleanMetrics.accountPref.promoMonitorSubmit).toHaveBeenCalledWith({
86-
event: { reason: 'default' },
87-
});
82+
expect(GleanMetrics.accountPref.promoVpnSubmit).toHaveBeenCalledWith();
8883
});
8984
});
9085

9186
describe('getProductPromoData', () => {
92-
it('hides promo when Monitor is present', () => {
87+
it('hides promo when VPN is present', () => {
9388
const result = getProductPromoData([
94-
{ name: MozServices.Monitor },
89+
{ name: MozServices.MozillaVPN },
9590
] as AttachedClient[]);
9691
expect(result).toEqual({ hidePromo: true });
9792
});
9893

99-
it('hides promo when Monitor Stage is present', () => {
94+
it('hides promo when VPN Stage is present', () => {
10095
const result = getProductPromoData([
101-
{ name: MozServices.MonitorStage },
96+
{ name: MozServices.VPNStage },
10297
] as AttachedClient[]);
10398
expect(result).toEqual({ hidePromo: true });
10499
});
105100

106-
it('shows promo and provides gleanEvent when Monitor not present', () => {
101+
it('shows promo when VPN not present', () => {
107102
const result = getProductPromoData([
108103
{ name: MozServices.Default },
109104
] as AttachedClient[]);
110105
expect(result.hidePromo).toBe(false);
111-
expect(result.gleanEvent).toEqual({ event: { reason: 'default' } });
112106
});
113107

114-
it('shows promo with gleanEvent when there are no attached clients', () => {
108+
it('shows promo when there are no attached clients', () => {
115109
const result = getProductPromoData([] as AttachedClient[]);
116110
expect(result.hidePromo).toBe(false);
117-
expect(result.gleanEvent).toEqual({ event: { reason: 'default' } });
118111
});
119112
});
120113
});

0 commit comments

Comments
 (0)