Commit f088cd1
chore: relax-price-api-condition-legacy-chart and update to time based index (#33204)
## **Description**
### Purpose
This PR improves the legacy price chart on the Token Details Page (TDP)
with two changes:
1. **Time-based x-axis** — switched PriceChart from index-based to
time-based x-axis so partial data (e.g. 14h of data in a 24h window)
renders at its correct temporal position within the full time range,
with a visible gap on the left.
2. **Relaxed coverage threshold** — lowered `MIN_COVERAGE_RATIO` from
0.95 to 0.20. With the time-based x-axis, partial data is no longer
misleading, so the no-data overlay only triggers for extremely sparse
responses (<20% of the requested period).
### Changes
**`app/components/UI/AssetOverview/PriceChart/PriceChart.tsx`**
- Added `timePeriodMs?: number` prop
- Uses `xAccessor`/`yAccessor`/`xScale` with d3 `scaleTime` for
time-based positioning
- Sets `xMin = Date.now() - timePeriodMs` and `xMax = Date.now()`
- Rewrote touch logic: pixel → inverse scale → timestamp → binary search
nearest point
- Fixed stale PanResponder closure by routing through refs
- Fixed Tooltip and EndDot to use `x(timestamp)` instead of `x(index)`
**`app/components/UI/AssetOverview/Price/Price.legacy.tsx`**
- Passes `TIME_PERIOD_MS[timePeriod]` as `timePeriodMs` to PriceChart
**`app/components/UI/AssetOverview/Price/tokenOverviewChart.constants.ts`**
- Added `TIME_PERIOD_MS` mapping (`TimePeriod → number | null`)
**`app/components/hooks/useTokenHistoricalPrices.ts`**
- Lowered `MIN_COVERAGE_RATIO` from 0.95 to 0.20
### Scope
Only the Token Details Page (TDP) is affected. `TraderPriceChart.tsx`
and other consumers are **not** modified.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3618
## **Manual testing steps**
```gherkin
Feature: Legacy price chart renders partial data with correct time positioning
Scenario: Chart shows gap for partial 1D data
Given the user navigates to Token Details for a newly listed token
And the price API returns less than 24h of data for the 1D period
When the chart renders
Then there is a visible gap on the left side of the chart
And the price line starts at the actual first data timestamp
And the right edge of the chart represents "now"
Scenario: Touch/scrub selects correct data point
Given the user is viewing a chart with partial data and a gap on the left
When the user long-presses and drags on the chart
Then the tooltip snaps to the nearest actual data point
And does not select phantom points in the gap area
Scenario: ALL time range falls back to index-based
Given the user selects the "ALL" time period
When the chart renders
Then data fills the full chart width (no gap, index-based)
Scenario: No-data overlay shows for extremely sparse data
Given the price API returns data covering less than 20% of the requested period
When the chart renders
Then the no-data overlay is displayed
```
## **Screenshots/Recordings**
### **Before**
Chart stretches partial data (14h) across full width, making it look
like 24h of data.
### **After**
Chart correctly shows a gap on the left, with data starting at its
actual first timestamp.
https://github.com/user-attachments/assets/97ffcc5e-4f97-4b94-8330-763013f67037
## **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
- [x] I've included tests if applicable
- [x] 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)
- [x] I've tested on iOS
- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
## **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**
> Chart rendering and touch-selection behavior change on token details;
scope is UI-only but users may misread partial history if the new gap
layout is wrong.
>
> **Overview**
> The legacy token overview **PriceChart** can use a **time-based
x-axis** when `timePeriodMs` is passed from `Price.legacy` via new
`TIME_PERIOD_MS` constants. Fixed windows anchor from `now - period` to
`now`, so sparse history (e.g. 14h in 1D) draws at the correct time with
a **left gap** instead of stretching across the full width. **ALL**
still omits `timePeriodMs` and keeps **index-based** layout.
>
> Touch/scrub maps pixels to timestamps and uses exported
**`findNearestIndex`**; tooltip, end dot, and **`AreaChart`** accessors
switch between timestamp and index. **PanResponder** handlers go through
refs to avoid stale closures.
>
> **`hasInsufficientTimeCoverage`** threshold drops from **95% to 20%**
(`MIN_COVERAGE_RATIO`), so the no-data overlay only appears for very
sparse API responses; docs/comments align with the 50% boundary
behavior. Tests cover pass-through, time-based touch,
`findNearestIndex`, and updated coverage cases.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
dd06940. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>1 parent 53996cd commit f088cd1
7 files changed
Lines changed: 302 additions & 52 deletions
File tree
- app/components
- UI/AssetOverview
- PriceChart
- Price
- hooks
Lines changed: 26 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
14 | 17 | | |
15 | 18 | | |
16 | 19 | | |
| |||
195 | 198 | | |
196 | 199 | | |
197 | 200 | | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
198 | 223 | | |
199 | 224 | | |
200 | 225 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
24 | 27 | | |
25 | 28 | | |
26 | 29 | | |
| |||
201 | 204 | | |
202 | 205 | | |
203 | 206 | | |
| 207 | + | |
204 | 208 | | |
205 | 209 | | |
206 | 210 | | |
| |||
Lines changed: 18 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
21 | 39 | | |
22 | 40 | | |
23 | 41 | | |
| |||
Lines changed: 126 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
258 | 258 | | |
259 | 259 | | |
260 | 260 | | |
| 261 | + | |
| 262 | + | |
261 | 263 | | |
262 | | - | |
| 264 | + | |
263 | 265 | | |
264 | 266 | | |
265 | 267 | | |
| |||
315 | 317 | | |
316 | 318 | | |
317 | 319 | | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
318 | 442 | | |
319 | 443 | | |
0 commit comments