Skip to content

Commit d40f797

Browse files
authored
Increase tracker and cookie pop-up counter capacity (#2083)
* Increase capacity of counter and localize result * CSS changes to support max count
1 parent 654dbb5 commit d40f797

File tree

5 files changed

+37
-14
lines changed

5 files changed

+37
-14
lines changed

special-pages/pages/new-tab/app/privacy-stats/components/PrivacyStats.module.css

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,24 @@
6565

6666
.counterContainer {
6767
display: flex;
68-
gap: 24px;
68+
gap: 12px;
6969
}
7070

7171
.counter {
7272
display: flex;
7373
flex-direction: column;
7474
gap: 4px;
75-
padding-right: 38px;
75+
width: 196px;
76+
padding-right: 18px;
77+
box-sizing: content-box;
78+
79+
&:last-child {
80+
padding-right: 0;
81+
}
82+
}
83+
84+
.cookiePopUpsCounter {
85+
margin-left: 14px;
7686
}
7787

7888
.title {
@@ -89,6 +99,8 @@
8999
line-height: 20px;
90100
padding-bottom: 4px;
91101
padding-top: 12px;
102+
word-wrap: break-word;
103+
overflow-wrap: break-word;
92104
}
93105
}
94106

special-pages/pages/new-tab/app/protections/components/ProtectionsHeading.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import { InfoIcon } from '../../components/Icons.js';
77
import { NewBadge } from '../../components/NewBadge.js';
88
import { Tooltip } from '../../components/Tooltip/Tooltip.js';
99
import { useAnimatedCount } from '../utils/useAnimatedCount.js';
10-
import { useRef, useEffect } from 'preact/hooks';
10+
import { useRef, useEffect, useMemo } from 'preact/hooks';
11+
import { getLocalizedNumberFormatter } from '../../../../../shared/utils.js';
12+
import { useLocale } from '../../../../../shared/components/EnvironmentProvider.js';
1113

1214
/**
1315
* @import enStrings from "../strings.json"
@@ -32,6 +34,8 @@ export function ProtectionsHeading({
3234
}) {
3335
const { t } = useTypedTranslationWith(/** @type {Strings} */ ({}));
3436
const ntp = useMessaging();
37+
const locale = useLocale();
38+
const formatter = useMemo(() => getLocalizedNumberFormatter(locale), [locale]);
3539
const headingRef = useRef(/** @type {HTMLDivElement|null} */ (null));
3640
const counterContainerRef = useRef(/** @type {HTMLDivElement|null} */ (null));
3741
const totalTrackersBlocked = blockedCountSignal.value;
@@ -97,7 +101,7 @@ export function ProtectionsHeading({
97101
{animatedTrackersBlocked === 0 && <h3 class={styles.noRecentTitle}>{t('protections_noRecent')}</h3>}
98102
{animatedTrackersBlocked > 0 && (
99103
<h3 class={styles.title}>
100-
{animatedTrackersBlocked} <span>{trackersBlockedHeading}</span>
104+
{formatter.format(animatedTrackersBlocked)} <span>{trackersBlockedHeading}</span>
101105
</h3>
102106
)}
103107
</div>
@@ -107,9 +111,9 @@ export function ProtectionsHeading({
107111
enabled AND both `animatedTrackersBlocked` and
108112
`totalCookiePopUpsBlocked` are at least 1 */}
109113
{isCpmEnabled && animatedTrackersBlocked > 0 && totalCookiePopUpsBlocked > 0 && (
110-
<div class={styles.counter}>
114+
<div class={cn(styles.counter, styles.cookiePopUpsCounter)}>
111115
<h3 class={styles.title}>
112-
{animatedCookiePopUpsBlocked} <span>{cookiePopUpsBlockedHeading}</span>
116+
{formatter.format(animatedCookiePopUpsBlocked)} <span>{cookiePopUpsBlockedHeading}</span>
113117
</h3>
114118
{/* @todo `NewBadge` will be manually removed in
115119
a future iteration */}

special-pages/pages/new-tab/app/protections/mocks/protections.mock-transport.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { TestTransportConfig } from '@duckduckgo/messaging';
22
import { protectionsMocks } from './protections.mocks.js';
3+
import { AnimationConstants } from '../utils/animateCount.js';
34

45
const url = typeof window !== 'undefined' ? new URL(window.location.href) : new URL('https://example.com');
56

@@ -99,7 +100,12 @@ export function protectionsMockTransport() {
99100
dataset.totalCookiePopUpsBlocked = undefined;
100101

101102
if (url.searchParams.get('cpm') === 'true') {
102-
dataset.totalCookiePopUpsBlocked = 1222;
103+
dataset.totalCookiePopUpsBlocked = AnimationConstants.MAX_DISPLAY_COUNT;
104+
}
105+
106+
if (url.searchParams.get('cpm') === 'max') {
107+
dataset.totalCount = AnimationConstants.MAX_DISPLAY_COUNT;
108+
dataset.totalCookiePopUpsBlocked = AnimationConstants.MAX_DISPLAY_COUNT;
103109
}
104110

105111
// CPM = 0 state

special-pages/pages/new-tab/app/protections/unit-tests/animateCount.spec.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { equal, ok, deepEqual } from 'node:assert/strict';
22
import { test } from 'node:test';
3-
import { animateCount } from '../utils/animateCount.js';
3+
import { animateCount, AnimationConstants } from '../utils/animateCount.js';
44

55
/**
66
* Focused test suite for animateCount utility function
@@ -140,6 +140,7 @@ class AnimationMocker {
140140

141141
test.describe('animateCount - Core Algorithm', () => {
142142
test('should respect threshold boundaries and percentage-based start values', (t) => {
143+
const { MAX_DISPLAY_COUNT } = AnimationConstants;
143144
const mocker = new AnimationMocker();
144145
mocker.setup();
145146
t.after(() => mocker.cleanup());
@@ -175,13 +176,13 @@ test.describe('animateCount - Core Algorithm', () => {
175176
equal(updates39[0], 29); // Math.floor(39 * 0.75) = 29
176177
equal(updates40[0], 34); // Math.floor(40 * 0.85) = 34
177178

178-
// Test capping at 9999
179+
// Test capping at MAX_DISPLAY_COUNT
179180
const updatesCapped = [];
180-
animateCount(15000, (v) => updatesCapped.push(v));
181+
animateCount(MAX_DISPLAY_COUNT + 1, (v) => updatesCapped.push(v));
181182
mocker.tick(1);
182-
equal(updatesCapped[0], 8499); // Math.floor(9999 * 0.85) = 8499
183+
equal(updatesCapped[0], Math.floor(MAX_DISPLAY_COUNT * 0.85));
183184
mocker.runToCompletion(500, 10);
184-
equal(updatesCapped[updatesCapped.length - 1], 9999);
185+
equal(updatesCapped[updatesCapped.length - 1], MAX_DISPLAY_COUNT);
185186
});
186187

187188
test('should handle incremental updates and edge cases', (t) => {

special-pages/pages/new-tab/app/protections/utils/animateCount.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const AnimationConstants = {
1515
UPPER_THRESHOLD: 40,
1616
LOWER_START_PERCENTAGE: 0.75,
1717
UPPER_START_PERCENTAGE: 0.85,
18-
MAX_DISPLAY_COUNT: 9999,
18+
MAX_DISPLAY_COUNT: 9999999,
1919
};
2020

2121
/**
@@ -61,7 +61,7 @@ export function animateCount(targetValue, onUpdate, onComplete, fromValue = null
6161
MAX_DISPLAY_COUNT,
6262
} = AnimationConstants;
6363

64-
// Cap the target value at 9999
64+
// Cap the target value at MAX_DISPLAY_COUNT
6565
const cappedTarget = Math.min(targetValue, MAX_DISPLAY_COUNT);
6666
const isInitialDisplay = fromValue === null || fromValue === 0;
6767

0 commit comments

Comments
 (0)