What is this about?
This issue tracks the migration from the existing useMetrics hook and withMetricsAwareness HOC to a new useAnalytics hook and withAnalyticsAwareness HOC that directly uses the analytics utility from app/util/analytics/analytics instead of going through the MetaMetrics layer.
Objectives
-
Create new useAnalytics hook - Build a new hook in app/components/hooks/useAnalytics that:
- Uses
analytics from app/util/analytics/analytics as the underlying implementation
- Maintains the same API interface as
useMetrics for backward compatibility
- Provides all the same methods:
trackEvent, createEventBuilder, enable, addTraitsToUser, isEnabled, getMetaMetricsId, and data deletion methods
-
Create withAnalyticsAwareness HOC - Build a new Higher-Order Component in app/components/hooks/useAnalytics that:
- Follows the same pattern as
withMetricsAwareness
- Injects the
useAnalytics hook into component props
- Maintains the same prop interface for compatibility
-
Deprecate existing implementations - Mark useMetrics and withMetricsAwareness as deprecated:
- Add
@deprecated JSDoc tags to both exports
- Add deprecation notices in code comments
- Update documentation to indicate the migration path
Scenario
No response
Design
No response
Technical Details
Implementation Details
- Hook Location:
app/components/hooks/useAnalytics/useAnalytics.ts
- HOC Location:
app/components/hooks/useAnalytics/withAnalyticsAwareness.tsx
- Underlying Implementation: Uses
analytics utility from app/util/analytics/analytics instead of MetaMetrics singleton
- Event Builder: Uses
AnalyticsEventBuilder from app/util/analytics/AnalyticsEventBuilder for event construction
- API Compatibility: Maintains exact same interface as
useMetrics hook (IUseMetricsHook)
Key Implementation Points
-
Hook Implementation:
- Use
useMemo to memoize the hook return value (same pattern as useMetrics)
- Delegate
trackEvent to analytics.trackEvent with proper event conversion
- Delegate
enable to analytics.optIn/analytics.optOut
- Delegate
addTraitsToUser to analytics.identify
- Delegate
isEnabled to analytics.isEnabled
- Delegate
getMetaMetricsId to analytics.getAnalyticsId
- For data deletion methods, continue delegating to
MetaMetrics.getInstance() until fully migrated
-
HOC Implementation:
- Follow same pattern as
withMetricsAwareness
- Use TypeScript generics to ensure prop type safety
- Inject
useAnalytics() result as analytics prop
-
Deprecation:
- Add
@deprecated JSDoc tags to useMetrics and withMetricsAwareness
- Add deprecation notices in code comments
- Update exports to indicate migration path
Global Test Mock
Create a global mock for useAnalytics in app/util/test/testSetup.js so developers don't need to mock it in each test file. The mock should:
Allow individual tests to override specific methods using jest.mocked(useAnalytics).mockReturnValue() when needed
Files to Create:
- app/components/hooks/useAnalytics/useAnalytics.ts
- app/components/hooks/useAnalytics/useAnalytics.types.ts
- app/components/hooks/useAnalytics/withAnalyticsAwareness.tsx
- app/components/hooks/useAnalytics/withAnalyticsAwareness.types.ts
- app/components/hooks/useAnalytics/index.ts
- app/components/hooks/useAnalytics/useAnalytics.test.tsx
- app/components/hooks/useAnalytics/withAnalyticsAwareness.test.tsx
Files to Update:
- app/components/hooks/useMetrics/useMetrics.ts - Add @deprecated tag
- app/components/hooks/useMetrics/withMetricsAwareness.tsx - Add @deprecated tag
- app/components/hooks/useMetrics/index.ts - Add deprecation notices
- app/util/test/testSetup.js - Add global mock for useAnalytics
Threat Modeling Framework
-
What are we working on? Creating a new useAnalytics hook and withAnalyticsAwareness HOC that directly use the analytics utility instead of the MetaMetrics singleton, reducing legacy coupling.
-
What can go wrong? Hook not implementing same features as the original useMetrics.
-
What are we going to do about it? Ensure full TypeScript coverage with strict types, maintain exact API parity with useMetrics, use useMemo for proper memoization, add runtime validation for hook usage, use TypeScript generics for HOC prop safety, delegate all methods correctly to analytics utility, provide a proper global mock for the hook so devs don't have to implement it in their tests each time, and achieve comprehensive test coverage comparing behavior with useMetrics.
-
Did we do a good job? Success criteria: 100% API compatibility verified through side-by-side testing, full TypeScript coverage with no any types, >90% test coverage, no runtime errors, proper memoization preventing unnecessary re-renders, global mock available for easy test setup, and clear deprecation notices; validated through TypeScript compilation, automated test suite, and migration testing.
Acceptance Criteria
Stakeholder review needed before the work gets merged
References
app/core/Analytics/README.md - Analytics module documentation
app/components/hooks/useMetrics/useMetrics.ts - Current implementation reference
app/components/hooks/useMetrics/withMetricsAwareness.tsx - Current HOC pattern
app/util/analytics/analytics.ts - Target analytics utility
app/util/analytics/AnalyticsEventBuilder.ts - Event builder utility
app/components/hooks/useMetrics/useMetrics.types.ts - Type definitions
app/util/test/testSetup.js - Global test mocks location
.cursor/rules/unit-testing-guidelines.mdc - Unit testing standards
.cursor/rules/component-view-testing.mdc - Component testing patterns
What is this about?
This issue tracks the migration from the existing
useMetricshook andwithMetricsAwarenessHOC to a newuseAnalyticshook andwithAnalyticsAwarenessHOC that directly uses the analytics utility fromapp/util/analytics/analyticsinstead of going through the MetaMetrics layer.Objectives
Create new
useAnalyticshook - Build a new hook inapp/components/hooks/useAnalyticsthat:analyticsfromapp/util/analytics/analyticsas the underlying implementationuseMetricsfor backward compatibilitytrackEvent,createEventBuilder,enable,addTraitsToUser,isEnabled,getMetaMetricsId, and data deletion methodsCreate
withAnalyticsAwarenessHOC - Build a new Higher-Order Component inapp/components/hooks/useAnalyticsthat:withMetricsAwarenessuseAnalyticshook into component propsDeprecate existing implementations - Mark
useMetricsandwithMetricsAwarenessas deprecated:@deprecatedJSDoc tags to both exportsScenario
No response
Design
No response
Technical Details
Implementation Details
app/components/hooks/useAnalytics/useAnalytics.tsapp/components/hooks/useAnalytics/withAnalyticsAwareness.tsxanalyticsutility fromapp/util/analytics/analyticsinstead of MetaMetrics singletonAnalyticsEventBuilderfromapp/util/analytics/AnalyticsEventBuilderfor event constructionuseMetricshook (IUseMetricsHook)Key Implementation Points
Hook Implementation:
useMemoto memoize the hook return value (same pattern asuseMetrics)trackEventtoanalytics.trackEventwith proper event conversionenabletoanalytics.optIn/analytics.optOutaddTraitsToUsertoanalytics.identifyisEnabledtoanalytics.isEnabledgetMetaMetricsIdtoanalytics.getAnalyticsIdMetaMetrics.getInstance()until fully migratedHOC Implementation:
withMetricsAwarenessuseAnalytics()result asanalyticspropDeprecation:
@deprecatedJSDoc tags touseMetricsandwithMetricsAwarenessGlobal Test Mock
Create a global mock for
useAnalyticsinapp/util/test/testSetup.jsso developers don't need to mock it in each test file. The mock should:Provide all methods from
IUseMetricsHookinterface with sensible defaults:trackEvent: jest.fn()createEventBuilder: jest.fn() returning a builder withaddProperties,addSensitiveProperties,buildmethodsisEnabled: jest.fn().mockReturnValue(true)enable: jest.fn().mockResolvedValue(undefined)addTraitsToUser: jest.fn().mockResolvedValue(undefined)createDataDeletionTask: jest.fn().mockResolvedValue({ regulationId: 'mock-id' })checkDataDeleteStatus: jest.fn().mockResolvedValue({ status: 'pending' })getDeleteRegulationCreationDate: jest.fn().mockReturnValue(new Date())getDeleteRegulationId: jest.fn().mockReturnValue('mock-regulation-id')isDataRecorded: jest.fn().mockReturnValue(true)getMetaMetricsId: jest.fn().mockResolvedValue('mock-analytics-id')Mock both the hook and HOC exports:
Allow individual tests to override specific methods using
jest.mocked(useAnalytics).mockReturnValue()when neededFiles to Create:
Files to Update:
Threat Modeling Framework
What are we working on? Creating a new
useAnalyticshook andwithAnalyticsAwarenessHOC that directly use the analytics utility instead of the MetaMetrics singleton, reducing legacy coupling.What can go wrong? Hook not implementing same features as the original useMetrics.
What are we going to do about it? Ensure full TypeScript coverage with strict types, maintain exact API parity with
useMetrics, useuseMemofor proper memoization, add runtime validation for hook usage, use TypeScript generics for HOC prop safety, delegate all methods correctly to analytics utility, provide a proper global mock for the hook so devs don't have to implement it in their tests each time, and achieve comprehensive test coverage comparing behavior withuseMetrics.Did we do a good job? Success criteria: 100% API compatibility verified through side-by-side testing, full TypeScript coverage with no
anytypes, >90% test coverage, no runtime errors, proper memoization preventing unnecessary re-renders, global mock available for easy test setup, and clear deprecation notices; validated through TypeScript compilation, automated test suite, and migration testing.Acceptance Criteria
useAnalyticshook created with full test coveragewithAnalyticsAwarenessHOC created with full test coverageuseMetricsandwithMetricsAwarenessmarked as deprecated with appropriate JSDoc tagsStakeholder review needed before the work gets merged
References
app/core/Analytics/README.md- Analytics module documentationapp/components/hooks/useMetrics/useMetrics.ts- Current implementation referenceapp/components/hooks/useMetrics/withMetricsAwareness.tsx- Current HOC patternapp/util/analytics/analytics.ts- Target analytics utilityapp/util/analytics/AnalyticsEventBuilder.ts- Event builder utilityapp/components/hooks/useMetrics/useMetrics.types.ts- Type definitionsapp/util/test/testSetup.js- Global test mocks location.cursor/rules/unit-testing-guidelines.mdc- Unit testing standards.cursor/rules/component-view-testing.mdc- Component testing patterns