Adds more tracking all around the app (#142)
* Adds more tracking all around the app * more events * lint * using better analytics naming * missed file * more fixes
This commit is contained in:
+3
-12
@@ -6,17 +6,14 @@ import {GestureHandlerRootView} from 'react-native-gesture-handler'
|
||||
import SplashScreen from 'react-native-splash-screen'
|
||||
import {SafeAreaProvider} from 'react-native-safe-area-context'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {
|
||||
createClient,
|
||||
SegmentClient,
|
||||
AnalyticsProvider,
|
||||
} from '@segment/analytics-react-native'
|
||||
import {SegmentClient, AnalyticsProvider} from '@segment/analytics-react-native'
|
||||
import {ThemeProvider} from './view/lib/ThemeContext'
|
||||
import * as view from './view/index'
|
||||
import {RootStoreModel, setupState, RootStoreProvider} from './state'
|
||||
import {MobileShell} from './view/shell/mobile'
|
||||
import {s} from './view/lib/styles'
|
||||
import notifee, {EventType} from '@notifee/react-native'
|
||||
import {segmentClient} from './lib/segmentClient'
|
||||
|
||||
const App = observer(() => {
|
||||
const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
|
||||
@@ -27,12 +24,7 @@ const App = observer(() => {
|
||||
// init
|
||||
useEffect(() => {
|
||||
view.setup()
|
||||
setSegment(
|
||||
createClient({
|
||||
writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI',
|
||||
trackAppLifecycleEvents: true,
|
||||
}),
|
||||
)
|
||||
setSegment(segmentClient)
|
||||
setupState().then(store => {
|
||||
setRootStore(store)
|
||||
SplashScreen.hide()
|
||||
@@ -58,7 +50,6 @@ const App = observer(() => {
|
||||
if (!rootStore) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<GestureHandlerRootView style={s.h100pct}>
|
||||
<ThemeProvider theme={rootStore.shell.darkMode ? 'dark' : 'light'}>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
export class Logger {
|
||||
isDisabled: boolean
|
||||
|
||||
constructor(isDisabled: boolean = process.env.NODE_ENV === 'production') {
|
||||
this.isDisabled = isDisabled
|
||||
}
|
||||
|
||||
enable() {
|
||||
this.isDisabled = false
|
||||
}
|
||||
|
||||
disable() {
|
||||
this.isDisabled = true
|
||||
}
|
||||
|
||||
info(message?: any, ...optionalParams: any[]): void {
|
||||
if (!this.isDisabled) {
|
||||
console.info(message, ...optionalParams)
|
||||
}
|
||||
}
|
||||
|
||||
warn(message?: any, ...optionalParams: any[]): void {
|
||||
if (!this.isDisabled) {
|
||||
console.warn(message, ...optionalParams)
|
||||
}
|
||||
}
|
||||
|
||||
error(message?: any, ...optionalParams: any[]): void {
|
||||
if (!this.isDisabled) {
|
||||
console.error(message, ...optionalParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createLogger = (isDisabled?: boolean) => new Logger(isDisabled)
|
||||
@@ -0,0 +1,9 @@
|
||||
import {createClient} from '@segment/analytics-react-native'
|
||||
// import {createLogger} from './logger'
|
||||
|
||||
export const segmentClient = createClient({
|
||||
writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI',
|
||||
trackAppLifecycleEvents: true,
|
||||
// Uncomment to debug:
|
||||
// logger: createLogger(),
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import {makeAutoObservable} from 'mobx'
|
||||
import {TABS_ENABLED} from '../../build-flags'
|
||||
import {segmentClient} from '../../lib/segmentClient'
|
||||
|
||||
let __id = 0
|
||||
function genId() {
|
||||
@@ -96,6 +97,13 @@ export class NavigationTabModel {
|
||||
// =
|
||||
|
||||
navigate(url: string, title?: string) {
|
||||
try {
|
||||
const path = url.split('/')[1]
|
||||
segmentClient.track('Navigation', {
|
||||
path,
|
||||
})
|
||||
} catch (error) {}
|
||||
|
||||
if (this.current?.url === url) {
|
||||
this.refresh()
|
||||
} else {
|
||||
|
||||
@@ -68,7 +68,7 @@ export const ComposePost = observer(function ComposePost({
|
||||
onPost?: ComposerOpts['onPost']
|
||||
onClose: () => void
|
||||
}) {
|
||||
const {track} = useAnalytics()
|
||||
const {track, screen} = useAnalytics()
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const textInput = useRef<PasteInputRef>(null)
|
||||
@@ -88,6 +88,10 @@ export const ComposePost = observer(function ComposePost({
|
||||
)
|
||||
const [selectedPhotos, setSelectedPhotos] = useState<string[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
screen('ComposePost')
|
||||
}, [screen])
|
||||
|
||||
// Using default import (React.use...) instead of named import (use...) to be able to mock store's data in jest environment
|
||||
const autocompleteView = React.useMemo<UserAutocompleteViewModel>(
|
||||
() => new UserAutocompleteViewModel(store),
|
||||
@@ -183,6 +187,7 @@ export const ComposePost = observer(function ComposePost({
|
||||
textInput.current?.focus()
|
||||
}
|
||||
const onPressSelectPhotos = () => {
|
||||
track('ComposePost:SelectPhotos')
|
||||
if (isSelectingPhotos) {
|
||||
setIsSelectingPhotos(false)
|
||||
} else if (selectedPhotos.length < 4) {
|
||||
@@ -190,6 +195,7 @@ export const ComposePost = observer(function ComposePost({
|
||||
}
|
||||
}
|
||||
const onSelectPhotos = (photos: string[]) => {
|
||||
track('ComposePost:SelectPhotos:Done')
|
||||
setSelectedPhotos(photos)
|
||||
if (photos.length >= 4) {
|
||||
setIsSelectingPhotos(false)
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
import {compressIfNeeded, scaleDownDimensions} from '../../../lib/images'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {useStores} from '../../../state'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
const MAX_WIDTH = 2000
|
||||
const MAX_HEIGHT = 2000
|
||||
@@ -75,6 +76,7 @@ export const PhotoCarouselPicker = ({
|
||||
selectedPhotos: string[]
|
||||
onSelectPhotos: (v: string[]) => void
|
||||
}) => {
|
||||
const {track} = useAnalytics()
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const [isSetup, setIsSetup] = React.useState<boolean>(false)
|
||||
@@ -111,6 +113,7 @@ export const PhotoCarouselPicker = ({
|
||||
|
||||
const handleSelectPhoto = useCallback(
|
||||
async (item: PhotoIdentifier) => {
|
||||
track('PhotoCarouselPicker:PhotoSelected')
|
||||
try {
|
||||
const imgPath = await cropPhoto(
|
||||
item.node.image.uri,
|
||||
@@ -123,10 +126,11 @@ export const PhotoCarouselPicker = ({
|
||||
store.log.warn('Error selecting photo', err)
|
||||
}
|
||||
},
|
||||
[store.log, selectedPhotos, onSelectPhotos],
|
||||
[track, onSelectPhotos, selectedPhotos, store.log],
|
||||
)
|
||||
|
||||
const handleOpenGallery = useCallback(async () => {
|
||||
track('PhotoCarouselPicker:GalleryOpened')
|
||||
if (!(await requestPhotoAccessIfNeeded())) {
|
||||
return
|
||||
}
|
||||
@@ -156,7 +160,7 @@ export const PhotoCarouselPicker = ({
|
||||
result.push(permanentPath)
|
||||
}
|
||||
onSelectPhotos([...selectedPhotos, ...result])
|
||||
}, [selectedPhotos, onSelectPhotos])
|
||||
}, [track, selectedPhotos, onSelectPhotos])
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
|
||||
@@ -29,7 +29,7 @@ import {ServerInputModal} from '../../../state/models/shell-ui'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
|
||||
export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
const {track} = useAnalytics()
|
||||
const {track, screen} = useAnalytics()
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||
@@ -46,6 +46,10 @@ export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
const [handle, setHandle] = useState<string>('')
|
||||
const [is13, setIs13] = useState<boolean>(false)
|
||||
|
||||
useEffect(() => {
|
||||
screen('CreateAccount')
|
||||
}, [screen])
|
||||
|
||||
useEffect(() => {
|
||||
let aborted = false
|
||||
setError('')
|
||||
|
||||
@@ -35,6 +35,7 @@ enum Forms {
|
||||
export const Signin = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {track} = useAnalytics()
|
||||
const [error, setError] = useState<string>('')
|
||||
const [retryDescribeTrigger, setRetryDescribeTrigger] = useState<any>({})
|
||||
const [serviceUrl, setServiceUrl] = useState<string>(DEFAULT_SERVICE)
|
||||
@@ -88,6 +89,10 @@ export const Signin = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
}, [store.session, store.log, serviceUrl, retryDescribeTrigger])
|
||||
|
||||
const onPressRetryConnect = () => setRetryDescribeTrigger({})
|
||||
const onPressForgotPassword = () => {
|
||||
track('Signin:PressedForgotPassword')
|
||||
setCurrentForm(Forms.ForgotPassword)
|
||||
}
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView testID="signIn" behavior="padding" style={[pal.view]}>
|
||||
@@ -101,7 +106,7 @@ export const Signin = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
setError={setError}
|
||||
setServiceUrl={setServiceUrl}
|
||||
onPressBack={onPressBack}
|
||||
onPressForgotPassword={gotoForm(Forms.ForgotPassword)}
|
||||
onPressForgotPassword={onPressForgotPassword}
|
||||
onPressRetryConnect={onPressRetryConnect}
|
||||
/>
|
||||
) : undefined}
|
||||
@@ -150,10 +155,14 @@ const ChooseAccountForm = ({
|
||||
onSelectAccount: (account?: AccountData) => void
|
||||
onPressBack: () => void
|
||||
}) => {
|
||||
const {track} = useAnalytics()
|
||||
const {track, screen} = useAnalytics()
|
||||
const pal = usePalette('default')
|
||||
const [isProcessing, setIsProcessing] = React.useState(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
screen('Choose Account')
|
||||
}, [screen])
|
||||
|
||||
const onTryAccount = async (account: AccountData) => {
|
||||
if (account.accessJwt && account.refreshJwt) {
|
||||
setIsProcessing(true)
|
||||
@@ -267,6 +276,7 @@ const LoginForm = ({
|
||||
const onPressSelectService = () => {
|
||||
store.shell.openModal(new ServerInputModal(serviceUrl, setServiceUrl))
|
||||
Keyboard.dismiss()
|
||||
track('Signin:PressedSelectService')
|
||||
}
|
||||
|
||||
const onPressNext = async () => {
|
||||
@@ -458,6 +468,11 @@ const ForgotPasswordForm = ({
|
||||
const pal = usePalette('default')
|
||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||
const [email, setEmail] = useState<string>('')
|
||||
const {screen} = useAnalytics()
|
||||
|
||||
useEffect(() => {
|
||||
screen('Signin:ForgotPassword')
|
||||
}, [screen])
|
||||
|
||||
const onPressSelectService = () => {
|
||||
store.shell.openModal(new ServerInputModal(serviceUrl, setServiceUrl))
|
||||
@@ -594,6 +609,12 @@ const SetNewPasswordForm = ({
|
||||
onPasswordSet: () => void
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
const {screen} = useAnalytics()
|
||||
|
||||
useEffect(() => {
|
||||
screen('Signin:SetNewPasswordForm')
|
||||
}, [screen])
|
||||
|
||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||
const [resetCode, setResetCode] = useState<string>('')
|
||||
const [password, setPassword] = useState<string>('')
|
||||
@@ -716,6 +737,12 @@ const SetNewPasswordForm = ({
|
||||
}
|
||||
|
||||
const PasswordUpdatedForm = ({onPressNext}: {onPressNext: () => void}) => {
|
||||
const {screen} = useAnalytics()
|
||||
|
||||
useEffect(() => {
|
||||
screen('Signin:PasswordUpdatedForm')
|
||||
}, [screen])
|
||||
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -24,6 +24,7 @@ import {compressIfNeeded} from '../../../lib/images'
|
||||
import {UserBanner} from '../util/UserBanner'
|
||||
import {UserAvatar} from '../util/UserAvatar'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
export const snapPoints = ['80%']
|
||||
|
||||
@@ -37,6 +38,7 @@ export function Component({
|
||||
const store = useStores()
|
||||
const [error, setError] = useState<string>('')
|
||||
const pal = usePalette('default')
|
||||
const {track} = useAnalytics()
|
||||
|
||||
const [isProcessing, setProcessing] = useState<boolean>(false)
|
||||
const [displayName, setDisplayName] = useState<string>(
|
||||
@@ -57,6 +59,7 @@ export function Component({
|
||||
store.shell.closeModal()
|
||||
}
|
||||
const onSelectNewAvatar = async (img: PickedImage) => {
|
||||
track('EditProfile:AvatarSelected')
|
||||
try {
|
||||
const finalImg = await compressIfNeeded(img, 1000000)
|
||||
setNewUserAvatar(finalImg)
|
||||
@@ -66,6 +69,7 @@ export function Component({
|
||||
}
|
||||
}
|
||||
const onSelectNewBanner = async (img: PickedImage) => {
|
||||
track('EditProfile:BannerSelected')
|
||||
try {
|
||||
const finalImg = await compressIfNeeded(img, 1000000)
|
||||
setNewUserBanner(finalImg)
|
||||
@@ -75,6 +79,7 @@ export function Component({
|
||||
}
|
||||
}
|
||||
const onPressSave = async () => {
|
||||
track('EditProfile:Save')
|
||||
setProcessing(true)
|
||||
if (error) {
|
||||
setError('')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {MutableRefObject} from 'react'
|
||||
import React, {MutableRefObject, useEffect} from 'react'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
@@ -16,6 +16,7 @@ import {FeedItem} from './FeedItem'
|
||||
import {PromptButtons} from './PromptButtons'
|
||||
import {OnScrollCb} from '../../lib/hooks/useOnMainScroll'
|
||||
import {s} from '../../lib/styles'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
const COMPOSE_PROMPT_ITEM = {_reactKey: '__prompt__'}
|
||||
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
||||
@@ -37,6 +38,12 @@ export const Feed = observer(function Feed({
|
||||
onScroll?: OnScrollCb
|
||||
testID?: string
|
||||
}) {
|
||||
const {screen, track} = useAnalytics()
|
||||
|
||||
useEffect(() => {
|
||||
screen('Feed')
|
||||
}, [screen])
|
||||
|
||||
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
|
||||
// VirtualizedList: You have a large list that is slow to update - make sure your
|
||||
// renderItem function renders components that follow React performance best practices
|
||||
@@ -57,6 +64,7 @@ export const Feed = observer(function Feed({
|
||||
}
|
||||
}
|
||||
const onRefresh = () => {
|
||||
track('Feed:onRefresh')
|
||||
feed
|
||||
.refresh()
|
||||
.catch(err =>
|
||||
@@ -64,6 +72,7 @@ export const Feed = observer(function Feed({
|
||||
)
|
||||
}
|
||||
const onEndReached = () => {
|
||||
track('Feed:onEndReached')
|
||||
feed
|
||||
.loadMore()
|
||||
.catch(err => feed.rootStore.log.error('Failed to load more posts', err))
|
||||
|
||||
@@ -18,6 +18,7 @@ import {UserAvatar} from '../util/UserAvatar'
|
||||
import {s} from '../../lib/styles'
|
||||
import {useStores} from '../../../state'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
export const FeedItem = observer(function ({
|
||||
item,
|
||||
@@ -30,6 +31,7 @@ export const FeedItem = observer(function ({
|
||||
}) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {track} = useAnalytics()
|
||||
const [deleted, setDeleted] = useState(false)
|
||||
const record = item.postRecord
|
||||
const itemHref = useMemo(() => {
|
||||
@@ -47,6 +49,7 @@ export const FeedItem = observer(function ({
|
||||
}, [record?.reply])
|
||||
|
||||
const onPressReply = () => {
|
||||
track('FeedItem:PostReply')
|
||||
store.shell.openComposer({
|
||||
replyTo: {
|
||||
uri: item.post.uri,
|
||||
@@ -61,11 +64,13 @@ export const FeedItem = observer(function ({
|
||||
})
|
||||
}
|
||||
const onPressToggleRepost = () => {
|
||||
track('FeedItem:PostRepost')
|
||||
return item
|
||||
.toggleRepost()
|
||||
.catch(e => store.log.error('Failed to toggle repost', e))
|
||||
}
|
||||
const onPressToggleUpvote = () => {
|
||||
track('FeedItem:PostLike')
|
||||
return item
|
||||
.toggleUpvote()
|
||||
.catch(e => store.log.error('Failed to toggle upvote', e))
|
||||
@@ -75,6 +80,7 @@ export const FeedItem = observer(function ({
|
||||
Toast.show('Copied to clipboard')
|
||||
}
|
||||
const onDeletePost = () => {
|
||||
track('FeedItem:PostDelete')
|
||||
item.delete().then(
|
||||
() => {
|
||||
setDeleted(true)
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
export function PromptButtons({
|
||||
onPressCompose,
|
||||
@@ -9,18 +10,29 @@ export function PromptButtons({
|
||||
onPressCompose: (imagesOpen?: boolean) => void
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const {track} = useAnalytics()
|
||||
|
||||
const onPressNewPost = () => {
|
||||
track('PromptButtons:NewPost')
|
||||
onPressCompose(false)
|
||||
}
|
||||
|
||||
const onPressSharePhoto = () => {
|
||||
track('PromptButtons:SharePhoto')
|
||||
onPressCompose(true)
|
||||
}
|
||||
return (
|
||||
<View style={[pal.view, pal.border, styles.container]}>
|
||||
<TouchableOpacity
|
||||
testID="composePromptButton"
|
||||
onPress={() => onPressCompose(false)}
|
||||
onPress={onPressNewPost}
|
||||
style={[styles.btn, {backgroundColor: pal.colors.backgroundLight}]}>
|
||||
<Text type="button" style={pal.text}>
|
||||
New post
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => onPressCompose(true)}
|
||||
onPress={onPressSharePhoto}
|
||||
style={[styles.btn, {backgroundColor: pal.colors.backgroundLight}]}>
|
||||
<Text type="button" style={pal.text}>
|
||||
Share photo
|
||||
|
||||
@@ -27,6 +27,7 @@ import {RichText} from '../util/text/RichText'
|
||||
import {UserAvatar} from '../util/UserAvatar'
|
||||
import {UserBanner} from '../util/UserBanner'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
export const ProfileHeader = observer(function ProfileHeader({
|
||||
view,
|
||||
@@ -37,7 +38,7 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
|
||||
const {track} = useAnalytics()
|
||||
const onPressBack = () => {
|
||||
store.nav.tab.goBack()
|
||||
}
|
||||
@@ -59,18 +60,23 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||
)
|
||||
}
|
||||
const onPressEditProfile = () => {
|
||||
track('ProfileHeader:EditProfileButtonClicked')
|
||||
store.shell.openModal(new EditProfileModal(view, onRefreshAll))
|
||||
}
|
||||
const onPressFollowers = () => {
|
||||
track('ProfileHeader:FollowersButtonClicked')
|
||||
store.nav.navigate(`/profile/${view.handle}/followers`)
|
||||
}
|
||||
const onPressFollows = () => {
|
||||
track('ProfileHeader:FollowsButtonClicked')
|
||||
store.nav.navigate(`/profile/${view.handle}/follows`)
|
||||
}
|
||||
const onPressShare = () => {
|
||||
track('ProfileHeader:ShareButtonClicked')
|
||||
Share.share({url: toShareUrl(`/profile/${view.handle}`)})
|
||||
}
|
||||
const onPressMuteAccount = async () => {
|
||||
track('ProfileHeader:MuteAccountButtonClicked')
|
||||
try {
|
||||
await view.muteAccount()
|
||||
Toast.show('Account muted')
|
||||
@@ -80,6 +86,7 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||
}
|
||||
}
|
||||
const onPressUnmuteAccount = async () => {
|
||||
track('ProfileHeader:UnmuteAccountButtonClicked')
|
||||
try {
|
||||
await view.unmuteAccount()
|
||||
Toast.show('Account unmuted')
|
||||
@@ -89,6 +96,7 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||
}
|
||||
}
|
||||
const onPressReportAccount = () => {
|
||||
track('ProfileHeader:ReportAccountButtonClicked')
|
||||
store.shell.openModal(new ReportAccountModal(view.did))
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {MagnifyingGlassIcon} from '../../lib/icons'
|
||||
import {useStores} from '../../../state'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {colors} from '../../lib/styles'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
const HITSLOP = {left: 10, top: 10, right: 10, bottom: 10}
|
||||
const BACK_HITSLOP = {left: 10, top: 10, right: 30, bottom: 10}
|
||||
@@ -28,10 +29,12 @@ export const ViewHeader = observer(function ViewHeader({
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {track} = useAnalytics()
|
||||
const onPressBack = () => {
|
||||
store.nav.tab.goBack()
|
||||
}
|
||||
const onPressMenu = () => {
|
||||
track('ViewHeader:MenuButtonClicked')
|
||||
store.shell.setMainMenuOpen(true)
|
||||
}
|
||||
const onPressSearch = () => {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {ScreenParams} from '../routes'
|
||||
import {s, colors, gradients} from '../lib/styles'
|
||||
import {useOnMainScroll} from '../lib/hooks/useOnMainScroll'
|
||||
import {clamp} from 'lodash'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
const HITSLOP = {left: 20, top: 20, right: 20, bottom: 20}
|
||||
|
||||
@@ -23,6 +24,7 @@ export const Home = observer(function Home({
|
||||
}: ScreenParams) {
|
||||
const store = useStores()
|
||||
const onMainScroll = useOnMainScroll(store)
|
||||
const {track} = useAnalytics()
|
||||
const safeAreaInsets = useSafeAreaInsets()
|
||||
const [wasVisible, setWasVisible] = React.useState<boolean>(false)
|
||||
const {appState} = useAppState({
|
||||
@@ -72,6 +74,7 @@ export const Home = observer(function Home({
|
||||
}, [visible, store, store.me.mainFeed, navIdx, doPoll, wasVisible])
|
||||
|
||||
const onPressCompose = (imagesOpen?: boolean) => {
|
||||
track('Home:ComposeButtonPressed')
|
||||
store.shell.openComposer({imagesOpen})
|
||||
}
|
||||
const onPressTryAgain = () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useState} from 'react'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {SafeAreaView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import FastImage, {Source as FISource} from 'react-native-fast-image'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
@@ -9,6 +9,7 @@ import {ErrorBoundary} from '../com/util/ErrorBoundary'
|
||||
import {colors} from '../lib/styles'
|
||||
import {usePalette} from '../lib/hooks/usePalette'
|
||||
import {CLOUD_SPLASH} from '../lib/assets'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
enum ScreenState {
|
||||
S_SigninOrCreateAccount,
|
||||
@@ -23,6 +24,12 @@ const SigninOrCreateAccount = ({
|
||||
onPressSignin: () => void
|
||||
onPressCreateAccount: () => void
|
||||
}) => {
|
||||
const {screen} = useAnalytics()
|
||||
|
||||
useEffect(() => {
|
||||
screen('Login')
|
||||
}, [screen])
|
||||
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -6,10 +6,16 @@ import {useStores} from '../../state'
|
||||
import {ScreenParams} from '../routes'
|
||||
import {useOnMainScroll} from '../lib/hooks/useOnMainScroll'
|
||||
import {s} from '../lib/styles'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
export const Notifications = ({navIdx, visible}: ScreenParams) => {
|
||||
const store = useStores()
|
||||
const onMainScroll = useOnMainScroll(store)
|
||||
const {screen} = useAnalytics()
|
||||
|
||||
useEffect(() => {
|
||||
screen('Notifications')
|
||||
}, [screen])
|
||||
|
||||
useEffect(() => {
|
||||
if (!visible) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import {Text} from '../com/util/text/Text'
|
||||
import {FAB} from '../com/util/FAB'
|
||||
import {s, colors} from '../lib/styles'
|
||||
import {useOnMainScroll} from '../lib/hooks/useOnMainScroll'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
const LOADING_ITEM = {_reactKey: '__loading__'}
|
||||
const END_ITEM = {_reactKey: '__end__'}
|
||||
@@ -22,6 +23,12 @@ const EMPTY_ITEM = {_reactKey: '__empty__'}
|
||||
|
||||
export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||
const store = useStores()
|
||||
const {screen} = useAnalytics()
|
||||
|
||||
useEffect(() => {
|
||||
screen('Profile')
|
||||
}, [screen])
|
||||
|
||||
const onMainScroll = useOnMainScroll(store)
|
||||
const [hasSetup, setHasSetup] = useState<boolean>(false)
|
||||
const uiState = React.useMemo(
|
||||
|
||||
@@ -18,6 +18,7 @@ import * as Toast from '../com/util/Toast'
|
||||
import {UserAvatar} from '../com/util/UserAvatar'
|
||||
import {usePalette} from '../lib/hooks/usePalette'
|
||||
import {AccountData} from '../../state/models/session'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
import {DeleteAccountModal} from '../../state/models/shell-ui'
|
||||
|
||||
export const Settings = observer(function Settings({
|
||||
@@ -26,8 +27,13 @@ export const Settings = observer(function Settings({
|
||||
}: ScreenParams) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {screen, track} = useAnalytics()
|
||||
const [isSwitching, setIsSwitching] = React.useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
screen('Settings')
|
||||
}, [screen])
|
||||
|
||||
useEffect(() => {
|
||||
if (!visible) {
|
||||
return
|
||||
@@ -37,6 +43,7 @@ export const Settings = observer(function Settings({
|
||||
}, [visible, store, navIdx])
|
||||
|
||||
const onPressSwitchAccount = async (acct: AccountData) => {
|
||||
track('Settings:SwitchAccountButtonClicked')
|
||||
setIsSwitching(true)
|
||||
if (await store.session.resumeSession(acct)) {
|
||||
setIsSwitching(false)
|
||||
@@ -50,9 +57,11 @@ export const Settings = observer(function Settings({
|
||||
store.session.clear()
|
||||
}
|
||||
const onPressAddAccount = () => {
|
||||
track('Settings:AddAccountButtonClicked')
|
||||
store.session.clear()
|
||||
}
|
||||
const onPressSignout = () => {
|
||||
track('Settings:SignOutButtonClicked')
|
||||
store.session.logout()
|
||||
}
|
||||
const onPressDeleteAccount = () => {
|
||||
|
||||
@@ -22,15 +22,19 @@ import {UserAvatar} from '../../com/util/UserAvatar'
|
||||
import {Text} from '../../com/util/text/Text'
|
||||
import {ToggleButton} from '../../com/util/forms/ToggleButton'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
export const Menu = observer(({onClose}: {onClose: () => void}) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {track} = useAnalytics()
|
||||
|
||||
// events
|
||||
// =
|
||||
|
||||
const onNavigate = (url: string) => {
|
||||
track('Menu:ItemClicked', {url})
|
||||
|
||||
onClose()
|
||||
if (url === '/notifications') {
|
||||
store.nav.switchTo(1, true)
|
||||
@@ -84,6 +88,11 @@ export const Menu = observer(({onClose}: {onClose: () => void}) => {
|
||||
</TouchableOpacity>
|
||||
)
|
||||
|
||||
const onDarkmodePress = () => {
|
||||
track('Menu:ItemClicked', {url: '/darkmode'})
|
||||
store.shell.setDarkMode(!store.shell.darkMode)
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollView testID="menuView" style={[styles.view, pal.view]}>
|
||||
<TouchableOpacity
|
||||
@@ -161,7 +170,7 @@ export const Menu = observer(({onClose}: {onClose: () => void}) => {
|
||||
<ToggleButton
|
||||
label="Dark mode"
|
||||
isSelected={store.shell.darkMode}
|
||||
onPress={() => store.shell.setDarkMode(!store.shell.darkMode)}
|
||||
onPress={onDarkmodePress}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.footer}>
|
||||
|
||||
@@ -45,6 +45,7 @@ import {
|
||||
import {useAnimatedValue} from '../../lib/hooks/useAnimatedValue'
|
||||
import {useTheme} from '../../lib/ThemeContext'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
|
||||
const Btn = ({
|
||||
icon,
|
||||
@@ -133,8 +134,10 @@ export const MobileShell: React.FC = observer(() => {
|
||||
const colorScheme = useColorScheme()
|
||||
const safeAreaInsets = useSafeAreaInsets()
|
||||
const screenRenderDesc = constructScreenRenderDesc(store.nav)
|
||||
const {track} = useAnalytics()
|
||||
|
||||
const onPressHome = () => {
|
||||
track('MobileShell:HomeButtonPressed')
|
||||
if (store.shell.isMainMenuOpen) {
|
||||
store.shell.setMainMenuOpen(false)
|
||||
}
|
||||
@@ -152,6 +155,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||
}
|
||||
}
|
||||
const onPressNotifications = () => {
|
||||
track('MobileShell:NotificationsButtonPressed')
|
||||
if (store.shell.isMainMenuOpen) {
|
||||
store.shell.setMainMenuOpen(false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user