Skip to content

Commit ead303c

Browse files
authored
feat: added pna-25 banner (#38112)
This PR is to add the updated privacy notice banner on homepage # Feature Flow Diagram ``` ┌─────────────────────────────────────────────────────────────────────┐ │ USER TYPE DETECTION │ └─────────────────────────────────────────────────────────────────────┘ │ ┌────────────────┴────────────────┐ │ │ ▼ ▼ ┌─────────────────┐ ┌──────────────────┐ │ NEW USER │ │ EXISTING USER │ │ (Onboarding) │ │ (Already setup) │ └────────┬────────┘ └────────┬─────────┘ │ │ │ │ ┌────────▼─────────┐ ┌───────▼──────────┐ │ Check LD Flag │ │ Check State │ │ (extensionUxPna25) │ │ newUserFeature │ │ │ │ Acknowledged? │ └────────┬─────────┘ └───────┬──────────┘ │ │ ┌───────┴────────┐ ▼ │ │ = null or false ▼ ▼ (State didn't exist LD = true LD = false when they onboarded) │ │ │ │ │ │ ▼ ▼ ┌───────▼──────────┐ ┌───────────┐ ┌───────────┐ │ Check LD Flag │ │Set state │ │ State │ │ (Feature X) │ │to TRUE │ │ remains │ └────────┬─────────┘ │ │ │ null │ │ │(auto- │ │ │ ┌───────┴────────┐ │acknowledged)│ │(Feature │ │ │ └─────┬─────┘ │ disabled) │ ▼ ▼ │ └─────┬─────┘ LD = true LD = false │ │ │ │ ▼ ▼ │ │ ┌──────────────────────────────┐ ▼ ▼ │ Continue with onboarding │ ┌──────────┐ ┌──────────┐ │ (User experiences feature │ │ SHOW │ │ DON'T │ │ naturally) │ │ BANNER │ │ SHOW │ └──────────────────────────────┘ │ │ │ BANNER │ │"Hey! New │ │ │ │ Feature" │ │(Feature │ └────┬─────┘ │ not │ │ │ enabled) │ │ └──────────┘ ▼ ┌──────────────────┐ │ User Clicks │ │ Banner/Button │ └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Set state to │ │ TRUE │ │ │ │ (Changed from │ │ null/false │ │ to true) │ └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Banner disappears│ │ (permanently) │ │ │ │ User now has │ │ acknowledged the │ │ new feature │ └──────────────────┘ ┌─────────────────────────────────────────────────────────────────────┐ │ STATE VALUES │ ├─────────────────────────────────────────────────────────────────────┤ │ TRUE = User has acknowledged the feature │ │ - NEW users: Set during onboarding (if LD flag ON) │ │ - EXISTING users: Set after clicking banner │ │ │ │ FALSE = User hasn't acknowledged yet (or feature was OFF) │ │ - EXISTING users: Start with FALSE (not null) │ │ - NEW users: If LD flag is OFF during onboarding │ │ │ │└─────────────────────────────────────────────────────────────────────┘ ``` ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Introduces metametrics banner ## **Related issues** Fixes: [issue](https://consensyssoftware.atlassian.net/browse/CEUX-716?atlOrigin=eyJpIjoiNThiZDViYmI2NTA5NDVhYjhiMGVmMmIyODlmOTY1NmIiLCJwIjoiaiJ9) ## **Manual testing steps** 1. If user onboarded (existing user), opted for metametrics, LD flag on -> Banner should show 2. If user onboarded (existing user), not opted for metametrics, LD flag on -> Banner shouldn't show 3. New user and LD flag on -> Banner shouldn't show 4. LD flag off -> Banner shouldn't show ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** ![Screenshot 2025-11-26 at 5 27 21 PM](https://github.com/user-attachments/assets/8ebac63c-ca1c-4344-8489-dca08c6dd929) ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a feature-flagged MetaMetrics privacy banner (`PNA25`) with persisted `pna25Acknowledged` state, onboarding/use-metrics integration, and supporting env/config/i18n updates. > > - **UI**: > - **Toast**: New `Pna25Banner` in `ui/components/app/toast-master/toast-master.js` with selector `selectShowPna25Banner` and action to acknowledge (`setPna25Acknowledged`). > - **Selectors/Utils**: Add `selectShowPna25Banner` in `toast-master/selectors.ts`; wire `setPna25Acknowledged` in `toast-master/utils.ts`. > - **Hooks**: `useEnableMetametrics` auto-acknowledges when `extensionUxPna25` enabled and `pna25Acknowledged === false`. > - **Onboarding**: `metametrics.js` and `welcome.js` set `pna25Acknowledged` for new/social users when `EXTENSION_UX_PNA25` is enabled; updated checkbox copy toggle. > - **State/Controllers**: > - Add `pna25Acknowledged` to `AppStateController` state, defaults, metadata, setter `setPna25Acknowledged`, and background API exposure via `metamask-controller.js`. > - Include in Sentry safe-state: `app/scripts/constants/sentry-state.ts`. > - Types: add to `shared/types/background.ts`; selector `getPna25Acknowledged`. > - **Build/Env**: > - New env flag `EXTENSION_UX_PNA25: true` across `builds.yml` and default envs. > - **i18n/Links**: > - New messages `pna25BannerTitle`, `onboardingMetametricCheckboxDescriptionOneUpdated` in `app/_locales/en*/messages.json`. > - Add `METAMETRICS_SETTINGS_LINK` in `shared/lib/ui-utils.js`. > - **Tests/Fixtures**: > - Update e2e fixtures and state-snapshot schemas to include `pna25Acknowledged` and related ordering tweaks. > - **Plumbing**: > - UI actions: new `setPna25Acknowledged` in `ui/store/actions.ts` and background wiring. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit bf7d334. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent f855a5e commit ead303c

File tree

23 files changed

+361
-176
lines changed

23 files changed

+361
-176
lines changed

app/_locales/en/messages.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/_locales/en_GB/messages.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/scripts/constants/sentry-state.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export const SENTRY_BACKGROUND_STATE = {
9393
shieldEndingToastLastClickedOrClosed: true,
9494
shieldPausedToastLastClickedOrClosed: true,
9595
isWalletResetInProgress: false,
96+
pna25Acknowledged: false,
9697
},
9798
MultichainBalancesController: {
9899
balances: false,

app/scripts/controllers/app-state-controller.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,7 @@ describe('AppStateController', () => {
792792
"outdatedBrowserWarningLastShown": null,
793793
"pendingShieldCohort": null,
794794
"pendingShieldCohortTxType": null,
795+
"pna25Acknowledged": false,
795796
"popupGasPollTokens": [],
796797
"productTour": "accountIcon",
797798
"recoveryPhraseReminderHasBeenShown": false,
@@ -883,6 +884,7 @@ describe('AppStateController', () => {
883884
"outdatedBrowserWarningLastShown": null,
884885
"pendingShieldCohort": null,
885886
"pendingShieldCohortTxType": null,
887+
"pna25Acknowledged": false,
886888
"popupGasPollTokens": [],
887889
"productTour": "accountIcon",
888890
"recoveryPhraseReminderHasBeenShown": false,
@@ -963,6 +965,7 @@ describe('AppStateController', () => {
963965
"onboardingDate": null,
964966
"outdatedBrowserWarningLastShown": null,
965967
"pendingShieldCohortTxType": null,
968+
"pna25Acknowledged": false,
966969
"productTour": "accountIcon",
967970
"recoveryPhraseReminderHasBeenShown": false,
968971
"recoveryPhraseReminderLastShown": 1000,
@@ -1053,6 +1056,7 @@ describe('AppStateController', () => {
10531056
"outdatedBrowserWarningLastShown": null,
10541057
"pendingShieldCohort": null,
10551058
"pendingShieldCohortTxType": null,
1059+
"pna25Acknowledged": false,
10561060
"popupGasPollTokens": [],
10571061
"productTour": "accountIcon",
10581062
"recoveryPhraseReminderHasBeenShown": false,

app/scripts/controllers/app-state-controller.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export type AppStateControllerState = {
114114
networkConnectionBanner: NetworkConnectionBanner;
115115
newPrivacyPolicyToastClickedOrClosed: boolean | null;
116116
newPrivacyPolicyToastShownDate: number | null;
117+
pna25Acknowledged: boolean;
117118
nftsDetectionNoticeDismissed: boolean;
118119
nftsDropdownState: Json;
119120
notificationGasPollTokens: string[];
@@ -282,6 +283,7 @@ const getDefaultAppStateControllerState = (): AppStateControllerState => ({
282283
lastViewedUserSurvey: null,
283284
newPrivacyPolicyToastClickedOrClosed: null,
284285
newPrivacyPolicyToastShownDate: null,
286+
pna25Acknowledged: false,
285287
nftsDetectionNoticeDismissed: false,
286288
notificationGasPollTokens: [],
287289
onboardingDate: null,
@@ -479,6 +481,12 @@ const controllerMetadata: StateMetadata<AppStateControllerState> = {
479481
includeInDebugSnapshot: true,
480482
usedInUi: true,
481483
},
484+
pna25Acknowledged: {
485+
includeInStateLogs: true,
486+
persist: true,
487+
includeInDebugSnapshot: true,
488+
usedInUi: true,
489+
},
482490
nftsDetectionNoticeDismissed: {
483491
includeInStateLogs: true,
484492
persist: true,
@@ -887,6 +895,12 @@ export class AppStateController extends BaseController<
887895
});
888896
}
889897

898+
setPna25Acknowledged(acknowledged: boolean): void {
899+
this.update((state) => {
900+
state.pna25Acknowledged = acknowledged;
901+
});
902+
}
903+
890904
setShieldPausedToastLastClickedOrClosed(time: number): void {
891905
this.update((state) => {
892906
state.shieldPausedToastLastClickedOrClosed = time;

app/scripts/metamask-controller.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,6 +2986,8 @@ export default class MetamaskController extends EventEmitter {
29862986
appStateController.setShieldEndingToastLastClickedOrClosed.bind(
29872987
appStateController,
29882988
),
2989+
setPna25Acknowledged:
2990+
appStateController.setPna25Acknowledged.bind(appStateController),
29892991
setAppActiveTab:
29902992
appStateController.setAppActiveTab.bind(appStateController),
29912993
setDefaultSubscriptionPaymentOptions:

builds.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ buildTypes:
3535
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/10.2.3/index.html
3636
- ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management
3737
- IS_SIDEPANEL: true
38+
- EXTENSION_UX_PNA25: true
3839
# for seedless onboarding (social login)
3940
- GOOGLE_PROD_CLIENT_ID
4041
- APPLE_PROD_CLIENT_ID
@@ -69,6 +70,7 @@ buildTypes:
6970
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/10.2.3/index.html
7071
- ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management
7172
- IS_SIDEPANEL: false
73+
- EXTENSION_UX_PNA25: true
7274
# for seedless onboarding (social login)
7375
- GOOGLE_BETA_CLIENT_ID
7476
- APPLE_BETA_CLIENT_ID
@@ -103,6 +105,7 @@ buildTypes:
103105
- REJECT_INVALID_SNAPS_PLATFORM_VERSION: true
104106
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/10.2.3/index.html
105107
- ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management
108+
- EXTENSION_UX_PNA25: true
106109
# for seedless onboarding (social login)
107110
- GOOGLE_EXPERIMENTAL_CLIENT_ID
108111
- APPLE_EXPERIMENTAL_CLIENT_ID
@@ -138,6 +141,7 @@ buildTypes:
138141
- ACCOUNT_SNAPS_DIRECTORY_URL: https://metamask.github.io/snaps-directory-staging/main/account-management
139142
- EIP_4337_ENTRYPOINT: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'
140143
- IS_SIDEPANEL: false
144+
- EXTENSION_UX_PNA25: true
141145
# for seedless onboarding (social login)
142146
- GOOGLE_FLASK_CLIENT_ID
143147
- APPLE_FLASK_CLIENT_ID
@@ -460,3 +464,6 @@ env:
460464
# This should only be used for local testing, and should not be enabled in any
461465
# production builds (including beta and Flask).
462466
- FORCE_PREINSTALLED_SNAPS: 'false'
467+
468+
# PNA25 (Privacy Notice)
469+
- EXTENSION_UX_PNA25: true

shared/lib/ui-utils.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ export const SUPPORT_LINK = process.env.SUPPORT_LINK;
55
export const COINGECKO_LINK = 'https://www.coingecko.com/';
66
export const CRYPTOCOMPARE_LINK = 'https://www.cryptocompare.com/';
77
export const PRIVACY_POLICY_LINK = 'https://consensys.io/privacy-policy/';
8+
export const METAMETRICS_SETTINGS_LINK =
9+
'https://support.metamask.io/configure/privacy/how-to-manage-your-metametrics-settings/';
810
export const SURVEY_LINK = 'https://www.getfeedback.com/r/Oczu1vP0';
911

1012
// TODO make sure these links are correct

shared/types/background.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export type ControllerStatePropertiesEnumerated = {
117117
isRampCardClosed: AppStateControllerState['isRampCardClosed'];
118118
newPrivacyPolicyToastClickedOrClosed: AppStateControllerState['newPrivacyPolicyToastClickedOrClosed'];
119119
newPrivacyPolicyToastShownDate: AppStateControllerState['newPrivacyPolicyToastShownDate'];
120+
pna25Acknowledged: AppStateControllerState['pna25Acknowledged'];
120121
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
121122
// eslint-disable-next-line @typescript-eslint/naming-convention
122123
hadAdvancedGasFeesSetPriorToMigration92_3: AppStateControllerState['hadAdvancedGasFeesSetPriorToMigration92_3'];

test/e2e/fixtures/default-fixture.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ function defaultFixture(inputChainId = CHAIN_IDS.LOCALHOST) {
113113
notificationGasPollTokens: [],
114114
popupGasPollTokens: [],
115115
recoveryPhraseReminderHasBeenShown: true,
116+
pna25Acknowledged: false,
116117
recoveryPhraseReminderLastShown:
117118
'__FIXTURE_SUBSTITUTION__currentDateInMilliseconds',
118119
showTestnetMessageInDropdown: true,

0 commit comments

Comments
 (0)