Skip to content

Commit 3feccf9

Browse files
committed
added pna-25 banner
1 parent 7411092 commit 3feccf9

File tree

6 files changed

+138
-2
lines changed

6 files changed

+138
-2
lines changed

app/_locales/en/messages.json

Lines changed: 7 additions & 1 deletion
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: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ export type AppStateControllerState = {
101101
networkConnectionBanner: NetworkConnectionBanner;
102102
newPrivacyPolicyToastClickedOrClosed: boolean | null;
103103
newPrivacyPolicyToastShownDate: number | null;
104+
pna25BannerClickedOrClosed: boolean | null;
105+
pna25BannerDismissedDate: number | null;
104106
nftsDetectionNoticeDismissed: boolean;
105107
nftsDropdownState: Json;
106108
notificationGasPollTokens: string[];
@@ -269,6 +271,8 @@ const getDefaultAppStateControllerState = (): AppStateControllerState => ({
269271
lastViewedUserSurvey: null,
270272
newPrivacyPolicyToastClickedOrClosed: null,
271273
newPrivacyPolicyToastShownDate: null,
274+
pna25BannerClickedOrClosed: null,
275+
pna25BannerDismissedDate: null,
272276
nftsDetectionNoticeDismissed: false,
273277
notificationGasPollTokens: [],
274278
onboardingDate: null,
@@ -466,6 +470,18 @@ const controllerMetadata: StateMetadata<AppStateControllerState> = {
466470
includeInDebugSnapshot: true,
467471
usedInUi: true,
468472
},
473+
pna25BannerClickedOrClosed: {
474+
includeInStateLogs: true,
475+
persist: true,
476+
includeInDebugSnapshot: true,
477+
usedInUi: true,
478+
},
479+
pna25BannerDismissedDate: {
480+
includeInStateLogs: true,
481+
persist: true,
482+
includeInDebugSnapshot: true,
483+
usedInUi: true,
484+
},
469485
nftsDetectionNoticeDismissed: {
470486
includeInStateLogs: true,
471487
persist: true,
@@ -874,6 +890,18 @@ export class AppStateController extends BaseController<
874890
});
875891
}
876892

893+
setPna25BannerClickedOrClosed(): void {
894+
this.update((state) => {
895+
state.pna25BannerClickedOrClosed = true;
896+
});
897+
}
898+
899+
setPna25BannerDismissedDate(time: number): void {
900+
this.update((state) => {
901+
state.pna25BannerDismissedDate = time;
902+
});
903+
}
904+
877905
setShieldPausedToastLastClickedOrClosed(time: number): void {
878906
this.update((state) => {
879907
state.shieldPausedToastLastClickedOrClosed = time;

ui/components/app/toast-master/selectors.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
getPermissions,
1818
isSolanaAccount,
1919
} from '../../../selectors';
20+
import { getRemoteFeatureFlags } from '../../../selectors/remote-feature-flags';
2021
import { MetaMaskReduxState } from '../../../store/store';
2122
import {
2223
PasswordChangeToastType,
@@ -47,6 +48,9 @@ type State = {
4748
| 'surveyLinkLastClickedOrClosed'
4849
| 'shieldEndingToastLastClickedOrClosed'
4950
| 'shieldPausedToastLastClickedOrClosed'
51+
| 'pna25BannerClickedOrClosed'
52+
| 'participateInMetaMetrics'
53+
| 'remoteFeatureFlags'
5054
>
5155
>;
5256
};
@@ -234,3 +238,51 @@ export function selectShowShieldEndingToast(
234238
): boolean {
235239
return !state.metamask.shieldEndingToastLastClickedOrClosed;
236240
}
241+
242+
/**
243+
* Determines if the PNA25 banner should be shown based on:
244+
* - LaunchDarkly feature flag (extension-ux-pna25) is enabled
245+
* - User has opted into metrics (participateInMetaMetrics === true)
246+
* - User onboarded before the PNA25 release date
247+
* - User hasn't dismissed the banner
248+
*
249+
* @param state - The application state containing PNA25 banner data.
250+
* @returns Object with showPna25Banner boolean and pna25BannerShownDate
251+
*/
252+
export function selectShowPna25Banner(state: Pick<State, 'metamask'>): boolean {
253+
const {
254+
pna25BannerClickedOrClosed,
255+
onboardingDate,
256+
participateInMetaMetrics,
257+
} = state.metamask || {};
258+
259+
// Get the feature flag from LaunchDarkly
260+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
261+
const remoteFeatureFlags = getRemoteFeatureFlags(state as any);
262+
const pna25Timestamp = remoteFeatureFlags?.['extension-ux-pna25'];
263+
264+
const currentDate = Date.now();
265+
266+
// Check all conditions
267+
if (!pna25Timestamp || typeof pna25Timestamp !== 'number') {
268+
return false; // LD flag not set or invalid
269+
}
270+
271+
if (participateInMetaMetrics !== true) {
272+
return false; // User hasn't opted into metrics
273+
}
274+
275+
if (pna25BannerClickedOrClosed) {
276+
return false; // User already dismissed banner
277+
}
278+
279+
if (currentDate < pna25Timestamp) {
280+
return false; // PNA25 date hasn't passed yet
281+
}
282+
283+
if (!onboardingDate || onboardingDate >= pna25Timestamp) {
284+
return false; // User onboarded after PNA25 or no onboarding date
285+
}
286+
287+
return true;
288+
}

ui/components/app/toast-master/toast-master.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ import {
9494
selectClaimSubmitToast,
9595
selectShowShieldPausedToast,
9696
selectShowShieldEndingToast,
97+
selectShowPna25Banner,
9798
} from './selectors';
9899
import {
99100
setNewPrivacyPolicyToastClickedOrClosed,
@@ -106,6 +107,8 @@ import {
106107
setShowClaimSubmitToast,
107108
setShieldPausedToastLastClickedOrClosed,
108109
setShieldEndingToastLastClickedOrClosed,
110+
setPna25BannerClickedOrClosed,
111+
setPna25BannerDismissedDate,
109112
} from './utils';
110113

111114
export function ToastMaster({ location } = {}) {
@@ -129,6 +132,7 @@ export function ToastMaster({ location } = {}) {
129132
)}
130133
<SurveyToastMayDelete />
131134
<PrivacyPolicyToast />
135+
<Pna25Banner />
132136
<NftEnablementToast />
133137
<PermittedNetworkToast />
134138
<NewSrpAddedToast />
@@ -749,3 +753,35 @@ function ShieldEndingToast() {
749753
)
750754
);
751755
}
756+
757+
function Pna25Banner() {
758+
const t = useI18nContext();
759+
760+
const showPna25Banner = useSelector(selectShowPna25Banner);
761+
762+
const handleDismiss = () => {
763+
setPna25BannerClickedOrClosed();
764+
setPna25BannerDismissedDate(Date.now());
765+
};
766+
767+
return (
768+
showPna25Banner && (
769+
<Toast
770+
key="pna25-banner"
771+
dataTestId="pna25-banner"
772+
startAdornment={
773+
<Icon name={IconName.Info} color={IconColor.infoDefault} />
774+
}
775+
text={t('pna25BannerTitle')}
776+
actionText={t('pna25BannerActionButton')}
777+
onActionClick={() => {
778+
global.platform.openTab({
779+
url: PRIVACY_POLICY_LINK,
780+
});
781+
handleDismiss();
782+
}}
783+
onClose={handleDismiss}
784+
/>
785+
)
786+
);
787+
}

ui/components/app/toast-master/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,11 @@ export function setShieldEndingToastLastClickedOrClosed(time: number) {
117117
time,
118118
]);
119119
}
120+
121+
export function setPna25BannerClickedOrClosed() {
122+
submitRequestToBackgroundAndCatch('setPna25BannerClickedOrClosed');
123+
}
124+
125+
export function setPna25BannerDismissedDate(time: number) {
126+
submitRequestToBackgroundAndCatch('setPna25BannerDismissedDate', [time]);
127+
}

0 commit comments

Comments
 (0)