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