Skip to content

Conversation

@jsoningram
Copy link
Contributor

@jsoningram jsoningram commented Nov 25, 2025

Asana Task/Github Issue: https://app.asana.com/1/137249556945/project/1211050482669423/task/1212009313322048?focus=true

Description

Implements an animated counter feature for the tracker and cookie pop-up counts displayed in the Protections section of the New Tab Page. Instead of the count instantly jumping to its final value, it now smoothly animates from a starting value to the target count, providing a more polished and engaging user experience.

animate.mov

Implementation Details

Animation Specification

The animateCount function implements a specific animation behavior based on count thresholds:

Initial Display Rules

  • Count < 5: No animation, displays target value immediately (still delays onComplete by 500ms)
  • Count 5-39: Animates from 75% of target value to 100%
  • Count ≥ 40: Animates from 85% of target value to 100%
  • Count > 9999: Capped at 9999 for display

Incremental Updates

When the count increases (e.g., from 50 to 55), the animation:

  • Starts from the current displayed value (50)
  • Animates smoothly to the new value (55)
  • Does NOT use percentage-based starting points

Animation Characteristics

  • Duration: 500ms
  • Easing: Cubic ease-in-out (approximates CSS cubic-bezier(0.42, 0.0, 0.58, 1.0))
  • Frame Updates: Uses requestAnimationFrame for smooth 60fps animation
  • Visibility Aware: Pauses/resumes based on page visibility

Hook Features (useAnimatedCount)

The useAnimatedCount hook provides:

  1. Automatic State Management: Maintains both the animated value and a ref for the current value
  2. Visibility Handling:
    • Cancels animation when page is hidden
    • Snaps to final value immediately when hidden
    • Resumes animation from current value when page becomes visible
  3. Cleanup: Automatically cancels animations on unmount
  4. Memoization: Uses useCallback to optimize performance

Testing

Visit the preview URL to see it in action.

The test suite (animateCount.spec.js) covers:

  • Basic Behavior: Initial display, threshold handling, completion callbacks
  • Edge Cases: Boundary values (5, 40, 9999), zero handling, capping behavior
  • Incremental Updates: Using fromValue parameter, smooth transitions
  • Cancellation: Cancel function behavior, cleanup
  • Easing Function: Cubic ease-in-out verification, monotonic progression
  • Duration: 500ms timing validation
  • Real-world Scenarios: Rapid updates, large jumps, integer-only values
  • Callback Behavior: Error handling, proper invocation

Testing Utilities

The suite includes a custom AnimationMocker class that:

  • Mocks requestAnimationFrame and cancelAnimationFrame
  • Mocks performance.now() for deterministic time control
  • Mocks setTimeout and clearTimeout
  • Provides tick() method to advance time programmatically
  • Provides runToCompletion() helper for full animation cycles

Checklist

Please tick all that apply:

  • I have tested this change locally
  • I have tested this change locally in all supported browsers
  • This change will be visible to users
  • I have added automated tests that cover this change
  • I have ensured the change is gated by config
  • This change was covered by a ship review
  • This change was covered by a tech design
  • Any dependent config has been merged

Note

Adds animated counts for trackers and cookie pop-ups in the Protections header using a new utility and hook, with style tweaks, mock updates, and comprehensive tests.

  • UI (Protections Header):
    • Animate displayed counts using useAnimatedCount in protections/components/ProtectionsHeading.js.
    • Defensive handling for totalCookiePopUpsBlocked; show CPM stats only when enabled and counts > 0.
    • Uses animated values to select singular/plural labels and zero state (noRecentTitle).
  • Utilities:
    • Add protections/utils/animateCount.js implementing 500ms cubic ease-in-out count animation with thresholds, caps, cancellation, and incremental updates.
    • Add protections/utils/useAnimatedCount.js hook with visibility-aware animations and cleanup.
  • Styles:
    • Tweak PrivacyStats.module.css headings: updated .title hierarchy, new .noRecentTitle, adjusted colors/sizing/spacing.
  • Mocks:
    • Update CPM mock value in protections.mock-transport.js (cpm=true -> 1222).
  • Tests:
    • Add protections/unit-tests/animateCount.spec.js covering thresholds, easing, duration, cancellation, incremental updates, and caps.

Written by Cursor Bugbot for commit 8f13df6. This will update automatically on new commits. Configure here.

@netlify
Copy link

netlify bot commented Nov 25, 2025

Deploy Preview for content-scope-scripts ready!

Name Link
🔨 Latest commit 8f13df6
🔍 Latest deploy log https://app.netlify.com/projects/content-scope-scripts/deploys/692648e17ce70e0007b41654
😎 Deploy Preview https://deploy-preview-2062--content-scope-scripts.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@jsoningram jsoningram changed the title Jingram/cpm stats on ntp animated jingram/cpm-stats-on-ntp-animate-count-poc: Animated tracking attempts and cookie pop-ups blocked Nov 25, 2025
@github-actions
Copy link

github-actions bot commented Nov 25, 2025

Temporary Branch Update

The temporary branch has been updated with the latest changes. Below are the details:

Please use the above install command to update to the latest version.

@github-actions
Copy link

github-actions bot commented Nov 25, 2025

[Beta] Generated file diff

Time updated: Wed, 26 Nov 2025 00:33:34 GMT

Apple
    - apple/pages/new-tab/dist/index.css
  • apple/pages/new-tab/dist/index.js

File has changed

Integration
    - integration/pages/new-tab/dist/index.css
  • integration/pages/new-tab/dist/index.js

File has changed

Windows
    - windows/pages/new-tab/dist/index.css
  • windows/pages/new-tab/dist/index.js

File has changed

@jsoningram jsoningram changed the title jingram/cpm-stats-on-ntp-animate-count-poc: Animated tracking attempts and cookie pop-ups blocked jingram/cpm-stats-on-ntp-animated: Animated Count for Protection Stats on New Tab Page Nov 25, 2025
@todo wire up real data
Balance of lint-fix fixes
Bug: Tracker Status UI: No Message for Zero Trackers.

The TrackerStatus function computes totalTrackersPillText for the
zero-trackers case but never displays it. When totalTrackersBlocked ===
0, the condition {totalTrackersBlocked > 0 && <TickPill .../>} prevents
rendering any tracker status message. The legacy TrackerStatusLegacy
displays "No trackers blocked" or "No trackers found" in this scenario,
but the new implementation shows nothing, breaking the expected UI
behavior for sites with no blocked trackers.

#2039 (comment)
Details: [integration] ›
pages/new-tab/app/protections/integrations-tests/protections.spec.js:61:5
› protections report › displays cookie popup blocking stats when enabled
and counts > 0
Apply ?cpm=true&locale=ru to see why this matters
@jsoningram jsoningram force-pushed the jingram/cpm-stats-on-ntp-animated branch from f8ef9b0 to 8f13df6 Compare November 26, 2025 00:25
@jsoningram jsoningram marked this pull request as ready for review November 26, 2025 00:32
@jsoningram jsoningram requested review from a team, mgurgel and shakyShane as code owners November 26, 2025 00:32
Copy link
Contributor

@shakyShane shakyShane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsoningram implementation looks solid 👍🏻

I'd possibly consider reducing the amount of tests, though.

Since all of the mocking is self-contained in the class (meaning the messing with globals doesn't impact other modules) I think it's ok to have these for now, but it's a lot of new code directly tied to the implementation - meaning any change to the feature carries a burden of changing the tests.

Let's scope a follow up with (or choose to do this now)

  • Have a think if you can reduce this right down to a few tests that give you confidence on the algorithm
  • Ensure end state is captured in screenshot tests

@jsoningram jsoningram added this pull request to the merge queue Nov 26, 2025
Merged via the queue into main with commit fc32fa6 Nov 26, 2025
26 checks passed
@jsoningram jsoningram deleted the jingram/cpm-stats-on-ntp-animated branch November 26, 2025 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants