mirror of
https://github.com/selfxyz/self.git
synced 2026-02-19 02:24:25 -05:00
SELF-773: standardize analytics imports (#1538)
* standardize analytics * format
This commit is contained in:
@@ -33,7 +33,7 @@ import { appsUrl } from '@/consts/links';
|
||||
import { useIncomingPoints, usePoints } from '@/hooks/usePoints';
|
||||
import { usePointsGuardrail } from '@/hooks/usePointsGuardrail';
|
||||
import type { RootStackParamList } from '@/navigation';
|
||||
import analytics from '@/services/analytics';
|
||||
import { trackScreenView } from '@/services/analytics';
|
||||
import {
|
||||
isTopicSubscribed,
|
||||
requestNotificationPermission,
|
||||
@@ -70,7 +70,6 @@ const Points: React.FC = () => {
|
||||
// Track NavBar view analytics
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
const { trackScreenView } = analytics();
|
||||
trackScreenView('Points NavBar', {
|
||||
screenName: 'Points NavBar',
|
||||
});
|
||||
|
||||
@@ -11,11 +11,9 @@ import { apiPingUrl } from '@/consts/links';
|
||||
import { useModal } from '@/hooks/useModal';
|
||||
import { useNetInfo } from '@/hooks/useNetInfo';
|
||||
import { navigationRef } from '@/navigation';
|
||||
import analytics from '@/services/analytics';
|
||||
import { trackEvent } from '@/services/analytics';
|
||||
import { useSettingStore } from '@/stores/settingStore';
|
||||
|
||||
const { trackEvent } = analytics();
|
||||
|
||||
const connectionModalParams = {
|
||||
titleText: 'Internet connection error',
|
||||
bodyText: 'In order to use SELF, you must have access to the internet.',
|
||||
|
||||
@@ -30,7 +30,7 @@ import sharedScreens from '@/navigation/shared';
|
||||
import verificationScreens from '@/navigation/verification';
|
||||
import type { ModalNavigationParams } from '@/screens/app/ModalScreen';
|
||||
import type { WebViewScreenParams } from '@/screens/shared/WebViewScreen';
|
||||
import analytics from '@/services/analytics';
|
||||
import { trackScreenView } from '@/services/analytics';
|
||||
import type { ProofHistory } from '@/stores/proofTypes';
|
||||
|
||||
export const navigationScreens = {
|
||||
@@ -195,7 +195,6 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
const { trackScreenView } = analytics();
|
||||
const Navigation = createStaticNavigation(AppNavigation);
|
||||
|
||||
const NavigationWithTracking = () => {
|
||||
|
||||
@@ -22,12 +22,10 @@ import {
|
||||
createKeychainOptions,
|
||||
detectSecurityCapabilities,
|
||||
} from '@/integrations/keychain';
|
||||
import analytics from '@/services/analytics';
|
||||
import { trackEvent } from '@/services/analytics';
|
||||
import { useSettingStore } from '@/stores/settingStore';
|
||||
import type { Mnemonic } from '@/types/mnemonic';
|
||||
|
||||
const { trackEvent } = analytics();
|
||||
|
||||
const SERVICE_NAME = 'secret';
|
||||
|
||||
type SignedPayload<T> = { signature: string; data: T };
|
||||
|
||||
@@ -18,11 +18,9 @@ import React, {
|
||||
|
||||
import { AuthEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
|
||||
|
||||
import analytics from '@/services/analytics';
|
||||
import { trackEvent } from '@/services/analytics';
|
||||
import type { Mnemonic } from '@/types/mnemonic';
|
||||
|
||||
const { trackEvent } = analytics();
|
||||
|
||||
type SignedPayload<T> = { signature: string; data: T };
|
||||
|
||||
// Check if Android bridge is available
|
||||
|
||||
@@ -8,9 +8,7 @@ import messaging from '@react-native-firebase/messaging';
|
||||
|
||||
import { NotificationEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
|
||||
|
||||
import analytics from '@/services/analytics';
|
||||
|
||||
const { trackEvent } = analytics();
|
||||
import { trackEvent } from '@/services/analytics';
|
||||
|
||||
export const NotificationTrackingProvider: React.FC<PropsWithChildren> = ({
|
||||
children,
|
||||
|
||||
@@ -25,7 +25,7 @@ import type { RootStackParamList } from '@/navigation';
|
||||
import { navigationRef } from '@/navigation';
|
||||
import { unsafe_getPrivateKey } from '@/providers/authProvider';
|
||||
import { selfClientDocumentsAdapter } from '@/providers/passportDataProvider';
|
||||
import analytics, { trackNfcEvent } from '@/services/analytics';
|
||||
import { trackEvent, trackNfcEvent } from '@/services/analytics';
|
||||
import { useSettingStore } from '@/stores/settingStore';
|
||||
|
||||
type GlobalCrypto = { crypto?: { subtle?: Crypto['subtle'] } };
|
||||
@@ -130,7 +130,7 @@ export const SelfClientProvider = ({ children }: PropsWithChildren) => {
|
||||
},
|
||||
analytics: {
|
||||
trackEvent: (event: string, data?: TrackEventParams) => {
|
||||
analytics().trackEvent(event, data);
|
||||
trackEvent(event, data);
|
||||
},
|
||||
trackNfcEvent: (name: string, data?: Record<string, unknown>) => {
|
||||
trackNfcEvent(name, data);
|
||||
@@ -211,21 +211,21 @@ export const SelfClientProvider = ({ children }: PropsWithChildren) => {
|
||||
|
||||
if (fcmToken) {
|
||||
try {
|
||||
analytics().trackEvent('DEVICE_TOKEN_REG_STARTED');
|
||||
trackEvent('DEVICE_TOKEN_REG_STARTED');
|
||||
logProofEvent('info', 'Device token registration started', context);
|
||||
|
||||
const { registerDeviceToken: registerFirebaseDeviceToken } =
|
||||
await import('@/services/notifications/notificationService');
|
||||
await registerFirebaseDeviceToken(uuid, fcmToken, isMock);
|
||||
|
||||
analytics().trackEvent('DEVICE_TOKEN_REG_SUCCESS');
|
||||
trackEvent('DEVICE_TOKEN_REG_SUCCESS');
|
||||
logProofEvent('info', 'Device token registration success', context);
|
||||
} catch (error) {
|
||||
logProofEvent('warn', 'Device token registration failed', context, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
console.error('Error registering device token:', error);
|
||||
analytics().trackEvent('DEVICE_TOKEN_REG_FAILED', {
|
||||
trackEvent('DEVICE_TOKEN_REG_FAILED', {
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,9 +27,7 @@ import {
|
||||
storePassportData,
|
||||
updateDocumentRegistrationState,
|
||||
} from '@/providers/passportDataProvider';
|
||||
import analytics from '@/services/analytics';
|
||||
|
||||
const { trackEvent } = analytics();
|
||||
import { trackEvent } from '@/services/analytics';
|
||||
|
||||
/**
|
||||
* This function checks and updates registration states for all documents and updates the `isRegistered`.
|
||||
|
||||
@@ -93,64 +93,41 @@ function validateParams(
|
||||
return cleanParams(validatedProps);
|
||||
}
|
||||
|
||||
/*
|
||||
Records analytics events and screen views
|
||||
In development mode, events are logged to console instead of being sent to Segment
|
||||
/**
|
||||
* Internal tracking function used by trackEvent and trackScreenView
|
||||
* Records analytics events and screen views
|
||||
* In development mode, events are logged to console instead of being sent to Segment
|
||||
*/
|
||||
const analytics = () => {
|
||||
function _track(
|
||||
type: 'event' | 'screen',
|
||||
eventName: string,
|
||||
properties?: Record<string, unknown>,
|
||||
) {
|
||||
// Validate and clean properties
|
||||
const validatedProps = validateParams(properties);
|
||||
function _track(
|
||||
type: 'event' | 'screen',
|
||||
eventName: string,
|
||||
properties?: Record<string, unknown>,
|
||||
) {
|
||||
// Validate and clean properties
|
||||
const validatedProps = validateParams(properties);
|
||||
|
||||
if (__DEV__) {
|
||||
console.log(`[DEV: Analytics ${type.toUpperCase()}]`, {
|
||||
name: eventName,
|
||||
properties: validatedProps,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!segmentClient) {
|
||||
return;
|
||||
}
|
||||
const trackMethod = (e: string, p?: JsonMap) =>
|
||||
type === 'screen'
|
||||
? segmentClient.screen(e, p)
|
||||
: segmentClient.track(e, p);
|
||||
|
||||
if (!validatedProps) {
|
||||
// you may need to remove the catch when debugging
|
||||
return trackMethod(eventName).catch(console.info);
|
||||
}
|
||||
|
||||
// you may need to remove the catch when debugging
|
||||
trackMethod(eventName, validatedProps).catch(console.info);
|
||||
if (__DEV__) {
|
||||
console.log(`[DEV: Analytics ${type.toUpperCase()}]`, {
|
||||
name: eventName,
|
||||
properties: validatedProps,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
// Using LiteralCheck will allow constants but not plain string literals
|
||||
trackEvent: (eventName: string, properties?: TrackEventParams) => {
|
||||
_track('event', eventName, properties);
|
||||
},
|
||||
trackScreenView: (
|
||||
screenName: string,
|
||||
properties?: Record<string, unknown>,
|
||||
) => {
|
||||
_track('screen', screenName, properties);
|
||||
},
|
||||
flush: () => {
|
||||
if (!__DEV__ && segmentClient) {
|
||||
segmentClient.flush();
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
if (!segmentClient) {
|
||||
return;
|
||||
}
|
||||
const trackMethod = (e: string, p?: JsonMap) =>
|
||||
type === 'screen' ? segmentClient.screen(e, p) : segmentClient.track(e, p);
|
||||
|
||||
export default analytics;
|
||||
if (!validatedProps) {
|
||||
// you may need to remove the catch when debugging
|
||||
return trackMethod(eventName).catch(console.info);
|
||||
}
|
||||
|
||||
// you may need to remove the catch when debugging
|
||||
trackMethod(eventName, validatedProps).catch(console.info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup function to clear event queues
|
||||
@@ -160,6 +137,69 @@ export const cleanupAnalytics = () => {
|
||||
eventCount = 0;
|
||||
};
|
||||
|
||||
// --- Mixpanel NFC Analytics ---
|
||||
export const configureNfcAnalytics = async () => {
|
||||
if (!MIXPANEL_NFC_PROJECT_TOKEN || mixpanelConfigured) return;
|
||||
const enableDebugLogs =
|
||||
String(ENABLE_DEBUG_LOGS ?? '')
|
||||
.trim()
|
||||
.toLowerCase() === 'true';
|
||||
|
||||
// Check if PassportReader and configure method exist (Android doesn't have configure)
|
||||
if (PassportReader && typeof PassportReader.configure === 'function') {
|
||||
try {
|
||||
// iOS configure method only accepts token and enableDebugLogs
|
||||
// Android doesn't have this method at all
|
||||
await Promise.resolve(
|
||||
PassportReader.configure(MIXPANEL_NFC_PROJECT_TOKEN, enableDebugLogs),
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn('Failed to configure NFC analytics:', error);
|
||||
}
|
||||
}
|
||||
|
||||
setupFlushPolicies();
|
||||
mixpanelConfigured = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Flush any pending analytics events immediately
|
||||
*/
|
||||
export const flush = () => {
|
||||
if (!__DEV__ && segmentClient) {
|
||||
segmentClient.flush();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Use named exports (trackEvent, trackScreenView, flush) instead
|
||||
* Factory function that returns analytics methods
|
||||
* Kept for backward compatibility
|
||||
*/
|
||||
const analytics = () => {
|
||||
return {
|
||||
trackEvent,
|
||||
trackScreenView,
|
||||
flush,
|
||||
};
|
||||
};
|
||||
|
||||
export default analytics;
|
||||
|
||||
/**
|
||||
* Consolidated analytics flush function that flushes both Segment and Mixpanel events
|
||||
* This should be called when you want to ensure all analytics events are sent immediately
|
||||
*/
|
||||
export const flushAllAnalytics = () => {
|
||||
// Flush Segment analytics
|
||||
flush();
|
||||
|
||||
// Never flush Mixpanel during active NFC scanning to prevent interference
|
||||
if (!isNfcScanningActive) {
|
||||
flushMixpanelEvents().catch(console.warn);
|
||||
}
|
||||
};
|
||||
|
||||
const setupFlushPolicies = () => {
|
||||
AppState.addEventListener('change', (state: AppStateStatus) => {
|
||||
// Never flush during active NFC scanning to prevent interference
|
||||
@@ -221,46 +261,6 @@ const flushMixpanelEvents = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// --- Mixpanel NFC Analytics ---
|
||||
export const configureNfcAnalytics = async () => {
|
||||
if (!MIXPANEL_NFC_PROJECT_TOKEN || mixpanelConfigured) return;
|
||||
const enableDebugLogs =
|
||||
String(ENABLE_DEBUG_LOGS ?? '')
|
||||
.trim()
|
||||
.toLowerCase() === 'true';
|
||||
|
||||
// Check if PassportReader and configure method exist (Android doesn't have configure)
|
||||
if (PassportReader && typeof PassportReader.configure === 'function') {
|
||||
try {
|
||||
// iOS configure method only accepts token and enableDebugLogs
|
||||
// Android doesn't have this method at all
|
||||
await Promise.resolve(
|
||||
PassportReader.configure(MIXPANEL_NFC_PROJECT_TOKEN, enableDebugLogs),
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn('Failed to configure NFC analytics:', error);
|
||||
}
|
||||
}
|
||||
|
||||
setupFlushPolicies();
|
||||
mixpanelConfigured = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Consolidated analytics flush function that flushes both Segment and Mixpanel events
|
||||
* This should be called when you want to ensure all analytics events are sent immediately
|
||||
*/
|
||||
export const flushAllAnalytics = () => {
|
||||
// Flush Segment analytics
|
||||
const { flush: flushAnalytics } = analytics();
|
||||
flushAnalytics();
|
||||
|
||||
// Never flush Mixpanel during active NFC scanning to prevent interference
|
||||
if (!isNfcScanningActive) {
|
||||
flushMixpanelEvents().catch(console.warn);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set NFC scanning state to prevent analytics flush interference
|
||||
*/
|
||||
@@ -277,6 +277,18 @@ export const setNfcScanningActive = (active: boolean) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Track an analytics event
|
||||
* @param eventName - Name of the event to track
|
||||
* @param properties - Optional properties to attach to the event
|
||||
*/
|
||||
export const trackEvent = (
|
||||
eventName: string,
|
||||
properties?: TrackEventParams,
|
||||
) => {
|
||||
_track('event', eventName, properties);
|
||||
};
|
||||
|
||||
export const trackNfcEvent = async (
|
||||
name: string,
|
||||
properties?: Record<string, unknown>,
|
||||
@@ -302,3 +314,15 @@ export const trackNfcEvent = async (
|
||||
eventQueue.push({ name, properties });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Track a screen view
|
||||
* @param screenName - Name of the screen to track
|
||||
* @param properties - Optional properties to attach to the screen view
|
||||
*/
|
||||
export const trackScreenView = (
|
||||
screenName: string,
|
||||
properties?: Record<string, unknown>,
|
||||
) => {
|
||||
_track('screen', screenName, properties);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user