diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index c576cd3a07..f9c09ee06e 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -65,6 +65,12 @@ const App = () => { }; }, []); + const showAuthenticatedApp = useMemo(() => { + return ( + isAuthenticated && !(currentlyOnboarding || finishingSelfHostedLogin) + ); + }, [isAuthenticated, currentlyOnboarding, finishingSelfHostedLogin]); + return ( {connected ? ( @@ -72,8 +78,7 @@ const App = () => { - ) : isAuthenticated && - !(currentlyOnboarding || finishingSelfHostedLogin) ? ( + ) : showAuthenticatedApp ? ( ) : ( diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index cbdfed6493..22535e52f9 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -2,12 +2,12 @@ import { useShip } from '@tloncorp/app/contexts/ship'; import { useAppStatusChange } from '@tloncorp/app/hooks/useAppStatusChange'; import { useConfigureUrbitClient } from '@tloncorp/app/hooks/useConfigureUrbitClient'; import { useCurrentUserId } from '@tloncorp/app/hooks/useCurrentUser'; +import { useNavigationLogging } from '@tloncorp/app/hooks/useNavigationLogger'; +import { useNetworkLogger } from '@tloncorp/app/hooks/useNetworkLogger'; import { useInitializeUserTelemetry, useTrackAppActive, -} from '@tloncorp/app/hooks/useInitializeTelemetry'; -import { useNavigationLogging } from '@tloncorp/app/hooks/useNavigationLogger'; -import { useNetworkLogger } from '@tloncorp/app/hooks/useNetworkLogger'; +} from '@tloncorp/app/hooks/useTelemetryHelpers'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; import { sync } from '@tloncorp/shared'; diff --git a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx index 1ca91477d6..162ac60d41 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx @@ -64,6 +64,7 @@ export const ShipLoginScreen = ({ navigation }: Props) => { const [codevisible, setCodeVisible] = useState(false); const isValidUrl = useCallback((url: string) => { + return true; const urlPattern = /^(https?:\/\/)?(localhost|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|[\w.-]+\.([a-z]{2,}))(:\d+)?$/i; const hostedPattern = /tlon\.network/i; @@ -96,6 +97,13 @@ export const ShipLoginScreen = ({ navigation }: Props) => { if (authCookie) { await setFinishingSelfHostedLogin(true); const shipId = getShipFromCookie(authCookie); + + navigation.navigate('SetTelemetry'); + + // Delay to allow the transition to telemetry screen via Onboarding navigator to complete + // before setting auth and potentially triggering a re-render of app.main (which might change nav prop to Root navigator) + await new Promise((resolve) => setTimeout(resolve, 100)); + setShip({ ship: shipId, shipUrl, @@ -107,8 +115,6 @@ export const ShipLoginScreen = ({ navigation }: Props) => { if (!hasSignedUp) { logger.trackEvent(AnalyticsEvent.LoggedInBeforeSignup); } - - navigation.navigate('SetTelemetry'); } else { setRemoteError( "Sorry, we couldn't log in to your ship. It may be busy or offline." diff --git a/packages/app/features/settings/AppInfoScreen.tsx b/packages/app/features/settings/AppInfoScreen.tsx index 216d2e1e15..790a10cda5 100644 --- a/packages/app/features/settings/AppInfoScreen.tsx +++ b/packages/app/features/settings/AppInfoScreen.tsx @@ -23,7 +23,7 @@ import { getEmailClients, openComposer } from 'react-native-email-link'; import { ScrollView } from 'react-native-gesture-handler'; import { NOTIFY_PROVIDER, NOTIFY_SERVICE } from '../../constants'; -import { useTelemetryDisabler } from '../../hooks/useInitializeTelemetry'; +import { useTelemetryDisabler } from '../../hooks/useTelemetryHelpers'; import { setDebug } from '../../lib/debug'; import { getEasUpdateDisplay } from '../../lib/platformHelpers'; import { RootStackParamList } from '../../navigation/types'; @@ -185,25 +185,23 @@ export function AppInfoScreen(props: Props) { )} - {telemetry.canDisable && ( - - - Share Usage Statistics - - - - By sharing, you help us improve the app for everyone. - - - )} + + + Share Usage Statistics + + + + By sharing, you help us improve the app for everyone. + + diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index 9eab438345..3be7e524f9 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -110,7 +110,7 @@ export function useBootSequence({ authCookie: auth.authCookie, authType: 'hosted', }); - telemetry?.identify(preSig(auth.nodeId)); + telemetry?.identify(preSig(auth.nodeId), { isHostedUser: true }); await wait(2000); diff --git a/packages/app/hooks/useHandleLogout.native.ts b/packages/app/hooks/useHandleLogout.native.ts index 7f1a24fdbe..cf3ae976da 100644 --- a/packages/app/hooks/useHandleLogout.native.ts +++ b/packages/app/hooks/useHandleLogout.native.ts @@ -1,6 +1,6 @@ import { createDevLogger } from '@tloncorp/shared'; import * as api from '@tloncorp/shared/api'; -import { didInitializeTelemetry } from '@tloncorp/shared/db'; +import { finishingSelfHostedLogin } from '@tloncorp/shared/db'; import * as store from '@tloncorp/shared/store'; import { useCallback } from 'react'; @@ -8,14 +8,14 @@ import { useBranch } from '../contexts/branch'; import { clearShipInfo, useShip } from '../contexts/ship'; import { removeHostingToken, removeHostingUserId } from '../utils/hosting'; import { clearSplashDismissed } from '../utils/splash'; -import { useTelemetry } from './useTelemetry'; +import { useClearTelemetryConfig } from './useTelemetryHelpers'; const logger = createDevLogger('logout', true); export function useHandleLogout({ resetDb }: { resetDb: () => void }) { const { clearShip } = useShip(); const { clearLure, clearDeepLink } = useBranch(); - const telemetry = useTelemetry(); + const resetTelemetry = useClearTelemetryConfig(); const handleLogout = useCallback(async () => { api.queryClient.clear(); @@ -27,15 +27,15 @@ export function useHandleLogout({ resetDb }: { resetDb: () => void }) { clearLure(); clearDeepLink(); clearSplashDismissed(); - telemetry?.reset(); - didInitializeTelemetry.resetValue(); + resetTelemetry(); + finishingSelfHostedLogin.resetValue(); if (!resetDb) { logger.trackError('could not reset db on logout'); return; } // delay DB reset to next tick to avoid race conditions setTimeout(() => resetDb()); - }, [clearDeepLink, clearLure, clearShip, resetDb, telemetry]); + }, [clearDeepLink, clearLure, clearShip, resetDb, resetTelemetry]); return handleLogout; } diff --git a/packages/app/hooks/useTelemetry.native.ts b/packages/app/hooks/useTelemetry.native.ts index 9555f40d92..9d6e521335 100644 --- a/packages/app/hooks/useTelemetry.native.ts +++ b/packages/app/hooks/useTelemetry.native.ts @@ -7,7 +7,6 @@ export function useTelemetry(): TelemetryClient { const posthog = useNativePosthog(); const optedOut = useMemo(() => { - console.log(`posthog opted out recalc`, posthog?.optedOut); return posthog?.optedOut ?? false; }, [posthog]); @@ -20,8 +19,8 @@ export function useTelemetry(): TelemetryClient { }, [posthog]); const identify = useCallback( - (userId: string) => { - return posthog?.identify(userId); + (userId: string, properties: Record) => { + return posthog?.identify(userId, properties); }, [posthog] ); diff --git a/packages/app/hooks/useTelemetry.ts b/packages/app/hooks/useTelemetry.ts index 113758455b..c3c9a2f5f9 100644 --- a/packages/app/hooks/useTelemetry.ts +++ b/packages/app/hooks/useTelemetry.ts @@ -19,8 +19,8 @@ export function useTelemetry(): TelemetryClient { }, [posthog]); const identify = useCallback( - (userId: string) => { - return posthog?.identify(userId); + (userId: string, properties?: Record) => { + return posthog?.identify(userId, properties); }, [posthog] ); diff --git a/packages/app/hooks/useInitializeTelemetry.ts b/packages/app/hooks/useTelemetryHelpers.ts similarity index 87% rename from packages/app/hooks/useInitializeTelemetry.ts rename to packages/app/hooks/useTelemetryHelpers.ts index fd05ed8b77..ac50356e93 100644 --- a/packages/app/hooks/useInitializeTelemetry.ts +++ b/packages/app/hooks/useTelemetryHelpers.ts @@ -9,6 +9,19 @@ import { useShip } from '../contexts/ship'; import { useCurrentUserId } from './useCurrentUser.native'; import { useTelemetry } from './useTelemetry'; +export function useClearTelemetryConfig() { + const telemetry = useTelemetry(); + + const clearTelemetryConfig = useCallback(async () => { + await telemetry.flush(); + telemetry?.reset(); + didInitializeTelemetry.resetValue(); + lastAnonymousAppOpenAt.resetValue(); + }, [telemetry]); + + return clearTelemetryConfig; +} + export function useIsHosted() { const ship = useShip(); // We use different heuristics for determining whether a user is hosted across the app. @@ -42,7 +55,7 @@ export function useSetTelemetryDisabled(methodId?: string) { async (shouldDisable: boolean) => { if (shouldDisable) { telemetry?.optIn(); - telemetry?.capture('Telemetry opt out', { + telemetry?.capture('Telemetry disabled', { isHostedUser, detectionMethod: methodId ?? 'useSetTelemetryDisabled', }); @@ -52,8 +65,9 @@ export function useSetTelemetryDisabled(methodId?: string) { } else { telemetry?.optIn(); if (isHosted) { - telemetry?.identify(currentUserId); + telemetry?.identify(currentUserId, { ishostedUser: true }); } + telemetry?.capture('Telemetry enabled', { isHostedUser }); } }, [currentUserId, isHosted, isHostedUser, methodId, telemetry] @@ -72,7 +86,7 @@ export function useInitializeUserTelemetry() { useEffect(() => { async function initializeTelemetry() { if (isHosted) { - telemetry?.identify(currentUserId); + telemetry?.identify(currentUserId, { isHostedUser: true }); } if (telemetry?.optedOut) { diff --git a/packages/app/types/telemetry.ts b/packages/app/types/telemetry.ts index 6d82ca6e46..ba33f445ab 100644 --- a/packages/app/types/telemetry.ts +++ b/packages/app/types/telemetry.ts @@ -2,7 +2,7 @@ export interface TelemetryClient { optedOut: boolean; optIn: () => void; optOut: () => void; - identify: (userId: string) => void; + identify: (userId: string, properties?: Record) => void; capture: (eventName: string, properties?: Record) => void; flush: () => Promise; reset: () => void; diff --git a/packages/shared/src/db/keyValue.ts b/packages/shared/src/db/keyValue.ts index 4fc3bc6818..131bde2a08 100644 --- a/packages/shared/src/db/keyValue.ts +++ b/packages/shared/src/db/keyValue.ts @@ -301,12 +301,12 @@ export const didInitializeTelemetry = createStorageItem({ defaultValue: false, }); -export const finishingSelfHostedLogin = createStorageItem({ - key: 'finishingSelfHostedLogin', - defaultValue: false, -}); - export const lastAnonymousAppOpenAt = createStorageItem({ key: 'lastAnonymousAppOpenAt', defaultValue: null, }); + +export const finishingSelfHostedLogin = createStorageItem({ + key: 'finishingSelfHostedLogin', + defaultValue: false, +});