diff --git a/core/screens/homeFeed/components/HomeFeedHeader.tsx b/core/screens/homeFeed/components/HomeFeedHeader.tsx index 3991a5c4a420d0c135eda081da6c3b623a92f63d..bddd0e1e071f273af7937de9dcd41184ef0b6fc5 100644 --- a/core/screens/homeFeed/components/HomeFeedHeader.tsx +++ b/core/screens/homeFeed/components/HomeFeedHeader.tsx @@ -103,7 +103,7 @@ const HomeFeedHeader: React.FC = () => { /> </Animated.View> </HoliBox> - <ProfileCompletionCard style={styles.container} /> + <ProfileCompletionCard style={styles.container} page="home_feed" /> {displayNewHomeFeed === 'test' && <AttendingChallengeEvents />} </View> ) diff --git a/core/screens/userprofile/OwnProfile.tsx b/core/screens/userprofile/OwnProfile.tsx index 839166d48bb7399ceb35054a25be6aae966c8875..81f11b184a7f03993ccd1d084acbd34b661b5d9b 100644 --- a/core/screens/userprofile/OwnProfile.tsx +++ b/core/screens/userprofile/OwnProfile.tsx @@ -27,8 +27,11 @@ import HoliModal from '@holi/ui/components/molecules/HoliModal' import HoliKeyboardSaveView from '@holi/ui/components/organisms/HoliKeyboardSaveView' import { useTheme } from '@holi/ui/styles/theme' import { ButtonIcon } from 'holi-bricks/components/button' +import useTracking from '@holi/core/tracking/hooks/useTracking' +import { TrackingEvent } from '@holi/core/tracking' const OwnProfile = () => { + const { track } = useTracking() const [activeTab, setActiveTab] = useState<string>(Tab.PROFILE) const [showModal, setshowModal] = useState(false) const [editMode, setEditMode] = useState<EditModeState>() @@ -48,17 +51,22 @@ const OwnProfile = () => { const toggleEditMode = useCallback( (newEditMode: EditModeState) => { setEditMode(newEditMode) + if (newEditMode === 'profile') { + track(TrackingEvent.UserProfile.editPressed()) + } // if pressed too soon, the state is set to true, but the modal is not shown. // crude mechanism to recover from this state. // FIXME: We need a proper solution, e.g. involve a loading state in button disabled if (showModal) setshowModal(false) setshowModal(true) }, - [showModal] + [showModal, track] ) // TODO: remove after implementing the feature - const showFeatureNotImplementedToast = useToastForNotAvailableFeature({ feature: 'USER_PROFILE_SHARE' }) + const showFeatureNotImplementedToast = useToastForNotAvailableFeature({ + feature: 'USER_PROFILE_SHARE', + }) useIsomorphicLayoutEffect(() => { const title = t('profile.title') @@ -116,7 +124,9 @@ const OwnProfile = () => { await client.clearStore() // for mobile we need to refetch data manually, web will refetch it anyway with SSR, except for the authenticatedUser itself // fetching all queries can take a while, so we do not await them to not block the UI - client.refetchQueries({ include: Platform.OS !== 'web' ? 'active' : [authenticatedUserV2Query] }) + client.refetchQueries({ + include: Platform.OS !== 'web' ? 'active' : [authenticatedUserV2Query], + }) closeModal() }, [client, closeModal]) diff --git a/core/screens/userprofile/components/OwnProfileView.tsx b/core/screens/userprofile/components/OwnProfileView.tsx index 456933b7e9b1c187676292dc2225fa48bca7bd06..45e77c9b64404e6d7d2a2e0f818ad675b38f9580 100644 --- a/core/screens/userprofile/components/OwnProfileView.tsx +++ b/core/screens/userprofile/components/OwnProfileView.tsx @@ -65,7 +65,11 @@ const OwnProfileView = ({ user, toggleEditMode, activeTab, onTabChange }: PropsW <View style={{ backgroundColor: colors.background10 }}> <HoliContainer> <UserProfileView user={user} contactPossible={false} /> - <ProfileCompletionCard onPressEdit={() => toggleEditMode('profile')} style={styles.profileCard} /> + <ProfileCompletionCard + onPressEdit={() => toggleEditMode('profile')} + style={styles.profileCard} + page="profile" + /> </HoliContainer> </View> <HoliTabs diff --git a/core/screens/userprofile/components/ProfileCompletionCard.tsx b/core/screens/userprofile/components/ProfileCompletionCard.tsx index 60d0eb2afe9fae65f87424a32cdeab9ba15fcf42..ce70b5669de4d5ba200133fc86549d9a1e242f8e 100644 --- a/core/screens/userprofile/components/ProfileCompletionCard.tsx +++ b/core/screens/userprofile/components/ProfileCompletionCard.tsx @@ -1,5 +1,5 @@ import type React from 'react' -import { useState, useMemo, useEffect } from 'react' +import { useState, useMemo, useEffect, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { Pressable, type StyleProp, StyleSheet, View, type ViewStyle } from 'react-native' import AsyncStorage from '@react-native-async-storage/async-storage' @@ -16,6 +16,8 @@ import useRouting from '@holi/core/navigation/hooks/useRouting' import { useLoggedInUser } from '@holi/core/auth/hooks/useLoggedInUser' import HoliLocalImage from '@holi/ui/components/atoms/HoliLocalImage' import { Button } from 'holi-bricks/components/button' +import { TrackingEvent } from '@holi/core/tracking' +import useTracking from '@holi/core/tracking/hooks/useTracking' type Selection = { label: string @@ -27,6 +29,7 @@ type Selection = { type ProfileCompletionCardProps = { onPressEdit?: () => void style?: StyleProp<ViewStyle> + page: 'profile' | 'home_feed' } const getCompletionPercentage = (selections: Selection[]): number => { @@ -34,8 +37,9 @@ const getCompletionPercentage = (selections: Selection[]): number => { return selections.length ? (completedSelections / selections.length) * 100 : 0 } -const ProfileCompletionCard: React.FC<ProfileCompletionCardProps> = ({ style, onPressEdit }) => { +const ProfileCompletionCard: React.FC<ProfileCompletionCardProps> = ({ style, onPressEdit, page }) => { const { theme } = useTheme() + const { track } = useTracking() const { navigate } = useRouting() const { colors } = theme const { t } = useTranslation() @@ -55,15 +59,36 @@ const ProfileCompletionCard: React.FC<ProfileCompletionCardProps> = ({ style, on const selections: Selection[] = useMemo( () => [ - { label: t('profile.completion.interests.title'), select: hasInterests, type: 'INTERESTS', icon: AddCircleLine }, - { label: t('profile.completion.avatar.title'), select: hasAvatar, type: 'AVATAR', icon: UserSmile }, - { label: t('profile.completion.location.title'), select: hasLocation, type: 'LOCATION', icon: MapPin2 }, + { + label: t('profile.completion.interests.title'), + select: hasInterests, + type: 'INTERESTS', + icon: AddCircleLine, + }, + { + label: t('profile.completion.avatar.title'), + select: hasAvatar, + type: 'AVATAR', + icon: UserSmile, + }, + { + label: t('profile.completion.location.title'), + select: hasLocation, + type: 'LOCATION', + icon: MapPin2, + }, ], [hasInterests, hasAvatar, hasLocation, t] ) const completedSteps = selections.filter((selection) => selection.select).length + const handleDismiss = useCallback(async () => { + await AsyncStorage.setItem('profileCardDismissed', 'true') + track(TrackingEvent.UserProfile.completionDismissed(page)) + setShowCard(false) + }, [track, page]) + useEffect(() => { const checkDismissed = async () => { const dismissed = await AsyncStorage.getItem('profileCardDismissed') @@ -91,12 +116,7 @@ const ProfileCompletionCard: React.FC<ProfileCompletionCardProps> = ({ style, on } } checkCompletionStatus() - }, [user, isCompleted, justCompleted]) - - const handleDismiss = () => { - AsyncStorage.setItem('profileCardDismissed', 'true') - setShowCard(false) - } + }, [user, isCompleted, justCompleted, handleDismiss]) const Header = () => ( <Pressable diff --git a/core/tracking/events.ts b/core/tracking/events.ts index ec1c7df3660fd520e3635f332ecc2943cd7cfda0..a46a7f3011a24bd4fc3b9fe410d6f9648d3d1c1d 100644 --- a/core/tracking/events.ts +++ b/core/tracking/events.ts @@ -395,6 +395,21 @@ export namespace TrackingEvent { properties: { pollId }, ...versionOne, }) + + export const UserProfile = { + editPressed: (): TrackingEvent => ({ + name: 'userProfileEdit_pressed', + + ...versionOne, + }), + completionDismissed: (page: 'profile' | 'home_feed'): TrackingEvent => ({ + name: 'userProfileCompletion_dismissed', + properties: { + page: page, + }, + ...versionOne, + }), + } } export const Unknown: TrackingEvent = {