diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 2da5a0d626..3d6a15c4eb 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -79,8 +79,8 @@ import {createNativeStackNavigatorWithAuth} from './view/shell/createNativeStack import {msg} from '@lingui/macro' import {i18n, MessageDescriptor} from '@lingui/core' import HashtagScreen from '#/screens/Hashtag' -import {logEvent} from './lib/statsig/statsig' import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy' +import {logEvent, attachRouteToLogEvents} from './lib/statsig/statsig' const navigationRef = createNavigationContainerRef() @@ -555,6 +555,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) { linking={LINKING} theme={theme} onReady={() => { + attachRouteToLogEvents(getCurrentRouteName) logModuleInitTime() onReady() }}> @@ -563,6 +564,10 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) { ) } +function getCurrentRouteName() { + return navigationRef.getCurrentRoute()?.name +} + /** * These helpers can be used from outside of the RoutesContainer * (eg in the state models). @@ -668,7 +673,9 @@ function logModuleInitTime() { performance.now() - global.__BUNDLE_START_TIME__, ) console.log(`Time to first paint: ${initMs} ms`) - logEvent('init', initMs) + logEvent('init', { + initMs, + }) if (__DEV__) { // This log is noisy, so keep false committed diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx index 9ffa9e7d89..1b9348d9c6 100644 --- a/src/components/Prompt.tsx +++ b/src/components/Prompt.tsx @@ -3,6 +3,7 @@ import {View} from 'react-native' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {isNative} from '#/platform/detection' import {useTheme, atoms as a, useBreakpoints} from '#/alf' import {Text} from '#/components/Typography' import {Button, ButtonColor, ButtonText} from '#/components/Button' @@ -84,7 +85,8 @@ export function Actions({children}: React.PropsWithChildren<{}>) { a.justify_end, gtMobile ? [a.flex_row, a.flex_row_reverse, a.justify_start] - : [a.flex_col, a.pt_md, a.pb_4xl], + : [a.flex_col], + isNative && [a.pb_4xl], ]}> {children} diff --git a/src/lib/media/picker.shared.ts b/src/lib/media/picker.shared.ts index 8bade34e25..96e82e4c72 100644 --- a/src/lib/media/picker.shared.ts +++ b/src/lib/media/picker.shared.ts @@ -18,11 +18,18 @@ export async function openPicker(opts?: ImagePickerOptions) { Toast.show('You may only select up to 4 images') } - return (response.assets ?? []).slice(0, 4).map(image => ({ - mime: 'image/jpeg', - height: image.height, - width: image.width, - path: image.uri, - size: getDataUriSize(image.uri), - })) + return (response.assets ?? []) + .slice(0, 4) + .filter(asset => { + if (asset.mimeType?.startsWith('image/')) return true + Toast.show('Only image files are supported') + return false + }) + .map(image => ({ + mime: 'image/jpeg', + height: image.height, + width: image.width, + path: image.uri, + size: getDataUriSize(image.uri), + })) } diff --git a/src/lib/statsig/events.ts b/src/lib/statsig/events.ts new file mode 100644 index 0000000000..bc647710ce --- /dev/null +++ b/src/lib/statsig/events.ts @@ -0,0 +1,5 @@ +export type Events = { + init: { + initMs: number + } +} diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx index 6d9ebeb099..a46cef4da0 100644 --- a/src/lib/statsig/statsig.tsx +++ b/src/lib/statsig/statsig.tsx @@ -6,6 +6,7 @@ import { } from 'statsig-react-native-expo' import {useSession} from '../../state/session' import {sha256} from 'js-sha256' +import {Events} from './events' const statsigOptions = { environment: { @@ -17,12 +18,28 @@ const statsigOptions = { initTimeoutMs: 1, } -export function logEvent( - eventName: string, - value?: string | number | null, - metadata?: Record | null, +type FlatJSONRecord = Record< + string, + string | number | boolean | null | undefined +> + +let getCurrentRouteName: () => string | null | undefined = () => null + +export function attachRouteToLogEvents( + getRouteName: () => string | null | undefined, ) { - Statsig.logEvent(eventName, value, metadata) + getCurrentRouteName = getRouteName +} + +export function logEvent( + eventName: E & string, + rawMetadata?: Events[E] & FlatJSONRecord, +) { + const fullMetadata = { + ...rawMetadata, + } as Record // Statsig typings are unnecessarily strict here. + fullMetadata.routeName = getCurrentRouteName() ?? '(Uninitialized)' + Statsig.logEvent(eventName, null, fullMetadata) } export function useGate(gateName: string) { diff --git a/src/view/com/profile/ProfileMenu.tsx b/src/view/com/profile/ProfileMenu.tsx index 4ea970a1b0..7de3494436 100644 --- a/src/view/com/profile/ProfileMenu.tsx +++ b/src/view/com/profile/ProfileMenu.tsx @@ -334,7 +334,7 @@ let ProfileMenu = ({ confirmButtonCta={ profile.viewer?.blocking ? _(msg`Unblock`) : _(msg`Block`) } - confirmButtonColor="negative" + confirmButtonColor={profile.viewer?.blocking ? undefined : 'negative'} /> )