Commit fafd355
authored
feat: Perps Watchlist empty state (MetaMask#31242)
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.
type=text Section must contain non-placeholder prose.
type=changelog Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section blocks the PR
check.
Sections without a directive are checked for structural presence only.
-->
## **Description**
<!-- mms-check: type=text required=true -->
1. Empty state: When the watchlist is empty, suggests the top 5 markets
by 24h volume. Each row shows the asset's live price and 24h change
alongside a "+" button to add to the watchlist.
2. Expand/collapse: When the watchlist has more than 3 markets, only the
first 3 are shown with a "Show X more" toggle. A "Show less" button
collapses it back.
3. Watchlist filter badge: A star badge appears at the start of the
market list filter row (before Crypto/Stocks/etc.) when the user has
watchlist markets. Tapping it filters the list to watchlisted assets
only. Mutually exclusive with category filters. When empty, we show the
same default state as on perps home
4. Watchlist header chevron: The "Watchlist" section header on the home
screen now has an arrow that deep-links into the full market list with
the star filter pre-selected. Hidden when the watchlist is empty.
## **Changelog**
<!-- mms-check: type=changelog required=true -->
<!--
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: Add new empty state for Perps Watchlist
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2725
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Feature: Perps market list filter mutual exclusivity
Scenario: Watchlist deep link clears active category filter
Given the market list screen is already mounted
And a category filter (e.g. "Stocks") is active
When the user navigates from the home watchlist header with showWatchlistOnly
Then the star (watchlist) filter is turned on
And the category filter is reset to "All"
And all watchlisted markets are visible regardless of category
Scenario: Selecting a category deactivates the watchlist filter
Given the watchlist filter is active
When the user taps a category badge (e.g. "Crypto")
Then the category filter is applied
And the watchlist filter is turned off
And all markets in that category are shown
Scenario: Activating the watchlist filter clears an active category
Given a category filter is active
When the user taps the star badge to enable the watchlist filter
Then the watchlist filter is turned on
And the category filter is reset to "All"
Feature: Category badge screen reader labels
Scenario: Screen reader announces correct category name
Given a category badge is displayed (e.g. "Forex")
When a screen reader focuses the badge
Then it announces "Forex"
And not a raw i18n key or empty string
```
## **Screenshots/Recordings**
<!-- mms-check: type=screenshot required=true -->
https://github.com/user-attachments/assets/00278952-9e7e-478a-a84f-3afec948bdf3
## **Pre-merge author checklist**
<!-- mms-check: type=checklist required=true -->
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [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
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] 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)
- [x] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [x] 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
- [x] 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**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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**
> Touches watchlist persistence paths and navigation params across
several Perps screens; behavior is well covered by tests but scope is
broad for a user-facing feature.
>
> **Overview**
> Adds a **Perps watchlist empty state and discovery flow** across home,
market list, wallet tab, and market details.
>
> **Watchlist UI:** `PerpsWatchlistMarkets` now accepts **suggested
markets** (top volume via `getSuggestedWatchlistMarkets`), shows an
empty subtitle with **+ add** rows, **show more/less** when more than
three saved markets, and an optional **header chevron**
(`onSeeAllPress`) to open the full list with watchlist-only mode.
Suggested rows hide when the list hits **`WATCHLIST_LIMIT` (10)**.
>
> **Market list:** A **star filter badge** on the category row toggles
watchlist-only view, **mutually exclusive** with category filters
(synced in `usePerpsMarketListView` and list handlers). Empty watchlist
filter reuses `PerpsWatchlistMarkets` instead of the old favorites empty
copy; sort row hides while the star filter is active.
>
> **Actions & limits:** New **`usePerpsWatchlistActions`** centralizes
add/remove with analytics and toasts; **`PerpsMarketRowItem`** gains
optional **`onAddPress`**. Market details blocks favoriting at the cap
with a limit toast.
>
> **Wallet Perps tab:** **`PerpsTabView`** (with styles/tests) shows
watchlist + explore markets when there are no positions/orders, wired
through **`usePerpsTabExploreData`**.
>
> **Supporting:** New i18n strings, test IDs, trace name `PerpsTabView`,
category badge **icon mode** + required **`accessibilityLabel`**.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fe82a1e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent b470975 commit fafd355
34 files changed
Lines changed: 2933 additions & 427 deletions
File tree
- app
- components/UI/Perps
- Views
- PerpsHomeView
- PerpsMarketDetailsView
- PerpsMarketListView
- components/PerpsMarketFiltersBar
- PerpsTabView
- components
- PerpsMarketCategoryBadges
- PerpsMarketCategoryBadge
- PerpsMarketRowItem
- PerpsWatchlistMarkets
- hooks
- utils
- util
- locales/languages
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
148 | 148 | | |
149 | 149 | | |
150 | 150 | | |
| 151 | + | |
| 152 | + | |
151 | 153 | | |
152 | 154 | | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
153 | 169 | | |
154 | 170 | | |
155 | 171 | | |
| |||
166 | 182 | | |
167 | 183 | | |
168 | 184 | | |
| 185 | + | |
| 186 | + | |
169 | 187 | | |
170 | 188 | | |
171 | 189 | | |
| |||
238 | 256 | | |
239 | 257 | | |
240 | 258 | | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
241 | 266 | | |
242 | 267 | | |
243 | 268 | | |
| |||
Lines changed: 11 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
243 | 243 | | |
244 | 244 | | |
245 | 245 | | |
| 246 | + | |
246 | 247 | | |
247 | 248 | | |
248 | 249 | | |
| |||
743 | 744 | | |
744 | 745 | | |
745 | 746 | | |
| 747 | + | |
746 | 748 | | |
747 | 749 | | |
748 | 750 | | |
749 | 751 | | |
750 | 752 | | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
751 | 762 | | |
752 | 763 | | |
753 | 764 | | |
| |||
Lines changed: 17 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
116 | 116 | | |
117 | 117 | | |
118 | 118 | | |
| 119 | + | |
| 120 | + | |
119 | 121 | | |
120 | 122 | | |
121 | 123 | | |
| |||
200 | 202 | | |
201 | 203 | | |
202 | 204 | | |
| 205 | + | |
203 | 206 | | |
204 | 207 | | |
205 | 208 | | |
| |||
674 | 677 | | |
675 | 678 | | |
676 | 679 | | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
677 | 692 | | |
678 | | - | |
| 693 | + | |
679 | 694 | | |
680 | 695 | | |
681 | 696 | | |
682 | | - | |
683 | 697 | | |
684 | 698 | | |
685 | 699 | | |
| |||
695 | 709 | | |
696 | 710 | | |
697 | 711 | | |
698 | | - | |
| 712 | + | |
699 | 713 | | |
700 | 714 | | |
701 | 715 | | |
| |||
Lines changed: 33 additions & 27 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
| |||
92 | 93 | | |
93 | 94 | | |
94 | 95 | | |
95 | | - | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
96 | 103 | | |
97 | 104 | | |
98 | 105 | | |
| |||
115 | 122 | | |
116 | 123 | | |
117 | 124 | | |
118 | | - | |
| 125 | + | |
119 | 126 | | |
120 | 127 | | |
121 | 128 | | |
| |||
128 | 135 | | |
129 | 136 | | |
130 | 137 | | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
131 | 142 | | |
132 | | - | |
| 143 | + | |
133 | 144 | | |
134 | 145 | | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
135 | 155 | | |
136 | 156 | | |
137 | 157 | | |
| |||
221 | 241 | | |
222 | 242 | | |
223 | 243 | | |
224 | | - | |
225 | | - | |
| 244 | + | |
| 245 | + | |
226 | 246 | | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
233 | | - | |
234 | | - | |
235 | | - | |
236 | | - | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
249 | 252 | | |
250 | 253 | | |
251 | 254 | | |
| |||
335 | 338 | | |
336 | 339 | | |
337 | 340 | | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
338 | 344 | | |
339 | 345 | | |
340 | 346 | | |
| |||
Lines changed: 3 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
97 | | - | |
| 97 | + | |
98 | 98 | | |
99 | 99 | | |
| 100 | + | |
100 | 101 | | |
101 | 102 | | |
102 | 103 | | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
| 104 | + | |
107 | 105 | | |
108 | 106 | | |
109 | 107 | | |
| |||
Lines changed: 17 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
31 | 34 | | |
32 | 35 | | |
33 | 36 | | |
34 | 37 | | |
35 | 38 | | |
36 | 39 | | |
37 | | - | |
| 40 | + | |
38 | 41 | | |
39 | 42 | | |
40 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
41 | 47 | | |
42 | 48 | | |
43 | 49 | | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
52 | 60 | | |
53 | 61 | | |
54 | 62 | | |
| |||
Lines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
30 | 45 | | |
31 | 46 | | |
32 | 47 | | |
| |||
0 commit comments