Commit 71d5a1c
authored
feat: braze banner (#29301)
## **Description**
Adds a new `BrazeBanner` component to the wallet home screen that
displays Braze campaign content as a dismissible banner card.
**What changed:**
- New BrazeBanner UI backed by BrazeBannerCard for rendering campaign
content (title, body, image, CTA)
- `useBrazeBanner` hook drives the state machine: `loading → visible |
empty`, `visible → dismissed`
- Banner deeplinks are validated against an allowlist before being
routed through the app's deeplink pipeline
- Dismissal is always in-memory for the session; for non-test-send
campaigns with a `campaign_name` property, dismissal is also persisted
to Redux and Braze is notified — so the same banner is suppressed on the
following session's first render, then the guard is cleared
- New `banners` Redux slice field `lastDismissedBrazeBanner` + migration
133
- New Braze core helpers: `getBannerForPlacement`,
`refreshBrazeBanners`, `logBrazeBannerImpression`,
`logBrazeBannerClick`, `dismissBrazeBanner`
- Braze identity sync now refreshes banners on sign-in
- Banner is integrated into the Wallet home screen behind the
`brazeBannerHome` remote feature flag, taking priority over the existing
Carousel, wrapped in `ComponentErrorBoundary`
## **Changelog**
CHANGELOG entry: Added a Braze-driven promotional banner to the wallet
home screen
## **Related issues**
Fixes:
## **Manual testing steps**
> To test with real banners, share your Braze profile ID with the author
so a campaign can be targeted to your device.
```gherkin
Feature: Braze home banner
Scenario: User sees the banner on app open
Given the user has an active Braze banner campaign targeting their profile
When the user opens the app and navigates to the wallet home screen
Then the banner is displayed at the top of the home screen
Scenario: User dismisses the banner
Given the banner is visible on the home screen
When the user taps the dismiss button
Then the banner disappears immediately
And the banner does not reappear for the rest of that session
And the same banner is not shown on the next app session
Scenario: Banner rotates between sessions
Given the user has previously dismissed a banner
When the user closes the app and reopens it
Then a different banner (if available) may be shown
And the previously dismissed banner is not shown
```
## **Screenshots/Recordings**
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<img width="434" height="891" alt="image"
src="https://github.com/user-attachments/assets/034d186c-0b77-43ef-8e01-55b6017b470b"
/>
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] 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-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **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]
> **Medium Risk**
> Adds a new Braze-powered banner surface on wallet home with deeplink
routing and persistent dismissal state, touching analytics and
navigation paths. Risk is mitigated by an explicit deeplink allowlist,
error boundary wrapping, and extensive unit tests, but it still
introduces remote-content driven UI/flows.
>
> **Overview**
> **Adds a new Braze-backed promotional banner on wallet home**,
rendered via `BrazeBanner`/`BrazeBannerCard` and controlled by a small
state machine (`loading`/`visible`/`empty`/`dismissed`) in
`useBrazeBanner` with warm-cache probing, event subscription, timeouts,
and foreground refresh.
>
> **Integrates the banner into the Wallet screen behind a new remote
feature flag** (`brazeBannerHomeMinVersion`), taking priority over the
existing `Carousel` when enabled and wrapped in `ComponentErrorBoundary`
so failures don’t block the home UI.
>
> **Extends Braze and Redux plumbing**: adds core helpers for banner
fetch/refresh and impression/click/dismiss logging; introduces
`banners.lastDismissedBrazeBanner` with migration `134` to persist the
last dismissed campaign; and adds a deeplink allowlist
(`isAllowedBrazeDeeplink`) to block unsafe schemes/hosts and explicitly
reject MWP connection links. Updates test mocks/registries accordingly.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
38b9ee6. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent 94e8c0f commit 71d5a1c
44 files changed
Lines changed: 3358 additions & 72 deletions
File tree
- .github
- scripts
- app
- components
- UI
- BrazeBanner
- Carousel
- Views/Wallet
- hooks
- core/Braze
- hooks
- useBrazeIdentity
- reducers/banners
- selectors
- featureFlagController/brazeBannerHome
- store/migrations
- util
- identity/hooks
- useBrazeIdentity
- useIdentityEffects
- test
- tests/feature-flags
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
155 | 159 | | |
156 | 160 | | |
157 | 161 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
0 commit comments