diff --git a/packages/common/src/api/tan-query/collection/useDeleteCollection.ts b/packages/common/src/api/tan-query/collection/useDeleteCollection.ts index 20a9bc17800..599288d0f01 100644 --- a/packages/common/src/api/tan-query/collection/useDeleteCollection.ts +++ b/packages/common/src/api/tan-query/collection/useDeleteCollection.ts @@ -3,8 +3,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query' import { useDispatch } from 'react-redux' import { useQueryContext } from '~/api/tan-query/utils' -import { useAppContext } from '~/context/appContext' -import { Name } from '~/models/Analytics' import { ID } from '~/models/Identifiers' import { accountActions } from '~/store' @@ -28,9 +26,6 @@ export const useDeleteCollection = () => { const queryClient = useQueryClient() const dispatch = useDispatch() const { data: currentUserId } = useCurrentUserId() - const { - analytics: { track: trackEvent } - } = useAppContext() return useMutation({ mutationFn: async ({ collectionId }: DeleteCollectionArgs) => { @@ -44,7 +39,7 @@ export const useDeleteCollection = () => { return { collectionId } }, - onMutate: async ({ collectionId, source }): Promise => { + onMutate: async ({ collectionId }): Promise => { if (!currentUserId) { throw new Error('User ID is required') } @@ -60,16 +55,6 @@ export const useDeleteCollection = () => { ) if (!previousCollection) throw new Error('Collection not found') - // Analytics tracking - trackEvent({ - eventName: Name.DELETE, - properties: { - kind: previousCollection.is_album ? 'album' : 'playlist', - id: collectionId, - source - } - }) - // Optimistic updates - mark as deleted in cache primeCollectionData({ collections: [ diff --git a/packages/common/src/api/tan-query/search/useSearchResults.ts b/packages/common/src/api/tan-query/search/useSearchResults.ts index 1e52850c5e7..e4d9f1a9a6f 100644 --- a/packages/common/src/api/tan-query/search/useSearchResults.ts +++ b/packages/common/src/api/tan-query/search/useSearchResults.ts @@ -11,7 +11,6 @@ import { useCurrentUserId } from '~/api' import { useQueryContext } from '~/api/tan-query/utils' import { ID, - Name, SearchSource, UserMetadata, UserCollectionMetadata, @@ -128,7 +127,7 @@ const useSearchQueryProps = ( pageSize, ...filters } - const { audiusSdk, getFeatureEnabled, analytics } = useQueryContext() + const { audiusSdk, getFeatureEnabled } = useQueryContext() const queryClient = useQueryClient() return { @@ -182,27 +181,6 @@ const useSearchQueryProps = ( isPurchaseable: filters.isPremium } - // Fire analytics only for the first page of results - if (pageParam === 0 && !disableAnalytics) { - analytics.track( - analytics.make( - isTagsSearch - ? { - eventName: Name.SEARCH_TAG_SEARCH, - tag: query, - source, - ...searchParams - } - : { - eventName: Name.SEARCH_SEARCH, - term: query, - source, - ...searchParams - } - ) - ) - } - const { data } = isTagsSearch ? await sdk.search.searchTags(searchParams) : await sdk.search.search(searchParams) diff --git a/packages/common/src/api/tan-query/tracks/useDeleteTrack.ts b/packages/common/src/api/tan-query/tracks/useDeleteTrack.ts index d873ed25e1c..92e404cf8f5 100644 --- a/packages/common/src/api/tan-query/tracks/useDeleteTrack.ts +++ b/packages/common/src/api/tan-query/tracks/useDeleteTrack.ts @@ -2,8 +2,6 @@ import { Id } from '@audius/sdk' import { useMutation, useQueryClient } from '@tanstack/react-query' import { useQueryContext } from '~/api/tan-query/utils' -import { useAppContext } from '~/context/appContext' -import { Name } from '~/models/Analytics' import { ID } from '~/models/Identifiers' import { Track } from '~/models/Track' import { UserMetadata } from '~/models/User' @@ -30,9 +28,6 @@ export const useDeleteTrack = () => { const queryClient = useQueryClient() const { data: currentUserId } = useCurrentUserId() const { data: currentUser } = useUser(currentUserId) - const { - analytics: { track: trackEvent } - } = useAppContext() return useMutation({ mutationFn: async ({ trackId }: DeleteTrackArgs) => { @@ -46,7 +41,7 @@ export const useDeleteTrack = () => { return { trackId } }, - onMutate: async ({ trackId, source }): Promise => { + onMutate: async ({ trackId }): Promise => { if (!currentUserId || !currentUser) { throw new Error('User ID is required') } @@ -81,31 +76,8 @@ export const useDeleteTrack = () => { forceReplace: true }) - trackEvent({ - eventName: Name.DELETE, - properties: { - kind: 'track', - id: trackId, - source - } - }) - return { previousTrack, previousUser: currentUser } }, - onSuccess: async (_, { trackId }) => { - const track = queryClient.getQueryData(getTrackQueryKey(trackId)) - - if (track?.stem_of) { - trackEvent({ - eventName: Name.STEM_DELETE, - properties: { - id: track.track_id, - parent_track_id: track.stem_of.parent_track_id, - category: track.stem_of.category - } - }) - } - }, onError: (error, { trackId }, context) => { if (!context || !currentUserId || !context.previousTrack) return diff --git a/packages/common/src/api/tan-query/tracks/useFavoriteTrack.ts b/packages/common/src/api/tan-query/tracks/useFavoriteTrack.ts index 61cab5a2172..d1dc56f4d93 100644 --- a/packages/common/src/api/tan-query/tracks/useFavoriteTrack.ts +++ b/packages/common/src/api/tan-query/tracks/useFavoriteTrack.ts @@ -105,48 +105,9 @@ export const useFavoriteTrack = () => { return { previousTrack, previousUser: currentUser } }, onSuccess: async (_, { trackId }) => { - // Handle co-sign events after successful save const track = queryClient.getQueryData(getTrackQueryKey(trackId)) if (!track) return - const remixTrack = track.remix_of?.tracks?.[0] - const isCoSign = remixTrack?.user?.user_id === currentUserId - if (isCoSign) { - const parentTrackId = remixTrack?.parent_track_id - const hasAlreadyCoSigned = - remixTrack?.has_remix_author_reposted || - remixTrack?.has_remix_author_saved - - const parentTrack = queryClient.getQueryData( - getTrackQueryKey(parentTrackId) - ) - - // Dispatch co-sign events - trackEvent({ - eventName: Name.REMIX_COSIGN_INDICATOR, - properties: { - id: trackId, - handle: currentUser?.handle, - original_track_id: parentTrack?.track_id, - original_track_title: parentTrack?.title, - action: 'favorited' - } - }) - - if (!hasAlreadyCoSigned) { - trackEvent({ - eventName: Name.REMIX_COSIGN, - properties: { - id: trackId, - handle: currentUser?.handle, - original_track_id: parentTrack?.track_id, - original_track_title: parentTrack?.title, - action: 'favorited' - } - }) - } - } - // Dispatch the saveTrackSucceeded action dispatch(tracksSocialActions.saveTrackSucceeded(trackId)) }, diff --git a/packages/common/src/api/tan-query/tracks/useUpdateTrack.ts b/packages/common/src/api/tan-query/tracks/useUpdateTrack.ts index 64ec1ada280..a64c7cb8fdd 100644 --- a/packages/common/src/api/tan-query/tracks/useUpdateTrack.ts +++ b/packages/common/src/api/tan-query/tracks/useUpdateTrack.ts @@ -9,14 +9,8 @@ import { useDispatch, useStore } from 'react-redux' import { trackMetadataForUploadToSdk } from '~/adapters/track' import { useQueryContext } from '~/api/tan-query/utils' import { Track, UserTrackMetadata } from '~/models' -import { Name } from '~/models/Analytics' import { ID } from '~/models/Identifiers' -import { - TrackAccessType, - isContentFollowGated, - isContentTokenGated, - isContentUSDCPurchaseGated -} from '~/models/Track' +import { isContentUSDCPurchaseGated } from '~/models/Track' import { createUserBankIfNeeded } from '~/services/audius-backend' import { CommonState } from '~/store/commonStore' import { stemsUploadSelectors } from '~/store/stems-upload' @@ -31,7 +25,6 @@ import { QUERY_KEYS } from '../queryKeys' import { addPremiumMetadata } from '../upload/usePublishTracks' import { useCurrentAccountUser } from '../users/account/accountSelectors' import { useCurrentUserId } from '../users/account/useCurrentUserId' -import { getUserQueryKey } from '../users/useUser' import { handleStemUpdates } from '../utils/handleStemUpdates' import { primeTrackData } from '../utils/primeTrackData' @@ -52,22 +45,6 @@ export type UpdateTrackParams = { imageFile?: CrossPlatformFile } -const getTrackAccess = ({ - is_stream_gated, - stream_conditions -}: Partial): TrackAccessType => { - if (is_stream_gated && stream_conditions) { - if (isContentFollowGated(stream_conditions)) { - return TrackAccessType.FOLLOW_GATED - } else if (isContentTokenGated(stream_conditions)) { - return TrackAccessType.TOKEN_GATED - } else if (isContentUSDCPurchaseGated(stream_conditions)) { - return TrackAccessType.USDC_GATED - } - } - return TrackAccessType.PUBLIC -} - /** * Edit-track formatting that lived in the legacy `editTrackAsync` saga: * normalize description, format musical key, coerce bpm, and recompute the @@ -201,35 +178,6 @@ export const useUpdateTrack = () => { dispatch ) - // New-remix analytics — replaces the legacy `trackNewRemixEvent` saga - // helper. Fires when the parent_track_id changes. - const prevParentId = - previousMetadata?.remix_of?.tracks?.[0]?.parent_track_id ?? null - const nextParentId = - metadata.remix_of?.tracks?.[0]?.parent_track_id ?? null - if (nextParentId && prevParentId !== nextParentId) { - const accountUser = userId - ? queryClient.getQueryData(getUserQueryKey(userId)) - : undefined - const parentTrack = queryClient.getQueryData( - getTrackQueryKey(nextParentId) - ) - const parentUser = parentTrack - ? queryClient.getQueryData(getUserQueryKey(parentTrack.owner_id)) - : undefined - analytics.track( - analytics.make({ - eventName: Name.REMIX_NEW_REMIX, - id: trackId, - handle: accountUser?.handle ?? '', - title: metadata.title ?? previousMetadata?.title ?? '', - parent_track_id: nextParentId, - parent_track_title: parentTrack?.title ?? '', - parent_track_user_handle: parentUser?.handle ?? '' - }) - ) - } - return response }, onMutate: async ({ @@ -269,81 +217,11 @@ export const useUpdateTrack = () => { // Return context with the previous track and metadata return { previousTrack } }, - onSuccess: (_, params, context?: MutationContext) => { + onSuccess: (_, params) => { queryClient.invalidateQueries({ queryKey: getTrackQueryKey(params.trackId) }) dispatch(toast({ content: 'Changes saved!' })) - - // Edit-track analytics — replaces the `recordEditTrackAnalytics` - // generator the legacy `editTrackAsync` saga ran on confirmer success. - const prev = context?.previousTrack - if (!prev) return - const next = { ...prev, ...params.metadata } as Track - - // Hide-remixes - if ( - (prev?.field_visibility?.remixes ?? true) && - next?.field_visibility?.remixes === false - ) { - const accountUser = userId - ? queryClient.getQueryData(getUserQueryKey(userId)) - : undefined - analytics.track( - analytics.make({ - eventName: Name.REMIX_HIDE, - id: next.track_id, - handle: accountUser?.handle ?? '' - }) - ) - } - // Access changed - const prevAccess = getTrackAccess(prev) - const nextAccess = getTrackAccess(next) - if (prevAccess !== nextAccess) { - analytics.track( - analytics.make({ - eventName: Name.TRACK_EDIT_ACCESS_CHANGED, - id: next.track_id, - from: prevAccess, - to: nextAccess - }) - ) - } - // BPM changed - if (prev.bpm !== next.bpm && next.bpm) { - analytics.track( - analytics.make({ - eventName: Name.TRACK_EDIT_BPM_CHANGED, - id: next.track_id, - from: prev.bpm ?? 0, - to: next.bpm - }) - ) - } - // Musical key changed - if (prev.musical_key !== next.musical_key && next.musical_key) { - analytics.track( - analytics.make({ - eventName: Name.TRACK_EDIT_MUSICAL_KEY_CHANGED, - id: next.track_id, - from: prev.musical_key ?? '', - to: next.musical_key - }) - ) - } - // Comments disabled - if ( - prev.comments_disabled !== next.comments_disabled && - next.comments_disabled - ) { - analytics.track( - analytics.make({ - eventName: Name.COMMENTS_DISABLE_TRACK_COMMENTS, - trackId: next.track_id - }) - ) - } }, onError: (error, { trackId }, context?: MutationContext) => { // If the mutation fails, roll back track data diff --git a/packages/common/src/api/tan-query/upload/usePublishStems.ts b/packages/common/src/api/tan-query/upload/usePublishStems.ts index 29a09705d4f..4de4f76d3e8 100644 --- a/packages/common/src/api/tan-query/upload/usePublishStems.ts +++ b/packages/common/src/api/tan-query/upload/usePublishStems.ts @@ -1,7 +1,7 @@ -import { HashId, Id, type UploadResponse } from '@audius/sdk' +import { Id, type UploadResponse } from '@audius/sdk' import { useMutation, useQueryClient } from '@tanstack/react-query' -import { StemCategory, Name, type StemUpload } from '~/models' +import { StemCategory, type StemUpload } from '~/models' import { ProgressStatus, uploadActions } from '~/store' import type { TrackMetadataForUpload } from '~/store/upload/types' @@ -34,12 +34,7 @@ export const publishStems = async ( context: PublishStemsContext, params: PublishStemsParams ) => { - const { - userId, - audiusSdk, - dispatch, - analytics: { make, track } - } = context + const { userId, audiusSdk, dispatch } = context if (!userId) { throw new Error('User ID is required to publish stems') @@ -66,14 +61,6 @@ export const publishStems = async ( progress: { status: ProgressStatus.COMPLETE } }) ) - track( - make({ - eventName: Name.STEM_COMPLETE_UPLOAD, - id: HashId.parse(stemRes.trackId), - parent_track_id: params.parentTrackId, - category: stem.metadata.category ?? StemCategory.OTHER - }) - ) return { trackId: stemRes.trackId, error: null } } catch (e) { dispatch( diff --git a/packages/common/src/api/tan-query/upload/useUpload.ts b/packages/common/src/api/tan-query/upload/useUpload.ts index 1163fcf1925..57b4f19f136 100644 --- a/packages/common/src/api/tan-query/upload/useUpload.ts +++ b/packages/common/src/api/tan-query/upload/useUpload.ts @@ -4,7 +4,7 @@ import { HashId, Id, type UploadTrackFilesTask } from '@audius/sdk' import { useDispatch } from 'react-redux' import { fileToSdk } from '~/adapters' -import { Name, type StemUploadWithFile, isContentFollowGated } from '~/models' +import { Name, type StemUploadWithFile } from '~/models' import { type TrackForUpload, uploadActions, @@ -202,29 +202,8 @@ export const useUpload = ( const uploadTrackFiles = useCallback( async (tracks: TrackForUpload[]) => { - // Track analytics for each track being uploaded tracks.forEach((t) => { trackFiles.current.set(t.clientId, t.file) - track( - make({ - eventName: Name.TRACK_UPLOAD_TRACK_UPLOADING, - artworkSource: - t.metadata.artwork && 'source' in t.metadata.artwork - ? (t.metadata.artwork.source as 'unsplash' | 'original') - : 'original', - trackId: t.metadata.track_id!, - genre: t.metadata.genre ?? '', - mood: t.metadata.mood ?? undefined, - size: t.file.size ?? -1, - fileType: t.file.type ?? '', - name: t.file.name ?? '', - downloadable: isContentFollowGated(t.metadata.download_conditions) - ? 'follow' - : t.metadata.is_downloadable - ? 'yes' - : 'no' - }) - ) }) const tasks = await getTrackUploadTasks( @@ -240,7 +219,7 @@ export const useUpload = ( return await uploadFiles(tasks) }, - [audiusSdk, dispatch, uploadFiles, track, make, requireUserId] + [audiusSdk, dispatch, uploadFiles, requireUserId] ) /** diff --git a/packages/common/src/api/tan-query/users/account/useReorderLibrary.ts b/packages/common/src/api/tan-query/users/account/useReorderLibrary.ts index 95ba4392b45..e3f2aac6258 100644 --- a/packages/common/src/api/tan-query/users/account/useReorderLibrary.ts +++ b/packages/common/src/api/tan-query/users/account/useReorderLibrary.ts @@ -87,14 +87,6 @@ export const useReorderLibrary = () => { return { ...old, playlist_library: updatedLibrary } }) - track( - make({ - eventName: Name.PLAYLIST_LIBRARY_REORDER, - containsTemporaryPlaylists: false, - kind: collectionType - }) - ) - if (collectionType === 'playlist' && typeof collectionId === 'number') { const isNewAddition = !previousLibrary.contents.some( (item: PlaylistLibraryItem) => diff --git a/packages/common/src/api/tan-query/users/account/useResendRecoveryEmail.ts b/packages/common/src/api/tan-query/users/account/useResendRecoveryEmail.ts index 0422095cdab..a7335c5db3b 100644 --- a/packages/common/src/api/tan-query/users/account/useResendRecoveryEmail.ts +++ b/packages/common/src/api/tan-query/users/account/useResendRecoveryEmail.ts @@ -1,7 +1,6 @@ import { useMutation } from '@tanstack/react-query' import { useAppContext } from '~/context/appContext' -import { Name } from '~/models/Analytics' import { useQueryContext } from '../../utils' @@ -11,7 +10,7 @@ import { useQueryContext } from '../../utils' * packages/web/src/common/store/recovery-email/sagas.ts. */ export const useResendRecoveryEmail = () => { - const { authService, identityService, analytics } = useQueryContext() + const { authService, identityService } = useQueryContext() const { getHostUrl } = useAppContext() return useMutation({ @@ -24,13 +23,6 @@ export const useResendRecoveryEmail = () => { host }) }, - onSuccess: () => { - analytics.track( - analytics.make({ - eventName: Name.SETTINGS_RESEND_ACCOUNT_RECOVERY - }) - ) - }, onError: (error) => { console.error( 'Resend Recovery: Failed to send recovery email', diff --git a/packages/common/src/context/comments/commentsContext.tsx b/packages/common/src/context/comments/commentsContext.tsx index 6dade224763..7c77c787c6c 100644 --- a/packages/common/src/context/comments/commentsContext.tsx +++ b/packages/common/src/context/comments/commentsContext.tsx @@ -23,15 +23,13 @@ import { getCommentSectionLoading } from '~/api' import { useGatedContentAccess } from '~/hooks' -import { ModalSource, ID, Comment, ReplyComment, Name, Track } from '~/models' +import { ModalSource, ID, Comment, ReplyComment, Track } from '~/models' import { playbackActions } from '~/store' import { seekTo } from '~/store/playback/slice' import { PurchaseableContentType } from '~/store/purchase-content/types' import { usePremiumContentPurchaseModal } from '~/store/ui/modals/premium-content-purchase-modal' import { Nullable } from '~/utils' -import { useAppContext } from '../appContext' - type CommentSectionProviderProps = { entityId: ID entityType?: EntityType.TRACK @@ -110,10 +108,6 @@ export function CommentSectionProvider( } = props const { data: track } = useTrack(entityId) - const { - analytics: { make, track: trackEvent } - } = useAppContext() - const [currentSort, setCurrentSort] = useState( CommentSortMethod.Top ) @@ -121,18 +115,11 @@ export function CommentSectionProvider( resetPreviousCommentCount(queryClient, entityId) queryClient.resetQueries({ queryKey: [QUERY_KEYS.trackCommentList] }) setCurrentSort(sortMethod) - trackEvent( - make({ - eventName: Name.COMMENTS_APPLY_SORT, - sortType: sortMethod - }) - ) } const { data: currentUserId } = useCurrentUserId() const { - data: comments = [], commentIds = [], status, hasNextPage, @@ -171,21 +158,11 @@ export function CommentSectionProvider( const handleLoadMorePages = useCallback(() => { loadMorePages() - trackEvent( - make({ - eventName: Name.COMMENTS_LOAD_MORE_COMMENTS, - trackId: entityId, - offset: comments.length - }) - ) - }, [comments.length, entityId, loadMorePages, make, trackEvent]) + }, [loadMorePages]) const handleResetComments = useCallback(() => { resetComments() - trackEvent( - make({ eventName: Name.COMMENTS_LOAD_NEW_COMMENTS, trackId: entityId }) - ) - }, [entityId, make, resetComments, trackEvent]) + }, [resetComments]) const handleCloseDrawer = useCallback(() => { closeDrawer?.() diff --git a/packages/common/src/context/comments/commentsHooks.ts b/packages/common/src/context/comments/commentsHooks.ts index 5132e6659b8..7b65f1f9f45 100644 --- a/packages/common/src/context/comments/commentsHooks.ts +++ b/packages/common/src/context/comments/commentsHooks.ts @@ -4,7 +4,6 @@ import { CommentMention } from '@audius/sdk' -import { Name } from '~/models/Analytics' import { ID } from '~/models/Identifiers' import { @@ -20,7 +19,6 @@ import { useGetTrackCommentNotificationSetting as useTqGetTrackCommentNotificationSetting, useCurrentUserId } from '../../api' -import { useAppContext } from '../appContext' import { useCurrentCommentSection } from './commentsContext' @@ -28,9 +26,6 @@ export const usePostComment = () => { const { currentUserId, entityId, entityType, currentSort } = useCurrentCommentSection() const { mutate: postComment, ...rest } = useTqPostComment() - const { - analytics: { track, make } - } = useAppContext() const wrappedHandler = async ( message: string, @@ -49,14 +44,6 @@ export const usePostComment = () => { mentions, currentSort }) - track( - make({ - eventName: Name.COMMENTS_CREATE_COMMENT, - trackId: entityId, - parentCommentId, - timestamp: trackTimestampS - }) - ) } } @@ -67,9 +54,6 @@ export const useReactToComment = () => { const { currentUserId, isEntityOwner, currentSort, entityId } = useCurrentCommentSection() const { mutate: reactToComment, ...response } = useTqReactToComment() - const { - analytics: { track, make } - } = useAppContext() const wrappedHandler = async (commentId: ID, isLiked: boolean) => { if (currentUserId) { @@ -81,14 +65,6 @@ export const useReactToComment = () => { currentSort, trackId: entityId }) - track( - make({ - eventName: isLiked - ? Name.COMMENTS_LIKE_COMMENT - : Name.COMMENTS_UNLIKE_COMMENT, - commentId - }) - ) } } return [wrappedHandler, response] as const @@ -97,9 +73,6 @@ export const useReactToComment = () => { export const useEditComment = () => { const { currentUserId, currentSort, entityId } = useCurrentCommentSection() const { mutate: editComment, ...rest } = useTqEditComment() - const { - analytics: { track, make } - } = useAppContext() const wrappedHandler = async ( commentId: ID, @@ -115,12 +88,6 @@ export const useEditComment = () => { trackId: entityId, currentSort }) - track( - make({ - eventName: Name.COMMENTS_UPDATE_COMMENT, - commentId - }) - ) } } return [wrappedHandler, rest] as const @@ -134,9 +101,6 @@ export const usePinComment = () => { track: trackData } = useCurrentCommentSection() const { mutate: pinComment, ...rest } = useTqPinComment() - const { - analytics: { track, make } - } = useAppContext() const wrappedHandler = (commentId: ID, isPinned: boolean) => { if (currentUserId) { @@ -148,27 +112,14 @@ export const usePinComment = () => { currentSort, previousPinnedCommentId: trackData?.pinned_comment_id }) - track( - make({ - eventName: isPinned - ? Name.COMMENTS_PIN_COMMENT - : Name.COMMENTS_UNPIN_COMMENT, - trackId: entityId, - commentId - }) - ) } } return [wrappedHandler, rest] as const } export const useReportComment = () => { - const { currentUserId, entityId, currentSort, isEntityOwner } = - useCurrentCommentSection() + const { currentUserId, entityId, currentSort } = useCurrentCommentSection() const { mutate: reportComment, ...rest } = useTqReportComment() - const { - analytics: { track, make } - } = useAppContext() const wrappedHandler = (commentId: ID, parentCommentId?: ID) => { if (currentUserId) { @@ -179,14 +130,6 @@ export const useReportComment = () => { trackId: entityId, currentSort }) - track( - make({ - eventName: Name.COMMENTS_REPORT_COMMENT, - commentId, - commentOwnerId: currentUserId, - isRemoved: isEntityOwner - }) - ) } } return [wrappedHandler, rest] as const @@ -195,9 +138,6 @@ export const useReportComment = () => { export const useMuteUser = () => { const { data: currentUserId } = useCurrentUserId() const { mutate: muteUser, ...rest } = useTqMuteUser() - const { - analytics: { track, make } - } = useAppContext() const wrappedHandler = ({ mutedUserId, @@ -218,14 +158,6 @@ export const useMuteUser = () => { trackId, currentSort }) - track( - make({ - eventName: isMuted - ? Name.COMMENTS_UNMUTE_USER - : Name.COMMENTS_MUTE_USER, - userId: mutedUserId - }) - ) } } return [wrappedHandler, rest] as const @@ -234,9 +166,6 @@ export const useMuteUser = () => { export const useDeleteComment = () => { const { currentUserId, entityId, currentSort } = useCurrentCommentSection() const { mutate: deleteComment, ...rest } = useTqDeleteComment() - const { - analytics: { track, make } - } = useAppContext() const wrappedHandler = (commentId: ID, parentCommentId?: ID) => { if (currentUserId) { @@ -247,12 +176,6 @@ export const useDeleteComment = () => { currentSort, parentCommentId }) - track( - make({ - eventName: Name.COMMENTS_DELETE_COMMENT, - commentId - }) - ) } } return [wrappedHandler, rest] as const @@ -272,10 +195,6 @@ export const useUpdateTrackCommentNotificationSetting = (trackId: ID) => { const { mutate: updateSetting, ...rest } = useTqUpdateTrackCommentNotificationSetting() - const { - analytics: { track, make } - } = useAppContext() - const wrappedHandler = (action: 'mute' | 'unmute') => { if (currentUserId) { updateSetting({ @@ -286,15 +205,6 @@ export const useUpdateTrackCommentNotificationSetting = (trackId: ID) => { ? EntityManagerAction.MUTE : EntityManagerAction.UNMUTE }) - track( - make({ - eventName: - action === 'mute' - ? Name.COMMENTS_TURN_OFF_NOTIFICATIONS_FOR_TRACK - : Name.COMMENTS_TURN_ON_NOTIFICATIONS_FOR_TRACK, - trackId - }) - ) } } @@ -305,9 +215,6 @@ export const useUpdateCommentNotificationSetting = (commentId: ID) => { const { data: currentUserId } = useCurrentUserId() const { mutate: updateSetting, ...rest } = useTqUpdateCommentNotificationSetting() - const { - analytics: { track, make } - } = useAppContext() const wrappedHandler = (action: 'mute' | 'unmute') => { if (currentUserId) { @@ -319,15 +226,6 @@ export const useUpdateCommentNotificationSetting = (commentId: ID) => { ? EntityManagerAction.MUTE : EntityManagerAction.UNMUTE }) - track( - make({ - eventName: - action === 'mute' - ? Name.COMMENTS_TURN_OFF_NOTIFICATIONS_FOR_COMMENT - : Name.COMMENTS_TURN_ON_NOTIFICATIONS_FOR_COMMENT, - commentId - }) - ) } } diff --git a/packages/common/src/hooks/chats/useSetInboxPermissions.ts b/packages/common/src/hooks/chats/useSetInboxPermissions.ts index f7ac1fa37ab..f22ecad18a1 100644 --- a/packages/common/src/hooks/chats/useSetInboxPermissions.ts +++ b/packages/common/src/hooks/chats/useSetInboxPermissions.ts @@ -4,8 +4,6 @@ import { useDispatch, useSelector } from 'react-redux' import { useCurrentUserId } from '~/api' import { useQueryContext } from '~/api/tan-query/utils' -import { useAppContext } from '~/context/appContext' -import { Name } from '~/models/Analytics' import { CommonState } from '~/store' import { chatActions, @@ -24,9 +22,6 @@ export const useSetInboxPermissions = () => { const permissions = useSelector((state: CommonState) => getUserChatPermissions(state, userId) ) - const { - analytics: { track, make } - } = useAppContext() const permissionsStatus = useSelector(getChatPermissionsStatus) const doFetchPermissions = useCallback(() => { @@ -37,29 +32,16 @@ export const useSetInboxPermissions = () => { const savePermissions = useCallback( async (permitMap: InboxSettingsFormValues) => { - let permitList try { const sdk = await audiusSdk() - permitList = transformMapToPermitList(permitMap) + const permitList = transformMapToPermitList(permitMap) await sdk.chats.permit({ permitList, allow: true }) doFetchPermissions() - track( - make({ - eventName: Name.CHANGE_INBOX_SETTINGS_SUCCESS, - permitList - }) - ) } catch (e) { console.error('Chats', e as Error) - track( - make({ - eventName: Name.CHANGE_INBOX_SETTINGS_FAILURE, - permitList - }) - ) } }, - [audiusSdk, doFetchPermissions, track, make] + [audiusSdk, doFetchPermissions] ) return { diff --git a/packages/common/src/hooks/useAccountSwitcher.ts b/packages/common/src/hooks/useAccountSwitcher.ts index 99a88ab2f82..8753ce3ef2e 100644 --- a/packages/common/src/hooks/useAccountSwitcher.ts +++ b/packages/common/src/hooks/useAccountSwitcher.ts @@ -2,15 +2,11 @@ import { useCallback } from 'react' import { useCurrentUserId, useCurrentWeb3Account } from '~/api' import { useAppContext } from '~/context' -import { Name } from '~/models/Analytics' import { UserMetadata } from '~/models/User' export const useAccountSwitcher = () => { const { localStorage } = useAppContext() const { data: currentWeb3User } = useCurrentWeb3Account() - const { - analytics: { make, track } - } = useAppContext() const switchAccount = useCallback( async (user: UserMetadata) => { @@ -18,13 +14,6 @@ export const useAccountSwitcher = () => { console.error('User has no wallet address') return } - await track( - make({ - eventName: Name.MANAGER_MODE_SWITCH_ACCOUNT, - managedUserId: user.user_id - }) - ) - // Set an override if we aren't using the wallet of the "signed in" user if (currentWeb3User && currentWeb3User.wallet === user.wallet) { await localStorage.clearAudiusUserWalletOverride() @@ -37,7 +26,7 @@ export const useAccountSwitcher = () => { window.location.reload() }, - [currentWeb3User, localStorage, make, track] + [currentWeb3User, localStorage] ) /** Convenience method to switch out of Manager Mode and back to the current web3 user */ diff --git a/packages/common/src/models/Analytics.ts b/packages/common/src/models/Analytics.ts index dffbd56160e..c2529fe3718 100644 --- a/packages/common/src/models/Analytics.ts +++ b/packages/common/src/models/Analytics.ts @@ -1,17 +1,12 @@ -import { ChatPermission, Genre } from '@audius/sdk' +import { Genre } from '@audius/sdk' import { FeedFilter } from '~/models/FeedFilter' import { FeedTab } from '~/models/FeedTab' import { ID, PlayableType } from '~/models/Identifiers' -import { TimeRange } from '~/models/TimeRange' import { WalletAddress } from '~/models/Wallet' -import { Nullable } from '~/utils/typeUtils' -import { Chain } from './Chain' import { LaunchCoinResponse, LaunchpadFormValues } from './Launchpad' -import { PlaylistLibraryKind } from './PlaylistLibrary' import { PurchaseMethod } from './PurchaseContent' -import { AccessConditions, TrackAccessType } from './Track' const ANALYTICS_TRACK_EVENT = 'ANALYTICS/TRACK_EVENT' @@ -33,8 +28,6 @@ export type AnalyticsEvent = { } export enum Name { - APP_ERROR = 'App Error', // Generic app error - SESSION_START = 'Session Start', // Account creation // When the user opens the create account page CREATE_ACCOUNT_OPEN = 'Create Account: Open', @@ -74,44 +67,14 @@ export enum Name { SIGN_IN_WITH_INCOMPLETE_ACCOUNT = 'Sign In: Incomplete Account', SIGN_IN_WITH_DEACTIVATED_ACCOUNT = 'Sign In: Deactivated Account', - // Settings - SETTINGS_CHANGE_THEME = 'Settings: Change Theme', - SETTINGS_RESEND_ACCOUNT_RECOVERY = 'Settings: Resend Account Recovery', - SETTINGS_COMPLETE_CHANGE_PASSWORD = 'Settings: Complete Change Password', - SETTINGS_LOG_OUT = 'Settings: Log Out', - // Audius OAuth Login Page AUDIUS_OAUTH_START = 'Audius Oauth: Open Login (authenticate)', AUDIUS_OAUTH_SUBMIT = 'Audius Oauth: Submit Login (authenticate)', AUDIUS_OAUTH_COMPLETE = 'Audius Oauth: Login (authenticate) Success', AUDIUS_OAUTH_ERROR = 'Audius Oauth: Login (authenticate) Failed', - // Developer app - DEVELOPER_APP_CREATE_SUBMIT = 'Developer Apps: Create app submit', - DEVELOPER_APP_CREATE_SUCCESS = 'Developer Apps: Create app success', - DEVELOPER_APP_CREATE_ERROR = 'Developer Apps: Create app error', - DEVELOPER_APP_EDIT_SUBMIT = 'Developer Apps: Edit app submit', - DEVELOPER_APP_EDIT_SUCCESS = 'Developer Apps: Edit app success', - DEVELOPER_APP_EDIT_ERROR = 'Developer Apps: Edit app error', - DEVELOPER_APP_DELETE_SUCCESS = 'Developer Apps: Delete app success', - DEVELOPER_APP_DELETE_ERROR = 'Developer Apps: Delete app error', - - // Authorized app - AUTHORIZED_APP_REMOVE_SUCCESS = 'Authorized Apps: Remove app success', - AUTHORIZED_APP_REMOVE_ERROR = 'Authorized Apps: Remove app error', - - // Visualizer - VISUALIZER_OPEN = 'Visualizer: Open', - VISUALIZER_CLOSE = 'Visualizer: Close', - // Profile completion ACCOUNT_HEALTH_METER_FULL = 'Account Health: Meter Full', - ACCOUNT_HEALTH_UPLOAD_COVER_PHOTO = 'Account Health: Upload Cover Photo', - ACCOUNT_HEALTH_UPLOAD_PROFILE_PICTURE = 'Account Health: Upload Profile Picture', - ACCOUNT_HEALTH_DOWNLOAD_DESKTOP = 'Account Health: Download Desktop', - - // TOS - BANNER_TOS_CLICKED = 'Banner TOS Clicked', // Social actions SHARE = 'Share', @@ -120,38 +83,21 @@ export enum Name { UNDO_REPOST = 'Undo Repost', FAVORITE = 'Favorite', UNFAVORITE = 'Unfavorite', - ARTIST_PICK_SELECT_TRACK = 'Artist Pick: Select Track', FOLLOW = 'Follow', UNFOLLOW = 'Unfollow', - // Playlist creation - PLAYLIST_ADD = 'Playlist: Add To Playlist', - PLAYLIST_OPEN_CREATE = 'Playlist: Open Create Playlist', - PLAYLIST_START_CREATE = 'Playlist: Start Create Playlist', - PLAYLIST_COMPLETE_CREATE = 'Playlist: Complete Create Playlist', - PLAYLIST_MAKE_PUBLIC = 'Playlist: Make Public', - PLAYLIST_OPEN_EDIT_FROM_LIBRARY = 'Playlist: Open Edit Playlist From Sidebar', - - DELETE = 'Delete', - // Folders - FOLDER_OPEN_EDIT = 'Folder: Open Edit Playlist Folder', - FOLDER_SUBMIT_EDIT = 'Folder: Submit Edit Playlist Folder', FOLDER_DELETE = 'Folder: Delete Playlist Folder', - FOLDER_CANCEL_EDIT = 'Folder: Cancel Edit Playlist Folder', // Embed - EMBED_OPEN = 'Embed: Open modal', EMBED_COPY = 'Embed: Copy', // Upload funnel / conversion TRACK_UPLOAD_OPEN = 'Track Upload: Open', TRACK_UPLOAD_START_UPLOADING = 'Track Upload: Start Upload', - TRACK_UPLOAD_TRACK_UPLOADING = 'Track Upload: Track Uploading', // Note that upload is considered complete if it is explicitly rejected // by the node receiving the file (HTTP 403). TRACK_UPLOAD_COMPLETE_UPLOAD = 'Track Upload: Complete Upload', - TRACK_UPLOAD_VIEW_TRACK_PAGE = 'Track Upload: View Track page', TWEET_FIRST_UPLOAD = 'Tweet First Upload', // Upload success tracking @@ -159,43 +105,15 @@ export enum Name { TRACK_UPLOAD_FAILURE = 'Track Upload: Failure', // Gated Track Uploads - TRACK_UPLOAD_FOLLOW_GATED = 'Track Upload: Follow Gated', TRACK_UPLOAD_USDC_GATED = 'Track Upload: USDC Gated', - TRACK_UPLOAD_TOKEN_GATED = 'Track Upload: Token Gated', // Download-Only Gated Track Uploads - TRACK_UPLOAD_FOLLOW_GATED_DOWNLOAD = 'Track Upload: Follow Gated Download', TRACK_UPLOAD_USDC_GATED_DOWNLOAD = 'Track Upload: USDC Gated Download', - TRACK_UPLOAD_TOKEN_GATED_DOWNLOAD = 'Track Upload: Token Gated Download', - - // Track Downloads - TRACK_DOWNLOAD_CLICKED_DOWNLOAD_ALL = 'Track Download: Clicked Download All', - TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_ALL = 'Track Download: Successfull Download All', - TRACK_DOWNLOAD_FAILED_DOWNLOAD_ALL = 'Track Download: Failed Download All', - TRACK_DOWNLOAD_CLICKED_DOWNLOAD_SINGLE = 'Track Download: Clicked Download Single', - TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_SINGLE = 'Track Download: Successfull Download Single', - TRACK_DOWNLOAD_FAILED_DOWNLOAD_SINGLE = 'Track Download: Failed Download Single', - - // Track Edits - TRACK_EDIT_ACCESS_CHANGED = 'Track Edit: Access Changed', - TRACK_EDIT_BPM_CHANGED = 'Track Edit: BPM Changed', - TRACK_EDIT_MUSICAL_KEY_CHANGED = 'Track Edit: Musical Key Changed', - - // Collection Edits - COLLECTION_EDIT_ACCESS_CHANGED = 'Collection Edit: Access Changed', - COLLECTION_EDIT = 'Collection Edit: General Edits', // Unlocked Gated Tracks USDC_PURCHASE_GATED_TRACK_UNLOCKED = 'USDC Gated: Track Unlocked', USDC_PURCHASE_GATED_COLLECTION_UNLOCKED = 'USDC Gated: Collection Unlocked', - FOLLOW_GATED_TRACK_UNLOCKED = 'Follow Gated: Track Unlocked', - TOKEN_GATED_TRACK_UNLOCKED = 'Token Gated: Track Unlocked', // Unlocked Download-Only Gated Tracks USDC_PURCHASE_GATED_DOWNLOAD_TRACK_UNLOCKED = 'USDC Gated: Download Track Unlocked', - FOLLOW_GATED_DOWNLOAD_TRACK_UNLOCKED = 'Follow Gated: Download Track Unlocked', - TOKEN_GATED_DOWNLOAD_TRACK_UNLOCKED = 'Token Gated: Download Track Unlocked', - - // Trending - TRENDING_CHANGE_VIEW = 'Trending: Change view', // Feed FEED_CHANGE_VIEW = 'Feed: Change view', @@ -214,27 +132,12 @@ export enum Name { NOTIFICATIONS_CLICK_TASTEMAKER_TWITTER_SHARE = 'Notifications: Clicked Tastemaker Twitter Share', NOTIFICATIONS_CLICK_ADD_TRACK_TO_PLAYLIST_TWITTER_SHARE = 'Notifications: Clicked Add Track to Playlist Twitter Share', NOTIFICATIONS_CLICK_USDC_PURCHASE_TWITTER_SHARE = 'Notifications: Clicked USDC Purchase Twitter Share', - NOTIFICATIONS_TOGGLE_SETTINGS = 'Notifications: Toggle Setting', BROWSER_NOTIFICATION_SETTINGS = 'Browser Push Notification', - // Profile page - PROFILE_PAGE_TAB_CLICK = 'Profile Page: Tab Click', - PROFILE_PAGE_SORT = 'Profile Page: Sort', - PROFILE_PAGE_CLICK_INSTAGRAM = 'Profile Page: Go To Instagram', - PROFILE_PAGE_CLICK_TWITTER = 'Profile Page: Go To Twitter', - PROFILE_PAGE_CLICK_TIKTOK = 'Profile Page: Go To TikTok', - PROFILE_PAGE_CLICK_WEBSITE = 'ProfilePage: Go To Website', - PROFILE_PAGE_SHOWN_ARTIST_RECOMMENDATIONS = 'ProfilePage: Shown Artist Recommendations', - - // Track page - TRACK_PAGE_PLAY_MORE = 'Track Page: Play More By This Artist', - // Playback PLAYBACK_PLAY = 'Playback: Play', PLAYBACK_PAUSE = 'Playback: Pause', PLAYLIST_PLAY = 'Playlist: Play', - // Playback performance metrics - BUFFERING_TIME = 'Buffering Time', // Play Queue PLAY_QUEUE_OPEN = 'Play Queue: Open', @@ -247,20 +150,12 @@ export enum Name { // Navigation PAGE_VIEW = 'Page View', - LINK_CLICKING = 'Link Click', - TAG_CLICKING = 'Tag Click', // Modals MODAL_OPENED = 'Modal Opened', MODAL_CLOSED = 'Modal Closed', - // Search - SEARCH_SEARCH = 'Search: Search', - SEARCH_TAG_SEARCH = 'Search: Tag Search', - SEARCH_RESULT_SELECT = 'Search: Result Select', - // Explore - EXPLORE_SECTION_VIEW = 'Explore: Section View', EXPLORE_SECTION_CLICK = 'Explore: Section Click', // Weekly Rotation @@ -271,43 +166,22 @@ export enum Name { // Errors ERROR_PAGE = 'Error Page', - NOT_FOUND_PAGE = 'Not Found Page', // Remixes STEM_COMPLETE_UPLOAD = 'Stem: Complete Upload', - STEM_DELETE = 'Stem: Delete', - REMIX_NEW_REMIX = 'Remix: New Remix', - REMIX_COSIGN = 'Remix: CoSign', - REMIX_COSIGN_INDICATOR = 'Remix: CoSign Indicator', - REMIX_HIDE = 'Remix: Hide', // $AUDIO SEND_AUDIO_SUCCESS = 'Send $AUDIO: Success', SEND_AUDIO_FAILURE = 'Send $AUDIO: Failure', // Playlist library - PLAYLIST_LIBRARY_REORDER = 'Playlist Library: Reorder', PLAYLIST_LIBRARY_MOVE_PLAYLIST_INTO_FOLDER = 'Playlist Library: Move Playlist Into Folder', PLAYLIST_LIBRARY_ADD_PLAYLIST_TO_FOLDER = 'Playlist Library: Add Playlist To Folder', PLAYLIST_LIBRARY_MOVE_PLAYLIST_OUT_OF_FOLDER = 'Playlist Library: Move Playlist Out of Folder', - // Deactivate Account - DEACTIVATE_ACCOUNT_PAGE_VIEW = 'Deactivate Account: Page View', - DEACTIVATE_ACCOUNT_REQUEST = 'Deactivate Account: Request', - DEACTIVATE_ACCOUNT_SUCCESS = 'Deactivate Account: Success', - DEACTIVATE_ACCOUNT_FAILURE = 'Deactivate Account: Failure', - - // Create User Bank - CREATE_USER_BANK_SUCCESS = 'Create User Bank: Success', - CREATE_USER_BANK_FAILURE = 'Create User Bank: Failure', - // Rewards - REWARDS_CLAIM_DETAILS_OPENED = 'Rewards Claim: Opened', REWARDS_CLAIM_ALL_REQUEST = 'Rewards Claim All: Request', REWARDS_CLAIM_ALL_SUCCESS = 'Rewards Claim All: Success', - REWARDS_CLAIM_ALL_FAILURE = 'Rewards Claim All: Failure', - REWARDS_CLAIM_REQUEST = 'Rewards Claim: Request', - REWARDS_CLAIM_SUCCESS = 'Rewards Claim: Success', // Buy USDC BUY_USDC_ON_RAMP_OPENED = 'Buy USDC: On Ramp Opened', @@ -327,8 +201,6 @@ export enum Name { BUY_SELL_SWAP_FAILURE = 'Buy Sell Modal: Swap Failure', BUY_SELL_ADD_FUNDS_CLICKED = 'Buy Sell Modal: Add Funds Clicked', - // Withdraw USDC - WITHDRAW_USDC_MODAL_OPENED = 'Withdraw USDC: Modal Opened', WITHDRAW_USDC_ADDRESS_PASTED = 'Withdraw USDC: Address Pasted', WITHDRAW_USDC_REQUESTED = 'Withdraw USDC: Requested', @@ -355,8 +227,6 @@ export enum Name { STRIPE_ERROR = 'Stripe Modal: Error', STRIPE_REJECTED = 'Stripe Modal: Rejected', - // Purchase Content - PURCHASE_CONTENT_BUY_CLICKED = 'Purchase Content: Buy Clicked', PURCHASE_CONTENT_STARTED = 'Purchase Content: Started', PURCHASE_CONTENT_SUCCESS = 'Purchase Content: Success', @@ -365,38 +235,9 @@ export enum Name { PURCHASE_CONTENT_TOS_CLICKED = 'Purchase Content: Terms of Service Link Clicked', PURCHASE_CONTENT_USDC_USER_BANK_COPIED = 'Purchase Content: USDC User Bank Copied', - // Rate & Review CTA - RATE_CTA_DISPLAYED = 'Rate CTA: Displayed', - RATE_CTA_RESPONSE_YES = 'Rate CTA: User Responded Yes', - RATE_CTA_RESPONSE_NO = 'Rate CTA: User Responded No', - - // Connect Wallet - CONNECT_WALLET_NEW_WALLET_START = 'Connect Wallet: New Wallet Start', - CONNECT_WALLET_NEW_WALLET_CONNECTING = 'Connect Wallet: New Wallet Connecting', - CONNECT_WALLET_NEW_WALLET_CONNECTED = 'Connect Wallet: New Wallet Connected', - CONNECT_WALLET_ALREADY_ASSOCIATED = 'Connect Wallet: Already Associated', - CONNECT_WALLET_ERROR = 'Connect Wallet: Error', - // Chat - CREATE_CHAT_SUCCESS = 'Create Chat: Success', - CREATE_CHAT_FAILURE = 'Create Chat: Failure', - CHAT_BLAST_CTA_CLICKED = 'Chat Blast: CTA Clicked', - CREATE_CHAT_BLAST_SUCCESS = 'Chat Blast: Create - Success', - CREATE_CHAT_BLAST_FAILURE = 'Chat Blast: Create - Failure', CHAT_BLAST_MESSAGE_SENT = 'Chat Blast: Message Sent', - CHAT_BLAST_MESSAGE_VIEWED = 'Chat Blast: Message Viewed', SEND_MESSAGE_SUCCESS = 'Send Message: Success', - SEND_MESSAGE_FAILURE = 'Send Message: Failure', - DELETE_CHAT_SUCCESS = 'Delete Chat: Success', - DELETE_CHAT_FAILURE = 'Delete Chat: Failure', - SET_CHAT_CATEGORY_SUCCESS = 'Set Chat Category: Success', - SET_CHAT_CATEGORY_FAILURE = 'Set Chat Category: Failure', - BLOCK_USER_SUCCESS = 'Block User: Success', - BLOCK_USER_FAILURE = 'Block User: Failure', - CHANGE_INBOX_SETTINGS_SUCCESS = 'Change Inbox Settings: Success', - CHANGE_INBOX_SETTINGS_FAILURE = 'Change Inbox Settings: Failure', - SEND_MESSAGE_REACTION_SUCCESS = 'Send Message Reaction: Success', - SEND_MESSAGE_REACTION_FAILURE = 'Send Message Reaction: Failure', MESSAGE_UNFURL_TRACK = 'Message Unfurl: Track', MESSAGE_UNFURL_PLAYLIST = 'Message Unfurl: Playlist', CHAT_REPORT_USER = 'Report User: Chat', @@ -405,80 +246,9 @@ export enum Name { // Export Private Key EXPORT_PRIVATE_KEY_LINK_CLICKED = 'Export Private Key: Settings Link Clicked', - EXPORT_PRIVATE_KEY_PAGE_VIEWED = 'Export Private Key: Page Viewed', - EXPORT_PRIVATE_KEY_MODAL_OPENED = 'Export Private Key: Modal Opened', - EXPORT_PRIVATE_KEY_PUBLIC_ADDRESS_COPIED = 'Export Private Key: Public Address Copied', - EXPORT_PRIVATE_KEY_PRIVATE_KEY_COPIED = 'Export Private Key: Private Key Copied', - - // Manager Mode - MANAGER_MODE_SWITCH_ACCOUNT = 'Manager Mode: Switch Account', - MANAGER_MODE_ACCEPT_INVITE = 'Manager Mode: Accept Invite', - MANAGER_MODE_CANCEL_INVITE = 'Manager Mode: Cancel Invite', - MANAGER_MODE_REJECT_INVITE = 'Manager Mode: Reject Invite', - MANAGER_MODE_REMOVE_MANAGER = 'Manager Mode: Remove Manager', // Comments - COMMENTS_CREATE_COMMENT = 'Comments: Create Comment', - COMMENTS_UPDATE_COMMENT = 'Comments: Update Comment', - COMMENTS_DELETE_COMMENT = 'Comments: Delete Comment', - COMMENTS_FOCUS_COMMENT_INPUT = 'Comments: Focus Comment Input', - COMMENTS_CLICK_REPLY_BUTTON = 'Comments: Click Reply Button', - COMMENTS_LIKE_COMMENT = 'Comments: Like Comment', - COMMENTS_UNLIKE_COMMENT = 'Comments: Unlike Comment', - COMMENTS_REPORT_COMMENT = 'Comments: Report Comment', - COMMENTS_ADD_MENTION = 'Comments: Add Mention', - COMMENTS_CLICK_MENTION = 'Comments: Click Mention', - COMMENTS_ADD_TIMESTAMP = 'Comments: Add Timestamp', - COMMENTS_CLICK_TIMESTAMP = 'Comments: Click Timestamp', - COMMENTS_ADD_LINK = 'Comments: Add Link', - COMMENTS_CLICK_LINK = 'Comments: Click Link', COMMENTS_NOTIFICATION_OPEN = 'Comments: Notification Open', - COMMENTS_MUTE_USER = 'Comments: Mute User', - COMMENTS_UNMUTE_USER = 'Comments: Unmute User', - COMMENTS_PIN_COMMENT = 'Comments: Pin Comment', - COMMENTS_UNPIN_COMMENT = 'Comments: Unpin Comment', - COMMENTS_LOAD_MORE_COMMENTS = 'Comments: Load More Comments', - COMMENTS_LOAD_NEW_COMMENTS = 'Comments: Load New Comments', - COMMENTS_SHOW_REPLIES = 'Comments: Show Replies', - COMMENTS_HIDE_REPLIES = 'Comments: Hide Replies', - COMMENTS_APPLY_SORT = 'Comments: Apply Sort', - COMMENTS_CLICK_COMMENT_STAT = 'Comments: Click Comment Stat', - COMMENTS_OPEN_COMMENT_OVERFLOW_MENU = 'Comments: Open Comment Overflow Menu', - COMMENTS_TURN_ON_NOTIFICATIONS_FOR_COMMENT = 'Comments: Turn On Notifications for Comment', - COMMENTS_TURN_OFF_NOTIFICATIONS_FOR_COMMENT = 'Comments: Turn Off Notifications for Comment', - COMMENTS_OPEN_TRACK_OVERFLOW_MENU = 'Comments: Open Track Overflow Menu', - COMMENTS_TURN_ON_NOTIFICATIONS_FOR_TRACK = 'Comments: Turn On Notifications for Track', - COMMENTS_TURN_OFF_NOTIFICATIONS_FOR_TRACK = 'Comments: Turn Off Notifications for Track', - COMMENTS_DISABLE_TRACK_COMMENTS = 'Comments: Disable Track Comments', - COMMENTS_OPEN_COMMENT_DRAWER = 'Comments: Open Comment Drawer', - COMMENTS_CLOSE_COMMENT_DRAWER = 'Comments: Close Comment Drawer', - COMMENTS_OPEN_AUTH_MODAL = 'Comments: Open Auth Modal', - COMMENTS_OPEN_INSTALL_APP_MODAL = 'Comments: Open Install App Modal', - - // Recent Comments - RECENT_COMMENTS_CLICK = 'Recent Comments: Click', - COMMENTS_HISTORY_CLICK = 'Comments History: Click', - COMMENTS_HISTORY_DRAWER_OPEN = 'Comments History: Drawer Open', - - // Track Replace - TRACK_REPLACE_DOWNLOAD = 'Track Replace: Download', - TRACK_REPLACE_PREVIEW = 'Track Replace: Preview', - TRACK_REPLACE_REPLACE = 'Track Replace: Replace', - - // Remix Contests - REMIX_CONTEST_CREATE = 'Remix Contest: Create', - REMIX_CONTEST_UPDATE = 'Remix Contest: Update', - REMIX_CONTEST_DELETE = 'Remix Contest: Delete', - REMIX_CONTEST_PICK_WINNERS_OPEN = 'Remix Contest: Pick Winners Open', - REMIX_CONTEST_PICK_WINNERS_FINALIZE = 'Remix Contest: Finalize Winners', - REMIX_CONTEST_VIEW = 'Remix Contest: View', - REMIX_CONTEST_ENTER = 'Remix Contest: Enter', - REMIX_CONTEST_VIEW_SUBMISSIONS = 'Remix Contest: View Submissions', - - // Fan Clubs - BANNER_FAN_CLUBS_LAUNCH_CLICKED = 'Banner Artist Coins Launch Clicked', - BANNER_TRADING_VOLUME_LAUNCH_CLICKED = 'Banner Trading Volume Launch Clicked', - BANNER_YAK_COIN_LAUNCH_CLICKED = 'Banner Yak Coin Launch Clicked', // Fan Club Launchpad LAUNCHPAD_SPLASH_GET_STARTED = 'Launchpad: Get Started Clicked', @@ -526,11 +296,6 @@ type PageView = { route: string } -type AppError = { - eventName: Name.APP_ERROR - errorMessage: string -} - // Create Account export type CreateAccountOpen = { eventName: Name.CREATE_ACCOUNT_OPEN @@ -615,22 +380,6 @@ type SignInWithIncompleteAccount = { handle: string } -// Settings -type SettingsChangeTheme = { - eventName: Name.SETTINGS_CHANGE_THEME - mode: 'dark' | 'light' | 'matrix' | 'auto' -} -type SettingsResetAccountRecovery = { - eventName: Name.SETTINGS_RESEND_ACCOUNT_RECOVERY -} -type SettingsCompleteChangePassword = { - eventName: Name.SETTINGS_COMPLETE_CHANGE_PASSWORD - status: 'success' | 'failure' -} -type SettingsLogOut = { - eventName: Name.SETTINGS_LOG_OUT -} - // Error type ErrorPage = { eventName: Name.ERROR_PAGE @@ -638,34 +387,9 @@ type ErrorPage = { name: string route?: string } -type NotFoundPage = { - eventName: Name.NOT_FOUND_PAGE -} - -// Visualizer -type VisualizerOpen = { - eventName: Name.VISUALIZER_OPEN -} -type VisualizerClose = { - eventName: Name.VISUALIZER_CLOSE -} - type AccountHealthMeterFull = { eventName: Name.ACCOUNT_HEALTH_METER_FULL } -type AccountHealthUploadCoverPhoto = { - eventName: Name.ACCOUNT_HEALTH_UPLOAD_COVER_PHOTO - source: 'original' | 'unsplash' | 'url' -} -type AccountHealthUploadProfilePhoto = { - eventName: Name.ACCOUNT_HEALTH_UPLOAD_PROFILE_PICTURE - source: 'original' | 'unsplash' | 'url' -} -type AccountHealthDownloadDesktop = { - eventName: Name.ACCOUNT_HEALTH_DOWNLOAD_DESKTOP - source: 'banner' | 'settings' -} - // Social export enum ShareSource { TILE = 'tile', @@ -759,10 +483,6 @@ type Unfavorite = { source: FavoriteSource id: string } -type ArtistPickSelectTrack = { - eventName: Name.ARTIST_PICK_SELECT_TRACK - id: string -} type Follow = { eventName: Name.FOLLOW id: string @@ -787,64 +507,12 @@ export enum CreatePlaylistSource { PROFILE_PAGE = 'profile page' } -type PlaylistAdd = { - eventName: Name.PLAYLIST_ADD - trackId: string - playlistId: string -} -type PlaylistOpenCreate = { - eventName: Name.PLAYLIST_OPEN_CREATE - source: CreatePlaylistSource -} -type PlaylistStartCreate = { - eventName: Name.PLAYLIST_START_CREATE - source: CreatePlaylistSource - artworkSource: 'unsplash' | 'original' -} -type PlaylistCompleteCreate = { - eventName: Name.PLAYLIST_COMPLETE_CREATE - source: CreatePlaylistSource - status: 'success' | 'failure' -} -type PlaylistMakePublic = { - eventName: Name.PLAYLIST_MAKE_PUBLIC - id: string -} - -type PlaylistOpenEditFromLibrary = { - eventName: Name.PLAYLIST_OPEN_EDIT_FROM_LIBRARY -} - -type Delete = { - eventName: Name.DELETE - kind: PlayableType - id: string -} - // Folder -type FolderOpenEdit = { - eventName: Name.FOLDER_OPEN_EDIT -} - -type FolderSubmitEdit = { - eventName: Name.FOLDER_SUBMIT_EDIT -} - type FolderDelete = { eventName: Name.FOLDER_DELETE } -type FolderCancelEdit = { - eventName: Name.FOLDER_CANCEL_EDIT -} - -// Embed -type EmbedOpen = { - eventName: Name.EMBED_OPEN - kind: PlayableType - id: string -} type EmbedCopy = { eventName: Name.EMBED_COPY kind: PlayableType @@ -862,17 +530,6 @@ type TrackUploadStartUploading = { count: number kind: 'single_track' | 'multi_track' | 'album' | 'playlist' } -type TrackUploadTrackUploading = { - eventName: Name.TRACK_UPLOAD_TRACK_UPLOADING - artworkSource: 'unsplash' | 'original' - downloadable: 'yes' | 'no' | 'follow' - trackId: number - size: number - fileType: string - name: string - genre: string - mood?: string -} type TrackUploadCompleteUpload = { eventName: Name.TRACK_UPLOAD_COMPLETE_UPLOAD count: number @@ -890,18 +547,6 @@ type TrackUploadFailure = { error?: string } -type TrackUploadViewTrackPage = { - eventName: Name.TRACK_UPLOAD_VIEW_TRACK_PAGE - uploadType: string -} - -type TrackUploadFollowGated = { - eventName: Name.TRACK_UPLOAD_FOLLOW_GATED - kind: 'tracks' - downloadable: boolean - lossless: boolean -} - type TrackUploadUSDCGated = { eventName: Name.TRACK_UPLOAD_USDC_GATED price: number @@ -910,27 +555,6 @@ type TrackUploadUSDCGated = { lossless: boolean } -type TrackUploadTokenGated = { - eventName: Name.TRACK_UPLOAD_TOKEN_GATED - kind: 'tracks' - downloadable: boolean - lossless: boolean -} - -type TrackUploadFollowGatedDownload = { - eventName: Name.TRACK_UPLOAD_FOLLOW_GATED_DOWNLOAD - kind: 'tracks' - downloadable: boolean - lossless: boolean -} - -type TrackUploadTokenGatedDownload = { - eventName: Name.TRACK_UPLOAD_TOKEN_GATED_DOWNLOAD - kind: 'tracks' - downloadable: boolean - lossless: boolean -} - type TrackUploadUSDCGatedDownload = { eventName: Name.TRACK_UPLOAD_USDC_GATED_DOWNLOAD price: number @@ -939,115 +563,17 @@ type TrackUploadUSDCGatedDownload = { lossless: boolean } -// Track Downloads -type TrackDownloadClickedDownloadAll = { - eventName: Name.TRACK_DOWNLOAD_CLICKED_DOWNLOAD_ALL - parentTrackId: ID - stemTrackIds: ID[] - device: 'web' | 'native' -} - -type TrackDownloadSuccessfulDownloadAll = { - eventName: Name.TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_ALL - device?: 'web' | 'native' -} - -type TrackDownloadFailedDownloadAll = { - eventName: Name.TRACK_DOWNLOAD_FAILED_DOWNLOAD_ALL - device?: 'web' | 'native' -} - -type TrackDownloadClickedDownloadSingle = { - eventName: Name.TRACK_DOWNLOAD_CLICKED_DOWNLOAD_SINGLE - trackId: ID - device: 'web' | 'native' -} - -type TrackDownloadSuccessfulDownloadSingle = { - eventName: Name.TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_SINGLE - device: 'web' | 'native' -} - -type TrackDownloadFailedDownloadSingle = { - eventName: Name.TRACK_DOWNLOAD_FAILED_DOWNLOAD_SINGLE - device: 'web' | 'native' -} - -// Track Edits -type TrackEditAccessChanged = { - eventName: Name.TRACK_EDIT_ACCESS_CHANGED - id: number - from: TrackAccessType - to: TrackAccessType -} - -type TrackEditBpmChanged = { - eventName: Name.TRACK_EDIT_BPM_CHANGED - id: number - from: number - to: number -} - -type TrackEditMusicalKeyChanged = { - eventName: Name.TRACK_EDIT_MUSICAL_KEY_CHANGED - id: number - from: string - to: string -} - -// Collection Edits -type CollectionEditAccessChanged = { - eventName: Name.COLLECTION_EDIT_ACCESS_CHANGED - id: number - from: Nullable - to: Nullable -} - -type CollectionEdit = { - eventName: Name.COLLECTION_EDIT - id: number - from: TrackAccessType - to: TrackAccessType -} - // Unlocked Gated Tracks type USDCGatedTrackUnlocked = { eventName: Name.USDC_PURCHASE_GATED_TRACK_UNLOCKED count: number } -type FollowGatedTrackUnlocked = { - eventName: Name.FOLLOW_GATED_TRACK_UNLOCKED - trackId: number -} - -type TokenGatedTrackUnlocked = { - eventName: Name.TOKEN_GATED_TRACK_UNLOCKED - trackId: number -} - type USDCGatedDownloadTrackUnlocked = { eventName: Name.USDC_PURCHASE_GATED_DOWNLOAD_TRACK_UNLOCKED count: number } -type FollowGatedDownloadTrackUnlocked = { - eventName: Name.FOLLOW_GATED_DOWNLOAD_TRACK_UNLOCKED - trackId: number -} - -type TokenGatedDownloadTrackUnlocked = { - eventName: Name.TOKEN_GATED_DOWNLOAD_TRACK_UNLOCKED - trackId: number -} - -// Trending -type TrendingChangeView = { - eventName: Name.TRENDING_CHANGE_VIEW - timeframe: TimeRange - genre: string -} - // Feed type FeedChangeView = { eventName: Name.FEED_CHANGE_VIEW @@ -1108,52 +634,6 @@ type NotificationsClickTastemaker = { eventName: Name.NOTIFICATIONS_CLICK_TASTEMAKER_TWITTER_SHARE text: string } -type NotificationsToggleSettings = { - eventName: Name.NOTIFICATIONS_TOGGLE_SETTINGS - settings: string - enabled: boolean -} - -// Profile -type ProfilePageTabClick = { - eventName: Name.PROFILE_PAGE_TAB_CLICK - tab: 'tracks' | 'albums' | 'reposts' | 'playlists' -} -type ProfilePageSort = { - eventName: Name.PROFILE_PAGE_SORT - sort: 'recent' | 'popular' -} -type ProfilePageClickInstagram = { - eventName: Name.PROFILE_PAGE_CLICK_INSTAGRAM - handle: string - instagramHandle: string -} -type ProfilePageClickTwitter = { - eventName: Name.PROFILE_PAGE_CLICK_TWITTER - handle: string - twitterHandle: string -} -type ProfilePageClickTikTok = { - eventName: Name.PROFILE_PAGE_CLICK_TIKTOK - handle: string - tikTokHandle: string -} -type ProfilePageClickWebsite = { - eventName: Name.PROFILE_PAGE_CLICK_WEBSITE - handle: string - website: string -} -type ProfilePageShownArtistRecommendations = { - eventName: Name.PROFILE_PAGE_SHOWN_ARTIST_RECOMMENDATIONS - userId: number -} - -// Track Page -type TrackPagePlayMore = { - eventName: Name.TRACK_PAGE_PLAY_MORE - id: ID -} - // Playback export enum PlaybackSource { PLAYBAR = 'playbar', @@ -1200,11 +680,6 @@ type PlaylistPlay = { isPreview?: boolean } -type BufferingTime = { - eventName: Name.BUFFERING_TIME - duration: number -} - // Play Queue type PlayQueueOpen = { eventName: Name.PLAY_QUEUE_OPEN @@ -1246,18 +721,6 @@ type PlayQueueClear = { queueLength: number } -// Linking -type LinkClicking = { - eventName: Name.LINK_CLICKING - url: string - source: 'profile page' | 'track page' | 'collection page' | 'left nav' -} -type TagClicking = { - eventName: Name.TAG_CLICKING - tag: string - source: 'profile page' | 'track page' | 'collection page' -} - export enum ModalSource { TrackTile = 'track tile', CollectionTile = 'collection tile', @@ -1294,27 +757,6 @@ export type SearchSource = | 'search results page' | 'more results page' -// Search -type SearchTerm = { - eventName: Name.SEARCH_SEARCH - term: string - source: SearchSource -} - -type SearchTag = { - eventName: Name.SEARCH_TAG_SEARCH - tag: string - source: SearchSource -} - -type SearchResultSelect = { - eventName: Name.SEARCH_RESULT_SELECT - term: string - source: SearchSource - id: ID - kind: 'track' | 'profile' | 'playlist' | 'album' -} - // Explore export type ExploreSectionName = | 'Recommended Tracks' @@ -1341,12 +783,6 @@ export type ExploreSectionName = | 'Feeling Lucky' | 'Recent Searches' -type ExploreSectionView = { - eventName: Name.EXPLORE_SECTION_VIEW - section: ExploreSectionName - source: 'web' | 'mobile' -} - type ExploreSectionClick = { eventName: Name.EXPLORE_SECTION_CLICK section: ExploreSectionName @@ -1402,46 +838,6 @@ type StemCompleteUpload = { category: string } -type StemDelete = { - eventName: Name.STEM_DELETE - id: number - parent_track_id: number -} - -type RemixNewRemix = { - eventName: Name.REMIX_NEW_REMIX - id: number - handle: string - title: string - parent_track_id: number - parent_track_title: string - parent_track_user_handle: string -} - -type RemixCosign = { - eventName: Name.REMIX_COSIGN - id: number - handle: string - action: 'reposted' | 'favorited' - original_track_id: number - original_track_title: string -} - -type RemixCosignIndicator = { - eventName: Name.REMIX_COSIGN_INDICATOR - id: number - handle: string - action: 'reposted' | 'favorited' - original_track_id: number - original_track_title: string -} - -type RemixHide = { - eventName: Name.REMIX_HIDE - id: number - handle: string -} - /** Where in the app the send was initiated (for analytics parity with legacy Tip Audio) */ export type SendAudioSource = | 'send_tokens_modal' @@ -1473,13 +869,6 @@ type SendAudioFailure = { recipientWallet?: WalletAddress } -type PlaylistLibraryReorder = { - eventName: Name.PLAYLIST_LIBRARY_REORDER - // Whether or not the reorder contains newly created temp playlists - containsTemporaryPlaylists: boolean - kind: PlaylistLibraryKind -} - type PlaylistLibraryMovePlaylistIntoFolder = { eventName: Name.PLAYLIST_LIBRARY_MOVE_PLAYLIST_INTO_FOLDER } @@ -1492,52 +881,6 @@ type PlaylistLibraryMovePlaylistOutOfFolder = { eventName: Name.PLAYLIST_LIBRARY_MOVE_PLAYLIST_OUT_OF_FOLDER } -type DeactivateAccountPageView = { - eventName: Name.DEACTIVATE_ACCOUNT_PAGE_VIEW -} -type DeactivateAccountRequest = { - eventName: Name.DEACTIVATE_ACCOUNT_REQUEST -} -type DeactivateAccountSuccess = { - eventName: Name.DEACTIVATE_ACCOUNT_SUCCESS -} -type DeactivateAccountFailure = { - eventName: Name.DEACTIVATE_ACCOUNT_FAILURE -} - -type CreateUserBankSuccess = { - eventName: Name.CREATE_USER_BANK_SUCCESS - mint: string - recipientEthAddress: string -} - -type CreateUserBankFailure = { - eventName: Name.CREATE_USER_BANK_FAILURE - mint: string - recipientEthAddress: string - errorCode: string - errorMessage: string -} - -type RewardsClaimDetailsOpened = { - eventName: Name.REWARDS_CLAIM_DETAILS_OPENED - challengeId: string -} - -type RewardsClaimRequest = { - eventName: Name.REWARDS_CLAIM_REQUEST - challengeId: string - specifier: string - amount: number -} - -type RewardsClaimSuccess = { - eventName: Name.REWARDS_CLAIM_SUCCESS - challengeId: string - specifier: string - amount: number -} - type RewardsClaimAllRequest = { eventName: Name.REWARDS_CLAIM_ALL_REQUEST count: number @@ -1546,11 +889,6 @@ type RewardsClaimAllSuccess = { eventName: Name.REWARDS_CLAIM_ALL_SUCCESS count: number } -type RewardsClaimAllFailure = { - eventName: Name.REWARDS_CLAIM_ALL_FAILURE - count: number -} - type AudiusOauthStart = { eventName: Name.AUDIUS_OAUTH_START redirectUriParam: string | string[] @@ -1582,66 +920,6 @@ type AudiusOauthError = { error: string } -type DeveloperAppCreateSubmit = { - eventName: Name.DEVELOPER_APP_CREATE_SUBMIT - name?: string - description?: string -} - -type DeveloperAppCreateSuccess = { - eventName: Name.DEVELOPER_APP_CREATE_SUCCESS - name: string - apiKey: string -} - -type DeveloperAppCreateError = { - eventName: Name.DEVELOPER_APP_CREATE_ERROR - error?: string -} - -type DeveloperAppEditSubmit = { - eventName: Name.DEVELOPER_APP_EDIT_SUBMIT - name?: string - description?: string -} - -type DeveloperAppEditSuccess = { - eventName: Name.DEVELOPER_APP_EDIT_SUCCESS - name: string - apiKey: string -} - -type DeveloperAppEditError = { - eventName: Name.DEVELOPER_APP_EDIT_ERROR - error?: string -} - -type DeveloperAppDeleteSuccess = { - eventName: Name.DEVELOPER_APP_DELETE_SUCCESS - name?: string - apiKey?: string -} - -type DeveloperAppDeleteError = { - eventName: Name.DEVELOPER_APP_DELETE_ERROR - name?: string - apiKey?: string - error?: string -} - -type AuthorizedAppRemoveSuccess = { - eventName: Name.AUTHORIZED_APP_REMOVE_SUCCESS - name?: string - apiKey?: string -} - -type AuthorizedAppRemoveError = { - eventName: Name.AUTHORIZED_APP_REMOVE_ERROR - name?: string - apiKey?: string - error?: string -} - // Buy USDC type BuyUSDCOnRampOpened = { eventName: Name.BUY_USDC_ON_RAMP_OPENED @@ -1916,85 +1194,6 @@ type PurchaseContentUSDCUserBankCopied = { address: string } -type BannerTOSClicked = { - eventName: Name.BANNER_TOS_CLICKED -} - -type BannerFanClubsLaunchClicked = { - eventName: Name.BANNER_FAN_CLUBS_LAUNCH_CLICKED -} - -type BannerTradingVolumeLaunchClicked = { - eventName: Name.BANNER_TRADING_VOLUME_LAUNCH_CLICKED -} - -type RateCtaDisplayed = { - eventName: Name.RATE_CTA_DISPLAYED -} - -type RateCtaResponseNo = { - eventName: Name.RATE_CTA_RESPONSE_NO -} - -type RateCtaResponseYes = { - eventName: Name.RATE_CTA_RESPONSE_YES -} - -type ConnectWalletNewWalletStart = { - eventName: Name.CONNECT_WALLET_NEW_WALLET_START -} - -type ConnectWalletNewWalletConnecting = { - eventName: Name.CONNECT_WALLET_NEW_WALLET_CONNECTING - chain: Chain - walletAddress: WalletAddress -} - -type ConnectWalletNewWalletConnected = { - eventName: Name.CONNECT_WALLET_NEW_WALLET_CONNECTED - chain: Chain - walletAddress: WalletAddress -} - -type ConnectWalletAlreadyAssociated = { - eventName: Name.CONNECT_WALLET_ALREADY_ASSOCIATED - chain: Chain - walletAddress: WalletAddress -} - -type ConnectWalletError = { - eventName: Name.CONNECT_WALLET_ERROR - error: string -} - -type ChatBlastCTAClicked = { - eventName: Name.CHAT_BLAST_CTA_CLICKED -} - -type CreateChatSuccess = { - eventName: Name.CREATE_CHAT_SUCCESS -} - -type CreateChatFailure = { - eventName: Name.CREATE_CHAT_FAILURE -} - -type CreateChatBlastSuccess = { - eventName: Name.CREATE_CHAT_BLAST_SUCCESS - audience: string - audienceContentType?: string - audienceContentId?: ID - sentBy: ID -} - -type CreateChatBlastFailure = { - eventName: Name.CREATE_CHAT_BLAST_FAILURE - audience: string - audienceContentType?: string - audienceContentId?: ID - sentBy?: ID -} - type ChatBlastMessageSent = { eventName: Name.CHAT_BLAST_MESSAGE_SENT audience: string @@ -2002,73 +1201,10 @@ type ChatBlastMessageSent = { audienceContentId?: ID } -type ChatBlastMessageViewed = { - eventName: Name.CHAT_BLAST_MESSAGE_VIEWED - isNativeMobile?: boolean - chatId: string - audience: string - audienceContentType?: string - audienceContentId?: ID -} - type SendMessageSuccess = { eventName: Name.SEND_MESSAGE_SUCCESS } -type SendMessageFailure = { - eventName: Name.SEND_MESSAGE_FAILURE -} - -type DeleteChatSuccess = { - eventName: Name.DELETE_CHAT_SUCCESS -} - -type DeleteChatFailure = { - eventName: Name.DELETE_CHAT_FAILURE -} - -type SetChatCategorySuccess = { - eventName: Name.SET_CHAT_CATEGORY_SUCCESS - category: 'priority' | 'general' | null -} - -type SetChatCategoryFailure = { - eventName: Name.SET_CHAT_CATEGORY_FAILURE - category: 'priority' | 'general' | null -} - -type BlockUserSuccess = { - eventName: Name.BLOCK_USER_SUCCESS - blockedUserId: ID -} - -type BlockUserFailure = { - eventName: Name.BLOCK_USER_FAILURE - blockedUserId: ID -} - -type ChangeInboxSettingsSuccess = { - eventName: Name.CHANGE_INBOX_SETTINGS_SUCCESS - permission?: ChatPermission - permitList?: ChatPermission[] -} - -type ChangeInboxSettingsFailure = { - eventName: Name.CHANGE_INBOX_SETTINGS_FAILURE - permission?: ChatPermission - permitList?: ChatPermission[] -} - -type SendMessageReactionSuccess = { - eventName: Name.SEND_MESSAGE_REACTION_SUCCESS - reaction: string | null -} - -type SendMessageReactionFailure = { - eventName: Name.SEND_MESSAGE_REACTION_FAILURE - reaction: string | null -} - type MessageUnfurlTrack = { eventName: Name.MESSAGE_UNFURL_TRACK } @@ -2099,334 +1235,12 @@ type ExportPrivateKeyLinkClicked = { userId?: ID } -type ExportPrivateKeyPageOpened = { - eventName: Name.EXPORT_PRIVATE_KEY_PAGE_VIEWED - handle: string - userId: ID -} - -type ExportPrivateKeyModalOpened = { - eventName: Name.EXPORT_PRIVATE_KEY_MODAL_OPENED - handle: string - userId: ID -} - -type ExportPrivateKeyPublicAddressCopied = { - eventName: Name.EXPORT_PRIVATE_KEY_PUBLIC_ADDRESS_COPIED - handle: string - userId: ID -} - -type ExportPrivateKeyPrivateKeyCopied = { - eventName: Name.EXPORT_PRIVATE_KEY_PRIVATE_KEY_COPIED - handle: string - userId: ID -} - -// Manager Mode -type ManagerModeSwitchAccount = { - eventName: Name.MANAGER_MODE_SWITCH_ACCOUNT - managedUserId: ID -} - -type ManagerModeAcceptInvite = { - eventName: Name.MANAGER_MODE_ACCEPT_INVITE - managedUserId: ID -} - -type ManagerModeCancelInvite = { - eventName: Name.MANAGER_MODE_CANCEL_INVITE - managerId: ID -} - -type ManagerModeRejectInvite = { - eventName: Name.MANAGER_MODE_REJECT_INVITE - managedUserId: ID -} - -type ManagerModeRemoveManager = { - eventName: Name.MANAGER_MODE_REMOVE_MANAGER - managerId: ID -} - -export type CommentsCreateComment = { - eventName: Name.COMMENTS_CREATE_COMMENT - parentCommentId?: ID - timestamp?: number - trackId: ID -} - -export type CommentsUpdateComment = { - eventName: Name.COMMENTS_UPDATE_COMMENT - commentId: ID -} - -export type CommentsDeleteComment = { - eventName: Name.COMMENTS_DELETE_COMMENT - commentId: ID -} - -export type CommentsFocusCommentInput = { - eventName: Name.COMMENTS_FOCUS_COMMENT_INPUT - trackId: ID - source: 'comment_input' | 'comment_preview' -} - -export type CommentsClickReplyButton = { - eventName: Name.COMMENTS_CLICK_REPLY_BUTTON - commentId: ID -} - -export type CommentsLikeComment = { - eventName: Name.COMMENTS_LIKE_COMMENT - commentId: ID -} - -export type CommentsUnlikeComment = { - eventName: Name.COMMENTS_UNLIKE_COMMENT - commentId: ID -} - -export type CommentsAddMention = { - eventName: Name.COMMENTS_ADD_MENTION - userId: ID -} - -export type CommentsClickMention = { - eventName: Name.COMMENTS_CLICK_MENTION - commentId: ID - userId: ID -} - -export type CommentsAddTimestamp = { - eventName: Name.COMMENTS_ADD_TIMESTAMP - timestamp: number -} - -export type CommentsClickTimestamp = { - eventName: Name.COMMENTS_CLICK_TIMESTAMP - commentId: ID - timestamp: number -} - -export type CommentsAddLink = { - eventName: Name.COMMENTS_ADD_LINK - entityId?: ID - kind: 'track' | 'collection' | 'user' | 'other' -} - -export type CommentsClickLink = { - eventName: Name.COMMENTS_CLICK_LINK - commentId: ID - kind: 'track' | 'collection' | 'user' | 'other' - entityId?: ID -} - export type CommentsNotificationOpen = { eventName: Name.COMMENTS_NOTIFICATION_OPEN commentId: ID notificationType: 'comment' | 'reaction' | 'thread' | 'mention' } -export type CommentsReportComment = { - eventName: Name.COMMENTS_REPORT_COMMENT - commentId: ID - commentOwnerId: ID - isRemoved: boolean -} - -export type CommentsMuteUser = { - eventName: Name.COMMENTS_MUTE_USER - userId: ID -} - -export type CommentsUnmuteUser = { - eventName: Name.COMMENTS_UNMUTE_USER - userId: ID -} - -export type CommentsPinComment = { - eventName: Name.COMMENTS_PIN_COMMENT - trackId: ID - commentId: ID -} - -export type CommentsUnpinComment = { - eventName: Name.COMMENTS_UNPIN_COMMENT - trackId: ID - commentId: ID -} - -export type CommentsLoadMoreComments = { - eventName: Name.COMMENTS_LOAD_MORE_COMMENTS - trackId: ID - offset: number -} - -export type CommentsLoadNewComments = { - eventName: Name.COMMENTS_LOAD_NEW_COMMENTS - trackId: ID -} - -export type CommentsShowReplies = { - eventName: Name.COMMENTS_SHOW_REPLIES - commentId: ID - trackId: ID -} - -export type CommentsHideReplies = { - eventName: Name.COMMENTS_HIDE_REPLIES - commentId: ID - trackId: ID -} - -export type CommentsApplySort = { - eventName: Name.COMMENTS_APPLY_SORT - sortType: 'top' | 'newest' | 'timestamp' -} - -export type CommentsClickCommentStat = { - eventName: Name.COMMENTS_CLICK_COMMENT_STAT - trackId: ID - source: 'lineup' | 'track_page' -} - -export type CommentsOpenCommentOverflowMenu = { - eventName: Name.COMMENTS_OPEN_COMMENT_OVERFLOW_MENU - commentId: ID -} - -export type CommentsTurnOnNotificationsForComment = { - eventName: Name.COMMENTS_TURN_ON_NOTIFICATIONS_FOR_COMMENT - commentId: ID -} - -export type CommentsTurnOffNotificationsForComment = { - eventName: Name.COMMENTS_TURN_OFF_NOTIFICATIONS_FOR_COMMENT - commentId: ID -} - -export type CommentsOpenTrackOverflowMenu = { - eventName: Name.COMMENTS_OPEN_TRACK_OVERFLOW_MENU - trackId: ID -} - -export type CommentsTurnOnNotificationsForTrack = { - eventName: Name.COMMENTS_TURN_ON_NOTIFICATIONS_FOR_TRACK - trackId: ID -} - -export type CommentsTurnOffNotificationsForTrack = { - eventName: Name.COMMENTS_TURN_OFF_NOTIFICATIONS_FOR_TRACK - trackId: ID -} - -export type CommentsDisableTrackComments = { - eventName: Name.COMMENTS_DISABLE_TRACK_COMMENTS - trackId: ID -} - -type CommentsOpenCommentDrawer = { - eventName: Name.COMMENTS_OPEN_COMMENT_DRAWER - trackId: ID -} - -type CommentsCloseCommentDrawer = { - eventName: Name.COMMENTS_CLOSE_COMMENT_DRAWER - trackId: ID -} - -export type CommentsOpenAuthModal = { - eventName: Name.COMMENTS_OPEN_AUTH_MODAL - trackId: ID -} - -export type CommentsOpenInstallAppModal = { - eventName: Name.COMMENTS_OPEN_INSTALL_APP_MODAL - trackId: ID -} - -export type CommentsHistoryClick = { - eventName: Name.COMMENTS_HISTORY_CLICK - commentId: ID - userId: ID -} - -export type CommentsHistoryDrawerOpen = { - eventName: Name.COMMENTS_HISTORY_DRAWER_OPEN - userId: ID | undefined -} - -export type RecentCommentsClick = { - eventName: Name.RECENT_COMMENTS_CLICK - commentId: ID - userId: ID -} - -export type TrackReplaceDownload = { - eventName: Name.TRACK_REPLACE_DOWNLOAD - trackId?: ID -} - -export type TrackReplaceReplace = { - eventName: Name.TRACK_REPLACE_REPLACE - trackId?: ID - source: 'upload' | 'edit' -} - -export type TrackReplacePreview = { - eventName: Name.TRACK_REPLACE_PREVIEW - trackId?: ID - source: 'upload' | 'edit' -} - -export type RemixContestCreate = { - eventName: Name.REMIX_CONTEST_CREATE - trackId: ID -} - -export type RemixContestUpdate = { - eventName: Name.REMIX_CONTEST_UPDATE - remixContestId: ID - trackId: ID -} - -export type RemixContestDelete = { - eventName: Name.REMIX_CONTEST_DELETE - remixContestId: ID - trackId: ID -} - -export type RemixContestPickWinnersOpen = { - eventName: Name.REMIX_CONTEST_PICK_WINNERS_OPEN - remixContestId: ID - trackId: ID -} - -export type RemixContestPickWinnersFinalize = { - eventName: Name.REMIX_CONTEST_PICK_WINNERS_FINALIZE - remixContestId: ID - trackId: ID -} - -export type RemixContestView = { - eventName: Name.REMIX_CONTEST_VIEW - remixContestId: ID - trackId: ID -} - -export type RemixContestEnter = { - eventName: Name.REMIX_CONTEST_ENTER - remixContestId: ID - trackId: ID -} - -export type RemixContestViewSubmissions = { - eventName: Name.REMIX_CONTEST_VIEW_SUBMISSIONS - remixContestId: ID - trackId: ID -} - // Fan Club Launchpad export type LaunchpadSplashGetStarted = { eventName: Name.LAUNCHPAD_SPLASH_GET_STARTED @@ -2657,7 +1471,6 @@ export type LaunchpadClaimVestedCoinsWalletConnected = { export type BaseAnalyticsEvent = { type: typeof ANALYTICS_TRACK_EVENT } export type AllTrackingEvents = - | AppError | CreateAccountOpen | CreateAccountCompleteEmail | CreateAccountCompleteCreating @@ -2673,63 +1486,23 @@ export type AllTrackingEvents = | SignInStart | SignInFinish | SignInWithIncompleteAccount - | SettingsChangeTheme - | SettingsResetAccountRecovery - | SettingsCompleteChangePassword - | SettingsLogOut - | VisualizerOpen - | VisualizerClose | AccountHealthMeterFull - | AccountHealthUploadCoverPhoto - | AccountHealthUploadProfilePhoto - | AccountHealthDownloadDesktop | Share | ShareToTwitter | Repost | UndoRepost | Favorite | Unfavorite - | ArtistPickSelectTrack - | PlaylistAdd - | PlaylistOpenCreate - | PlaylistStartCreate - | PlaylistCompleteCreate - | PlaylistMakePublic - | PlaylistOpenEditFromLibrary - | Delete - | EmbedOpen | EmbedCopy | TrackUploadOpen | TrackUploadStartUploading - | TrackUploadTrackUploading | TrackUploadCompleteUpload - | TrackUploadFollowGated | TrackUploadUSDCGated - | TrackUploadTokenGated - | TrackUploadFollowGatedDownload | TrackUploadUSDCGatedDownload - | TrackUploadTokenGatedDownload - | TrackDownloadClickedDownloadAll - | TrackDownloadSuccessfulDownloadAll - | TrackDownloadFailedDownloadAll - | TrackDownloadClickedDownloadSingle - | TrackDownloadSuccessfulDownloadSingle - | TrackDownloadFailedDownloadSingle - | TrackEditAccessChanged - | TrackEditBpmChanged - | TrackEditMusicalKeyChanged - | CollectionEditAccessChanged - | CollectionEdit | TrackUploadSuccess | TrackUploadFailure - | TrackUploadViewTrackPage | USDCGatedTrackUnlocked - | FollowGatedTrackUnlocked - | TokenGatedTrackUnlocked | USDCGatedDownloadTrackUnlocked - | FollowGatedDownloadTrackUnlocked - | TokenGatedDownloadTrackUnlocked - | TrendingChangeView | FeedChangeView | NotificationsOpen | NotificationsOpenPushNotification @@ -2743,19 +1516,9 @@ export type AllTrackingEvents = | NotificationsClickTrendingUnderground | NotificationsClickUSDCPurchaseBuyer | NotificationsClickTastemaker - | NotificationsToggleSettings - | ProfilePageTabClick - | ProfilePageSort - | ProfilePageClickInstagram - | ProfilePageClickTwitter - | ProfilePageClickTikTok - | ProfilePageClickWebsite - | ProfilePageShownArtistRecommendations - | TrackPagePlayMore | PlaybackPlay | PlaybackPause | PlaylistPlay - | BufferingTime | PlayQueueOpen | PlayQueueClose | PlayQueueAddTrack @@ -2765,52 +1528,26 @@ export type AllTrackingEvents = | PlayQueueClear | Follow | Unfollow - | LinkClicking - | TagClicking | ModalOpened | ModalClosed - | SearchTerm - | SearchTag - | SearchResultSelect - | ExploreSectionView | ExploreSectionClick | WeeklyRotationBannerView | WeeklyRotationBannerClick | WeeklyRotationPageView | WeeklyRotationPlayAll | ErrorPage - | NotFoundPage | PageView | BrowserNotificationSetting | TweetFirstUpload | StemCompleteUpload - | StemDelete - | RemixNewRemix - | RemixCosign - | RemixCosignIndicator - | RemixHide | SendAudioSuccess | SendAudioFailure - | PlaylistLibraryReorder | PlaylistLibraryMovePlaylistIntoFolder | PlaylistLibraryAddPlaylistToFolder | PlaylistLibraryMovePlaylistOutOfFolder - | DeactivateAccountPageView - | DeactivateAccountRequest - | DeactivateAccountSuccess - | DeactivateAccountFailure - | CreateUserBankSuccess - | CreateUserBankFailure - | RewardsClaimDetailsOpened - | RewardsClaimRequest - | RewardsClaimSuccess | RewardsClaimAllRequest | RewardsClaimAllSuccess - | RewardsClaimAllFailure - | FolderOpenEdit - | FolderSubmitEdit | FolderDelete - | FolderCancelEdit | AudiusOauthStart | AudiusOauthComplete | AudiusOauthSubmit @@ -2860,111 +1597,15 @@ export type AllTrackingEvents = | PurchaseContentTwitterShare | PurchaseContentTOSClicked | PurchaseContentUSDCUserBankCopied - | BannerTOSClicked - | BannerFanClubsLaunchClicked - | BannerTradingVolumeLaunchClicked - | RateCtaDisplayed - | RateCtaResponseNo - | RateCtaResponseYes - | ConnectWalletNewWalletStart - | ConnectWalletNewWalletConnecting - | ConnectWalletNewWalletConnected - | ConnectWalletAlreadyAssociated - | ConnectWalletError - | ChatBlastCTAClicked | ChatBlastMessageSent - | ChatBlastMessageViewed - | CreateChatSuccess - | CreateChatFailure - | CreateChatBlastSuccess - | CreateChatBlastFailure | SendMessageSuccess - | SendMessageFailure - | DeleteChatSuccess - | DeleteChatFailure - | SetChatCategorySuccess - | SetChatCategoryFailure - | BlockUserSuccess - | BlockUserFailure - | ChangeInboxSettingsSuccess - | ChangeInboxSettingsFailure - | SendMessageReactionSuccess - | SendMessageReactionFailure | MessageUnfurlTrack | MessageUnfurlPlaylist | ChatReportUser - | DeveloperAppCreateSubmit - | DeveloperAppCreateSuccess - | DeveloperAppCreateError - | DeveloperAppEditSubmit - | DeveloperAppEditSuccess - | DeveloperAppEditError - | DeveloperAppDeleteSuccess - | DeveloperAppDeleteError - | AuthorizedAppRemoveSuccess - | AuthorizedAppRemoveError | ChatEntryPoint | ChatWebsocketError | ExportPrivateKeyLinkClicked - | ExportPrivateKeyPageOpened - | ExportPrivateKeyModalOpened - | ExportPrivateKeyPublicAddressCopied - | ExportPrivateKeyPrivateKeyCopied - | ManagerModeSwitchAccount - | ManagerModeAcceptInvite - | ManagerModeCancelInvite - | ManagerModeRejectInvite - | ManagerModeRemoveManager - | CommentsCreateComment - | CommentsUpdateComment - | CommentsDeleteComment - | CommentsFocusCommentInput - | CommentsClickReplyButton - | CommentsLikeComment - | CommentsUnlikeComment - | CommentsReportComment - | CommentsAddMention - | CommentsClickMention - | CommentsAddTimestamp - | CommentsClickTimestamp - | CommentsAddLink - | CommentsClickLink | CommentsNotificationOpen - | CommentsMuteUser - | CommentsUnmuteUser - | CommentsPinComment - | CommentsUnpinComment - | CommentsLoadMoreComments - | CommentsLoadNewComments - | CommentsShowReplies - | CommentsHideReplies - | CommentsApplySort - | CommentsClickCommentStat - | CommentsOpenCommentOverflowMenu - | CommentsTurnOffNotificationsForComment - | CommentsTurnOnNotificationsForComment - | CommentsOpenTrackOverflowMenu - | CommentsTurnOnNotificationsForTrack - | CommentsTurnOffNotificationsForTrack - | CommentsDisableTrackComments - | CommentsOpenCommentDrawer - | CommentsCloseCommentDrawer - | CommentsOpenAuthModal - | CommentsOpenInstallAppModal - | CommentsHistoryClick - | CommentsHistoryDrawerOpen - | RecentCommentsClick - | TrackReplaceDownload - | TrackReplacePreview - | TrackReplaceReplace - | RemixContestCreate - | RemixContestUpdate - | RemixContestDelete - | RemixContestPickWinnersOpen - | RemixContestPickWinnersFinalize - | RemixContestView - | RemixContestEnter - | RemixContestViewSubmissions | LaunchpadSplashGetStarted | LaunchpadHasExistingFanClub | LaunchpadSplashLearnMoreClicked diff --git a/packages/common/src/models/AnalyticsSampling.ts b/packages/common/src/models/AnalyticsSampling.ts new file mode 100644 index 00000000000..4ebcbb7282c --- /dev/null +++ b/packages/common/src/models/AnalyticsSampling.ts @@ -0,0 +1,199 @@ +import { Name } from './Analytics' + +/** + * Events sent from every device. Any other event is only sent from a fixed + * sample of devices (see getAnalyticsSampleRate). + */ +export const CORE_ANALYTICS_EVENTS: ReadonlySet = new Set([ + Name.CREATE_ACCOUNT_OPEN, + Name.CREATE_ACCOUNT_COMPLETE_EMAIL, + Name.CREATE_ACCOUNT_UPLOAD_PROFILE_PHOTO, + Name.CREATE_ACCOUNT_UPLOAD_PROFILE_PHOTO_ERROR, + Name.CREATE_ACCOUNT_UPLOAD_COVER_PHOTO, + Name.CREATE_ACCOUNT_UPLOAD_COVER_PHOTO_ERROR, + Name.CREATE_ACCOUNT_SELECT_GENRE, + Name.CREATE_ACCOUNT_FOLLOW_ARTIST, + Name.CREATE_ACCOUNT_ARTIST_PREVIEWED, + Name.CREATE_ACCOUNT_COMPLETE_CREATING, + Name.CREATE_ACCOUNT_COMPLETE_GUEST_CREATING, + Name.CREATE_ACCOUNT_COMPLETE_GUEST_PROFILE, + Name.CREATE_ACCOUNT_RATE_LIMIT, + Name.CREATE_ACCOUNT_BLOCKED, + Name.CREATE_ACCOUNT_WELCOME_MODAL, + Name.CREATE_ACCOUNT_WELCOME_MODAL_UPLOAD_TRACK, + Name.SIGN_IN_START, + Name.SIGN_IN_FINISH, + Name.SIGN_IN_WITH_INCOMPLETE_ACCOUNT, + Name.SIGN_IN_WITH_DEACTIVATED_ACCOUNT, + Name.AUDIUS_OAUTH_START, + Name.AUDIUS_OAUTH_SUBMIT, + Name.AUDIUS_OAUTH_COMPLETE, + Name.AUDIUS_OAUTH_ERROR, + Name.SHARE, + Name.SHARE_TO_TWITTER, + Name.REPOST, + Name.UNDO_REPOST, + Name.FAVORITE, + Name.UNFAVORITE, + Name.FOLLOW, + Name.UNFOLLOW, + Name.EMBED_COPY, + Name.TRACK_UPLOAD_OPEN, + Name.TRACK_UPLOAD_START_UPLOADING, + Name.TRACK_UPLOAD_COMPLETE_UPLOAD, + Name.TWEET_FIRST_UPLOAD, + Name.TRACK_UPLOAD_SUCCESS, + Name.TRACK_UPLOAD_FAILURE, + Name.TRACK_UPLOAD_USDC_GATED, + Name.TRACK_UPLOAD_USDC_GATED_DOWNLOAD, + Name.USDC_PURCHASE_GATED_TRACK_UNLOCKED, + Name.USDC_PURCHASE_GATED_COLLECTION_UNLOCKED, + Name.USDC_PURCHASE_GATED_DOWNLOAD_TRACK_UNLOCKED, + Name.NOTIFICATIONS_OPEN, + Name.NOTIFICATIONS_OPEN_PUSH_NOTIFICATION, + Name.NOTIFICATIONS_CLICK_TILE, + Name.NOTIFICATIONS_CLICK_MILESTONE_TWITTER_SHARE, + Name.NOTIFICATIONS_CLICK_REMIX_CREATE_TWITTER_SHARE, + Name.NOTIFICATIONS_CLICK_REMIX_COSIGN_TWITTER_SHARE, + Name.NOTIFICATIONS_CLICK_DETHRONED_TWITTER_SHARE, + Name.NOTIFICATIONS_CLICK_TRENDING_TRACK_TWITTER_SHARE, + Name.NOTIFICATIONS_CLICK_TRENDING_UNDERGROUND_TWITTER_SHARE, + Name.NOTIFICATIONS_CLICK_TASTEMAKER_TWITTER_SHARE, + Name.NOTIFICATIONS_CLICK_ADD_TRACK_TO_PLAYLIST_TWITTER_SHARE, + Name.NOTIFICATIONS_CLICK_USDC_PURCHASE_TWITTER_SHARE, + Name.PLAYBACK_PLAY, + Name.PLAYBACK_PAUSE, + Name.PAGE_VIEW, + Name.WEEKLY_ROTATION_BANNER_VIEW, + Name.WEEKLY_ROTATION_BANNER_CLICK, + Name.WEEKLY_ROTATION_PAGE_VIEW, + Name.WEEKLY_ROTATION_PLAY_ALL, + Name.SEND_AUDIO_SUCCESS, + Name.SEND_AUDIO_FAILURE, + Name.REWARDS_CLAIM_ALL_REQUEST, + Name.REWARDS_CLAIM_ALL_SUCCESS, + Name.BUY_USDC_ON_RAMP_OPENED, + Name.BUY_USDC_ON_RAMP_CANCELED, + Name.BUY_USDC_ON_RAMP_FAILURE, + Name.BUY_USDC_ON_RAMP_SUCCESS, + Name.BUY_USDC_SUCCESS, + Name.BUY_USDC_FAILURE, + Name.BUY_USDC_RECOVERY_IN_PROGRESS, + Name.BUY_USDC_RECOVERY_SUCCESS, + Name.BUY_USDC_RECOVERY_FAILURE, + Name.BUY_USDC_ADD_FUNDS_MANUALLY, + Name.BUY_SELL_SWAP_REQUESTED, + Name.BUY_SELL_SWAP_CONFIRMED, + Name.BUY_SELL_SWAP_SUCCESS, + Name.BUY_SELL_SWAP_FAILURE, + Name.BUY_SELL_ADD_FUNDS_CLICKED, + Name.WITHDRAW_USDC_MODAL_OPENED, + Name.WITHDRAW_USDC_ADDRESS_PASTED, + Name.WITHDRAW_USDC_REQUESTED, + Name.WITHDRAW_USDC_CREATE_DEST_TOKEN_ACCOUNT_START, + Name.WITHDRAW_USDC_CREATE_DEST_TOKEN_ACCOUNT_SUCCESS, + Name.WITHDRAW_USDC_CREATE_DEST_TOKEN_ACCOUNT_FAILED, + Name.WITHDRAW_USDC_TRANSFER_TO_ROOT_WALLET, + Name.WITHDRAW_USDC_COINFLOW_WITHDRAWAL_READY, + Name.WITHDRAW_USDC_COINFLOW_SEND_TRANSACTION, + Name.WITHDRAW_USDC_COINFLOW_SEND_TRANSACTION_FAILED, + Name.WITHDRAW_USDC_CANCELLED, + Name.WITHDRAW_USDC_FORM_ERROR, + Name.WITHDRAW_USDC_SUCCESS, + Name.WITHDRAW_USDC_FAILURE, + Name.WITHDRAW_USDC_TRANSACTION_LINK_CLICKED, + Name.STRIPE_SESSION_CREATION_ERROR, + Name.STRIPE_SESSION_CREATED, + Name.STRIPE_MODAL_INITIALIZED, + Name.STRIPE_REQUIRES_PAYMENT, + Name.STRIPE_FULLFILMENT_PROCESSING, + Name.STRIPE_FULLFILMENT_COMPLETE, + Name.STRIPE_ERROR, + Name.STRIPE_REJECTED, + Name.PURCHASE_CONTENT_BUY_CLICKED, + Name.PURCHASE_CONTENT_STARTED, + Name.PURCHASE_CONTENT_SUCCESS, + Name.PURCHASE_CONTENT_FAILURE, + Name.PURCHASE_CONTENT_TWITTER_SHARE, + Name.PURCHASE_CONTENT_TOS_CLICKED, + Name.PURCHASE_CONTENT_USDC_USER_BANK_COPIED, + Name.CHAT_BLAST_MESSAGE_SENT, + Name.SEND_MESSAGE_SUCCESS, + // The only record of a chat abuse report + Name.CHAT_REPORT_USER, + Name.COMMENTS_NOTIFICATION_OPEN, + Name.LAUNCHPAD_SPLASH_GET_STARTED, + Name.LAUNCHPAD_HAS_EXISTING_FAN_CLUB, + Name.LAUNCHPAD_SPLASH_LEARN_MORE_CLICKED, + Name.LAUNCHPAD_WALLET_CONNECT_SUCCESS, + Name.LAUNCHPAD_WALLET_CONNECT_ERROR, + Name.LAUNCHPAD_WALLET_INSUFFICIENT_BALANCE, + Name.LAUNCHPAD_SETUP_CONTINUE, + Name.LAUNCHPAD_FORM_BACK, + Name.LAUNCHPAD_FORM_INPUT_CHANGE, + Name.LAUNCHPAD_REVIEW_CONTINUE, + Name.LAUNCHPAD_COIN_CREATION_STARTED, + Name.LAUNCHPAD_COIN_CREATION_SUCCESS, + Name.LAUNCHPAD_COIN_CREATION_FAILURE, + Name.LAUNCHPAD_FIRST_BUY_RETRY, + Name.LAUNCHPAD_FIRST_BUY_MAX_BUTTON, + Name.LAUNCHPAD_FIRST_BUY_QUOTE_RECEIVED, + Name.LAUNCHPAD_BUY_MODAL_OPEN, + Name.LAUNCHPAD_BUY_MODAL_CLOSE, + Name.LAUNCHPAD_BUY_MODAL_SUBMIT, + Name.LAUNCHPAD_BUY_MODAL_SUCCESS, + Name.LAUNCHPAD_BUY_MODAL_FAILURE, + Name.LAUNCHPAD_BUY_MODAL_CHANGE_CURRENCY, + Name.LAUNCHPAD_BUY_MODAL_FORM_CHANGE, + Name.LAUNCHPAD_BUY_MODAL_MAX_BUTTON, + Name.LAUNCHPAD_BUY_MODAL_CONTINUE, + Name.LAUNCHPAD_BUY_MODAL_BACK, + Name.LAUNCHPAD_CLAIM_FEES_CLICKED, + Name.LAUNCHPAD_CLAIM_FEES_SUCCESS, + Name.LAUNCHPAD_CLAIM_FEES_FAILURE, + Name.LAUNCHPAD_CLAIM_FEES_CONNECT_WALLET, + Name.LAUNCHPAD_CLAIM_FEES_SWITCH_WALLET, + Name.LAUNCHPAD_CLAIM_VESTED_COINS_SWITCH_WALLET, + Name.LAUNCHPAD_CLAIM_VESTED_COINS_CLICKED, + Name.LAUNCHPAD_CLAIM_VESTED_COINS_CONNECT_WALLET, + Name.LAUNCHPAD_CLAIM_FEES_WALLET_CONNECTED, + Name.LAUNCHPAD_CLAIM_VESTED_COINS_WALLET_CONNECTED, + Name.LAUNCHPAD_CLAIM_VESTED_COINS_SUCCESS, + Name.LAUNCHPAD_CLAIM_VESTED_COINS_FAILURE +]) + +/** Share of devices that send non-core events */ +export const ANALYTICS_SAMPLE_RATE = 0.1 + +// FNV-1a, so a device lands in the same bucket on every load and platform +const hashString = (value: string) => { + let hash = 0x811c9dc5 + for (let i = 0; i < value.length; i++) { + hash ^= value.charCodeAt(i) + hash = Math.imul(hash, 0x01000193) + } + return hash >>> 0 +} + +export const isCoreAnalyticsEvent = ( + eventName: string, + coreEvents: ReadonlySet = CORE_ANALYTICS_EVENTS +) => + coreEvents.has(eventName) || + // Weekly Rotation events are still being added + eventName.startsWith('Weekly Rotation') + +/** + * Returns null when this device should not send the event, otherwise the + * sample rate it was sent at (1 for core events). Non-core events carry the + * rate as a `sampleRate` property so counts can be scaled back up. + */ +export const getAnalyticsSampleRate = ( + eventName: string, + deviceId: string | undefined, + coreEvents: ReadonlySet = CORE_ANALYTICS_EVENTS +) => { + if (isCoreAnalyticsEvent(eventName, coreEvents) || !deviceId) return 1 + const bucket = hashString(deviceId) % 10000 + return bucket < ANALYTICS_SAMPLE_RATE * 10000 ? ANALYTICS_SAMPLE_RATE : null +} diff --git a/packages/common/src/models/index.ts b/packages/common/src/models/index.ts index 40d7610b4b3..b5eb5e0079d 100644 --- a/packages/common/src/models/index.ts +++ b/packages/common/src/models/index.ts @@ -1,4 +1,5 @@ export * from './Analytics' +export * from './AnalyticsSampling' export * from './AudioRewards' export * from './BadgeTier' export * from './Cache' diff --git a/packages/common/src/services/audius-backend/solana.ts b/packages/common/src/services/audius-backend/solana.ts index f57b9c5c9e2..591ab79e0f8 100644 --- a/packages/common/src/services/audius-backend/solana.ts +++ b/packages/common/src/services/audius-backend/solana.ts @@ -140,7 +140,6 @@ export const getUserbankAccountInfo = async ( export const createUserBankIfNeeded = async ( sdk: AudiusSdkWithServices, { - recordAnalytics, mint = DEFAULT_MINT, ethAddress: recipientEthAddress }: CreateUserBankIfNeededConfig @@ -163,26 +162,10 @@ export const createUserBankIfNeeded = async ( } else { // Otherwise we must have tried to create one console.info(`Userbank doesn't exist, attempted to create...`) - - recordAnalytics({ - eventName: Name.CREATE_USER_BANK_SUCCESS, - properties: { mint, recipientEthAddress } - }) } return res.userBank } catch (err: any) { - // Catching error here for analytics purposes const errorMessage = 'error' in err ? err.error : (err as any).toString() - const errorCode = 'errorCode' in err ? err.errorCode : undefined - recordAnalytics({ - eventName: Name.CREATE_USER_BANK_FAILURE, - properties: { - mint, - recipientEthAddress, - errorCode, - errorMessage - } - }) throw new Error(`Failed to create user bank: ${errorMessage}`) } } diff --git a/packages/common/src/store/gated-content/sagas.ts b/packages/common/src/store/gated-content/sagas.ts index 5ee3ac686c0..dd1146cb480 100644 --- a/packages/common/src/store/gated-content/sagas.ts +++ b/packages/common/src/store/gated-content/sagas.ts @@ -18,7 +18,6 @@ import { ID, Name, isContentFollowGated, - isContentTokenGated, isContentUSDCPurchaseGated, GatedContentStatus, UserTrackMetadata, @@ -133,12 +132,6 @@ export function* pollGatedContent({ ? Name.USDC_PURCHASE_GATED_COLLECTION_UNLOCKED : Name.USDC_PURCHASE_GATED_TRACK_UNLOCKED } - if (isContentFollowGated(apiEntity.stream_conditions)) { - return Name.FOLLOW_GATED_TRACK_UNLOCKED - } - if (isContentTokenGated(apiEntity.stream_conditions)) { - return Name.TOKEN_GATED_TRACK_UNLOCKED - } return null } const eventName = getEventName() @@ -170,11 +163,7 @@ export function* pollGatedContent({ !isAlbum && (isContentUSDCPurchaseGated(apiEntity.download_conditions) ? Name.USDC_PURCHASE_GATED_DOWNLOAD_TRACK_UNLOCKED - : isContentFollowGated(apiEntity.download_conditions) - ? Name.FOLLOW_GATED_DOWNLOAD_TRACK_UNLOCKED - : isContentTokenGated(apiEntity.download_conditions) - ? Name.TOKEN_GATED_DOWNLOAD_TRACK_UNLOCKED - : null) + : null) if (eventName) { analytics.track({ eventName, diff --git a/packages/common/src/store/pages/chat/sagas.ts b/packages/common/src/store/pages/chat/sagas.ts index 6a6584f5255..180e1262cbf 100644 --- a/packages/common/src/store/pages/chat/sagas.ts +++ b/packages/common/src/store/pages/chat/sagas.ts @@ -364,7 +364,6 @@ function* doFetchMoreMessages(action: ReturnType) { function* doSetMessageReaction(action: ReturnType) { const { chatId, messageId, reaction, userId } = action.payload - const { track, make } = yield* getContext('analytics') try { const audiusSdk = yield* getContext('audiusSdk') const sdk = yield* call(audiusSdk) @@ -389,30 +388,15 @@ function* doSetMessageReaction(action: ReturnType) { reaction: reactionResponse }) ) - yield* call( - track, - make({ - eventName: Name.SEND_MESSAGE_REACTION_SUCCESS, - reaction - }) - ) } catch (e) { yield* put(setMessageReactionFailed(action.payload)) console.error('Chats', e as Error) - yield* call( - track, - make({ - eventName: Name.SEND_MESSAGE_REACTION_FAILURE, - reaction - }) - ) } } function* doCreateChat(action: ReturnType) { const { userIds, skipNavigation, presetMessage, replaceNavigation } = action.payload - const { track, make } = yield* getContext('analytics') try { const audiusSdk = yield* getContext('audiusSdk') const sdk = yield* call(audiusSdk) @@ -445,7 +429,6 @@ function* doCreateChat(action: ReturnType) { throw new Error("Chat couldn't be found after creating") } yield* put(createChatSucceeded({ chat })) - yield* call(track, make({ eventName: Name.CREATE_CHAT_SUCCESS })) } } catch (e) { const isForbiddenError = isResponseError(e) && e.response?.status === 403 @@ -472,7 +455,6 @@ function* doCreateChat(action: ReturnType) { if (!isForbiddenError) { console.error('Chats', e as Error) } - yield* call(track, make({ eventName: Name.CREATE_CHAT_FAILURE })) } } @@ -486,7 +468,6 @@ function* doCreateChatBlast(action: ReturnType) { skipNavigation } = action.payload - const { track, make } = yield* getContext('analytics') const currentUserId = yield* call(queryCurrentUserId) try { if (!currentUserId) { @@ -520,16 +501,6 @@ function* doCreateChatBlast(action: ReturnType) { chat: newBlast }) ) - yield* call( - track, - make({ - eventName: Name.CREATE_CHAT_BLAST_SUCCESS, - audience, - audienceContentType, - audienceContentId, - sentBy: currentUserId - }) - ) } } catch (e) { yield* put( @@ -539,17 +510,6 @@ function* doCreateChatBlast(action: ReturnType) { }) ) console.error('Chats', e as Error) - - yield* call( - track, - make({ - eventName: Name.CREATE_CHAT_BLAST_FAILURE, - audience, - audienceContentType, - audienceContentId, - sentBy: currentUserId ?? undefined - }) - ) } } @@ -676,7 +636,6 @@ function* doSendMessage(action: ReturnType) { } } console.error('Chats', e as Error) - yield* call(track, make({ eventName: Name.SEND_MESSAGE_FAILURE })) } } @@ -734,7 +693,6 @@ function* doFetchBlockers() { function* doBlockUser(action: ReturnType) { const { userId } = action.payload - const { track, make } = yield* getContext('analytics') try { const audiusSdk = yield* getContext('audiusSdk') const sdk = yield* call(audiusSdk) @@ -742,16 +700,8 @@ function* doBlockUser(action: ReturnType) { userId: Id.parse(userId) }) yield* put(fetchBlockees()) - yield* call( - track, - make({ eventName: Name.BLOCK_USER_SUCCESS, blockedUserId: userId }) - ) } catch (e) { console.error('Chats', e as Error) - yield* call( - track, - make({ eventName: Name.BLOCK_USER_FAILURE, blockedUserId: userId }) - ) } } @@ -821,7 +771,6 @@ function* doFetchLinkUnfurlMetadata( function* doDeleteChat(action: ReturnType) { const { chatId } = action.payload - const { track, make } = yield* getContext('analytics') try { const audiusSdk = yield* getContext('audiusSdk') const sdk = yield* call(audiusSdk) @@ -834,18 +783,13 @@ function* doDeleteChat(action: ReturnType) { yield* delay(1) // NOW delete the chat - otherwise we refetch it right away yield* put(deleteChatSucceeded({ chatId })) - yield* call(track, make({ eventName: Name.DELETE_CHAT_SUCCESS })) } catch (e) { console.error('Chats', e as Error) - yield* call(track, make({ eventName: Name.DELETE_CHAT_FAILURE })) } } function* doLogError({ payload: { error } }: ReturnType) { - const { track, make } = yield* getContext('analytics') - const { code } = error console.error(error) - yield* call(track, make({ eventName: Name.CHAT_WEBSOCKET_ERROR, code })) } function* watchFetchUnreadMessagesCount() { @@ -938,7 +882,6 @@ function* watchDeleteChat() { export function* doSetChatCategory(action: ReturnType) { const { chatId, category } = action.payload - const { track, make } = yield* getContext('analytics') try { const audiusSdk = yield* getContext('audiusSdk') const sdk = yield* call(audiusSdk) @@ -957,10 +900,6 @@ export function* doSetChatCategory(action: ReturnType) { : 'Conversation uncategorized' }) ) - yield* call( - track, - make({ eventName: Name.SET_CHAT_CATEGORY_SUCCESS, category }) - ) } catch (e) { yield* put(setChatCategoryFailed({ chatId })) yield* put( @@ -970,10 +909,6 @@ export function* doSetChatCategory(action: ReturnType) { }) ) console.error('Chats', e as Error) - yield* call( - track, - make({ eventName: Name.SET_CHAT_CATEGORY_FAILURE, category }) - ) } } diff --git a/packages/common/src/store/ui/modals/sagas.ts b/packages/common/src/store/ui/modals/sagas.ts index a5cb36a959f..1fd0c4f3c6a 100644 --- a/packages/common/src/store/ui/modals/sagas.ts +++ b/packages/common/src/store/ui/modals/sagas.ts @@ -1,36 +1,3 @@ -import { takeEvery, call } from 'typed-redux-saga' - -import { Name } from '~/models/Analytics' -import { getContext } from '~/store/effects' - -import { actions } from './parentSlice' -const { trackModalOpened, trackModalClosed } = actions - -function* handleTrackModalOpened({ - payload: { name, source, trackingData } -}: ReturnType) { - const { track, make } = yield* getContext('analytics') - yield* call( - track, - make({ eventName: Name.MODAL_OPENED, source, name, ...trackingData }) - ) -} - -function* handleTrackModalClosed({ - payload: { name } -}: ReturnType) { - const { track, make } = yield* getContext('analytics') - yield* call(track, make({ eventName: Name.MODAL_CLOSED, name })) -} - -function* watchTrackModalOpened() { - yield takeEvery(trackModalOpened, handleTrackModalOpened) -} - -function* watchTrackModalClosed() { - yield takeEvery(trackModalClosed, handleTrackModalClosed) -} - export function sagas() { - return [watchTrackModalOpened, watchTrackModalClosed] + return [] } diff --git a/packages/embed/src/analytics/analytics.js b/packages/embed/src/analytics/analytics.js index 2c0d9facdd4..bad2a7cb9d6 100644 --- a/packages/embed/src/analytics/analytics.js +++ b/packages/embed/src/analytics/analytics.js @@ -8,16 +8,39 @@ const AMP_PROXY = getAmplitudeProxy() const amp = amplitude.getInstance() -export const initTrackSessionStart = async () => { +const BOT_USER_AGENT_REGEX = + /bot|crawl|spider|slurp|headless|lighthouse|pagespeed|prerender|phantomjs|puppeteer|playwright|selenium|facebookexternalhit|embedly|bingpreview|inspectiontool/i + +// Crawlers of pages that embed the player get no analytics +const isLikelyBot = () => { + if (typeof navigator === 'undefined') return false + if (navigator.webdriver === true) return true + const userAgent = navigator.userAgent || '' + // Cubot is a phone brand, not a crawler + return BOT_USER_AGENT_REGEX.test(userAgent) && !/cubot/i.test(userAgent) +} + +let isEnabled = false + +const CLIENT_IDENTIFIED_KEY = 'amplitude:clientIdentified' + +// Which client the user is on, as a user property set once per device +const identifyClient = () => { + try { + if (window.localStorage.getItem(CLIENT_IDENTIFIED_KEY)) return + window.localStorage.setItem(CLIENT_IDENTIFIED_KEY, '1') + } catch { + // Storage can be blocked in third-party iframes, so identify every load + } + amp.identify(new amplitude.Identify().set('client', 'Embed')) +} + +export const initAnalytics = () => { try { - if (AMP_API_KEY && AMP_PROXY) { - const SESSION_START = 'Session Start' - const SOURCE = 'embed player' + if (AMP_API_KEY && AMP_PROXY && !isLikelyBot()) { amp.init(AMP_API_KEY, undefined, { apiEndpoint: AMP_PROXY }) - amp.logEvent(SESSION_START, { - source: SOURCE, - referrer: document.referrer - }) + isEnabled = true + identifyClient() } } catch (err) { logError(err) @@ -26,27 +49,16 @@ export const initTrackSessionStart = async () => { const SOURCE = 'embed player' -const OPEN = 'Embed: Open Player' -const ERROR = 'Embed: Player Error' const PLAYBACK_PLAY = 'Playback: Play' const PLAYBACK_PAUSE = 'Playback: Pause' const LISTEN = 'Listen' const track = (event, properties) => { - if (amp) { + if (isEnabled) { amp.logEvent(event, properties) } } -/** id param is the numeric id */ -export const recordOpen = (id, title, handle, path) => { - track(OPEN, { id: `${id}`, handle, title, path, referrer: document.referrer }) -} - -export const recordError = () => { - track(ERROR, { referrer: document.referrer }) -} - /** id param is the numeric id */ export const recordPlay = (id) => { track(PLAYBACK_PLAY, { diff --git a/packages/embed/src/components/app.jsx b/packages/embed/src/components/app.jsx index d089c5cd0a0..c6b54f853e8 100644 --- a/packages/embed/src/components/app.jsx +++ b/packages/embed/src/components/app.jsx @@ -7,11 +7,7 @@ import { CSSTransition } from 'react-transition-group' import '@audius/harmony/dist/harmony.css' -import { - initTrackSessionStart, - recordOpen, - recordError -} from '../analytics/analytics' +import { initAnalytics } from '../analytics/analytics' import { ID_ROUTE, HASH_ID_ROUTE, PERMALINK_ROUTE } from '../routes' import { getCollection, @@ -23,7 +19,6 @@ import { getEntityEvents } from '../util/BedtimeClient' import { getArtworkUrl } from '../util/getArtworkUrl' -import { decodeHashId } from '../util/hashIds' import { getDominantColor } from '../util/image/imageProcessingUtil' import { isMobileWebTwitter } from '../util/isMobileWebTwitter' import { logError } from '../util/logError' @@ -155,15 +150,9 @@ const App = (props) => { const [dominantColor, setDominantColor] = useState(null) const playerContainerRef = useRef(null) + // Set up analytics useEffect(() => { - if (didError) { - recordError() - } - }, [didError]) - - // Record this session with analytics - useEffect(() => { - initTrackSessionStart() + initAnalytics() }, []) // TODO: pull these out into separate functions? @@ -207,12 +196,6 @@ const App = (props) => { setDid404(false) setIsUnavailable(false) setTracksResponse({ ...track, events }) - recordOpen( - decodeHashId(track.id), - track.title, - track.user.handle, - stripLeadingSlash(track.permalink) - ) const artworkUrl = await getArtworkUrl(track) // Set dominant color @@ -254,12 +237,6 @@ const App = (props) => { setDid404(false) setIsUnavailable(false) setCollectionsResponse(collection) - recordOpen( - decodeHashId(collection.id), - collection.playlistName, - collection.user.handle, - stripLeadingSlash(collection.permalink) - ) const artworkUrl = await getArtworkUrl(collection) // Set dominant color diff --git a/packages/mobile/src/app/ErrorBoundary.tsx b/packages/mobile/src/app/ErrorBoundary.tsx index 68064a9a06b..713f257ff8e 100644 --- a/packages/mobile/src/app/ErrorBoundary.tsx +++ b/packages/mobile/src/app/ErrorBoundary.tsx @@ -4,8 +4,6 @@ import { PureComponent, useEffect } from 'react' import type { Nullable } from '@audius/common/utils' import { useToast } from 'app/hooks/useToast' -import { make, track } from 'app/services/analytics' -import { EventNames } from 'app/types/analytics' type ErrorToastProps = { error: Nullable @@ -38,12 +36,6 @@ class ErrorBoundary extends PureComponent { // On catch set the error state so it triggers a toast this.setState({ error: error?.message }) console.error(error ?? new Error('Unknown error caught by'), errorInfo) - track( - make({ - eventName: EventNames.APP_ERROR, - message: error?.message - }) - ) } render() { diff --git a/packages/mobile/src/components/audio/AudioPlayer.tsx b/packages/mobile/src/components/audio/AudioPlayer.tsx index 4452f26a251..ca15707e43b 100644 --- a/packages/mobile/src/components/audio/AudioPlayer.tsx +++ b/packages/mobile/src/components/audio/AudioPlayer.tsx @@ -2,7 +2,7 @@ import { useRef, useEffect, useCallback, useState, useMemo } from 'react' import { useCurrentUserId, useTracks, useUsers } from '@audius/common/api' import { useCurrentTrack } from '@audius/common/hooks' -import { Name, SquareSizes } from '@audius/common/models' +import { SquareSizes } from '@audius/common/models' import type { ID, Track } from '@audius/common/models' import { playbackActions, @@ -41,7 +41,6 @@ import TrackPlayer, { import { useDispatch, useSelector } from 'react-redux' import { useAsync, usePrevious } from 'react-use' -import { make, track as analyticsTrack } from 'app/services/analytics' import { audiusBackendInstance } from 'app/services/audius-backend-instance' import { getLocalAudioPath, @@ -504,7 +503,6 @@ const usePlaybackEvents = ({ getUserTrackPositions(state, { userId: currentUserId }) ) - const [bufferStartTime, setBufferStartTime] = useState() const { bufferingDuringPlay } = useIsPlaying() const previousBufferingState = usePrevious(bufferingDuringPlay) @@ -515,21 +513,8 @@ const usePlaybackEvents = ({ bufferingDuringPlay !== previousBufferingState ) { dispatch(playbackActions.setBuffering({ buffering: bufferingDuringPlay })) - if (!bufferingDuringPlay && bufferStartTime) { - const bufferDuration = Math.ceil(performance.now() - bufferStartTime) - analyticsTrack( - make({ eventName: Name.BUFFERING_TIME, duration: bufferDuration }) - ) - setBufferStartTime(undefined) - } } - }, [ - bufferStartTime, - bufferingDuringPlay, - dispatch, - previousBufferingState, - track - ]) + }, [bufferingDuringPlay, dispatch, previousBufferingState, track]) const seekToRef = useRef(null) @@ -626,7 +611,6 @@ const usePlaybackEvents = ({ // --- Active track changed --- if (event.type === Event.PlaybackActiveTrackChanged) { - setBufferStartTime(performance.now()) const playerIndex = await TrackPlayer.getActiveTrackIndex() if (playerIndex === undefined) return diff --git a/packages/mobile/src/components/comments/CommentActionBar.tsx b/packages/mobile/src/components/comments/CommentActionBar.tsx index 4f77df2835a..4f87a26b0b0 100644 --- a/packages/mobile/src/components/comments/CommentActionBar.tsx +++ b/packages/mobile/src/components/comments/CommentActionBar.tsx @@ -5,15 +5,9 @@ import { useReactToComment } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { - Name, - type Comment, - type ID, - type ReplyComment -} from '@audius/common/models' +import { type Comment, type ID, type ReplyComment } from '@audius/common/models' import { Box, Flex, PlainButton, Text } from '@audius/harmony-native' -import { make, track } from 'app/services/analytics' import { FavoriteButton } from '../favorite-button' @@ -43,14 +37,7 @@ export const CommentActionBar = (props: CommentActionBarProps) => { replyingToComment: comment, replyingToCommentId: parentCommentId ?? comment.id }) - - track( - make({ - eventName: Name.COMMENTS_CLICK_REPLY_BUTTON, - commentId - }) - ) - }, [comment, commentId, parentCommentId, setReplyingAndEditingState]) + }, [comment, parentCommentId, setReplyingAndEditingState]) return ( <> diff --git a/packages/mobile/src/components/comments/CommentBlock.tsx b/packages/mobile/src/components/comments/CommentBlock.tsx index 2ca2839fe19..d36d5259c8c 100644 --- a/packages/mobile/src/components/comments/CommentBlock.tsx +++ b/packages/mobile/src/components/comments/CommentBlock.tsx @@ -2,21 +2,14 @@ import { useCallback, useMemo } from 'react' import { useComment, useUser } from '@audius/common/api' import { useCurrentCommentSection } from '@audius/common/context' -import { - Name, - type Comment, - type ID, - type ReplyComment -} from '@audius/common/models' +import { type Comment, type ID, type ReplyComment } from '@audius/common/models' import { dayjs } from '@audius/common/utils' import { css } from '@emotion/native' import { useLinkProps } from '@react-navigation/native' -import type { GestureResponderEvent } from 'react-native' import { TouchableOpacity } from 'react-native' import Animated, { FadeIn, Keyframe } from 'react-native-reanimated' import { Flex, Text, useTheme } from '@audius/harmony-native' -import { make, track as trackEvent } from 'app/services/analytics' import { ProfilePicture } from '../core/ProfilePicture' import { Skeleton } from '../skeleton' @@ -84,19 +77,6 @@ export const CommentBlockInternal = ( onPressProfilePic() }, [handleNavigateAway, onPressProfilePic]) - const handlePressTimestamp = useCallback( - (e: GestureResponderEvent, timestampSeconds: number) => { - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_TIMESTAMP, - commentId, - timestamp: timestampSeconds - }) - ) - }, - [commentId] - ) - const highlightBackgroundFadeAnimation = useMemo( () => new Keyframe({ @@ -199,7 +179,6 @@ export const CommentBlockInternal = ( ) : null} diff --git a/packages/mobile/src/components/comments/CommentDrawerContext.tsx b/packages/mobile/src/components/comments/CommentDrawerContext.tsx index 22188bd66df..0717f64b661 100644 --- a/packages/mobile/src/components/comments/CommentDrawerContext.tsx +++ b/packages/mobile/src/components/comments/CommentDrawerContext.tsx @@ -8,11 +8,10 @@ import React, { useState } from 'react' -import { Name, type ID } from '@audius/common/models' +import { type ID } from '@audius/common/models' import type { BottomSheetModal } from '@gorhom/bottom-sheet' import { useDrawer } from 'app/hooks/useDrawer' -import { make, track } from 'app/services/analytics' import type { CommentDrawerData } from './CommentDrawer' import { CommentDrawer } from './CommentDrawer' @@ -54,15 +53,9 @@ export const CommentDrawerProvider = (props: PropsWithChildren) => { setDrawerData(props) setIsOpen(true) - track( - make({ - eventName: Name.COMMENTS_OPEN_COMMENT_DRAWER, - trackId: props.entityId - }) - ) }, []) - const close = useCallback((trackId: ID) => { + const close = useCallback(() => { // Closes the comment drawer only. The now-playing drawer should stay // open here — the BottomSheetModal's onDismiss callback (swipe-down, // backdrop tap, X button) routes through this path and historically @@ -70,29 +63,14 @@ export const CommentDrawerProvider = (props: PropsWithChildren) => { // Navigation flows that need both drawers closed call // `closeAndExitNowPlaying` instead. setIsOpen(false) - track( - make({ - eventName: Name.COMMENTS_CLOSE_COMMENT_DRAWER, - trackId - }) - ) }, []) - const closeAndExitNowPlaying = useCallback( - (trackId: ID) => { - setIsOpen(false) - if (isNowPlayingDrawerOpen) { - closeNowPlayingDrawer() - } - track( - make({ - eventName: Name.COMMENTS_CLOSE_COMMENT_DRAWER, - trackId - }) - ) - }, - [closeNowPlayingDrawer, isNowPlayingDrawerOpen] - ) + const closeAndExitNowPlaying = useCallback(() => { + setIsOpen(false) + if (isNowPlayingDrawerOpen) { + closeNowPlayingDrawer() + } + }, [closeNowPlayingDrawer, isNowPlayingDrawerOpen]) useEffect(() => { if (isOpen) { diff --git a/packages/mobile/src/components/comments/CommentDrawerHeader.tsx b/packages/mobile/src/components/comments/CommentDrawerHeader.tsx index 7242b89c81b..cd60018e142 100644 --- a/packages/mobile/src/components/comments/CommentDrawerHeader.tsx +++ b/packages/mobile/src/components/comments/CommentDrawerHeader.tsx @@ -6,7 +6,6 @@ import { useUpdateTrackCommentNotificationSetting } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { Name } from '@audius/common/models' import { Portal } from '@gorhom/portal' import { useKeyboard } from '@react-native-community/hooks' import { Keyboard, TouchableWithoutFeedback, View } from 'react-native' @@ -22,7 +21,6 @@ import { Text } from '@audius/harmony-native' import { useToast } from 'app/hooks/useToast' -import { track, make } from 'app/services/analytics' import { ActionDrawerWithoutRedux } from '../action-drawer' @@ -65,12 +63,6 @@ export const CommentDrawerHeader = (props: CommentDrawerHeaderProps) => { const handlePressOverflowMenu = () => { toggleNotificationActionDrawer() - track( - make({ - eventName: Name.COMMENTS_OPEN_TRACK_OVERFLOW_MENU, - trackId: entityId - }) - ) } const showCommentSortBar = commentCount !== undefined && commentCount > 1 diff --git a/packages/mobile/src/components/comments/CommentForm.tsx b/packages/mobile/src/components/comments/CommentForm.tsx index 6f2127feb5a..96f8038c4e4 100644 --- a/packages/mobile/src/components/comments/CommentForm.tsx +++ b/packages/mobile/src/components/comments/CommentForm.tsx @@ -3,8 +3,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { useUser } from '@audius/common/api' import { useCurrentCommentSection } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { Name } from '@audius/common/models' -import type { ID, UserMetadata } from '@audius/common/models' +import type { UserMetadata } from '@audius/common/models' import type { CommentMention } from '@audius/sdk' import type { TextInput as RNTextInput, TextInputProps } from 'react-native' @@ -17,7 +16,6 @@ import { Text, useTheme } from '@audius/harmony-native' -import { make, track } from 'app/services/analytics' import { ComposerInput } from '../composer-input' import { ProfilePicture } from '../core' @@ -94,8 +92,7 @@ export const CommentForm = (props: CommentFormProps) => { TextInputComponent, onPressIn, readOnly, - autoFocus, - isPreview + autoFocus } = props const [messageId, setMessageId] = useState(0) const [initialMessage, setInitialMessage] = useState(initialValue) @@ -175,49 +172,8 @@ export const CommentForm = (props: CommentFormProps) => { } }, [editingComment, initialMessage?.length, replyingToComment]) - const handleFocus = useCallback(() => { - track( - make({ - eventName: Name.COMMENTS_FOCUS_COMMENT_INPUT, - trackId: entityId, - source: isPreview ? 'comment_preview' : 'comment_input' - }) - ) - }, [entityId, isPreview]) - const showHelperText = editingComment || replyingToComment - const handleAddMention = useCallback((userId: ID) => { - track( - make({ - eventName: Name.COMMENTS_ADD_MENTION, - userId - }) - ) - }, []) - - const handleAddTimestamp = useCallback((timestamp: number) => { - track( - make({ - eventName: Name.COMMENTS_ADD_TIMESTAMP, - timestamp - }) - ) - }, []) - - const handleAddLink = useCallback( - (entityId: ID, kind: 'track' | 'collection' | 'user') => { - track( - make({ - eventName: Name.COMMENTS_ADD_LINK, - entityId, - kind - }) - ) - }, - [] - ) - return ( {currentUserId ? ( @@ -237,7 +193,6 @@ export const CommentForm = (props: CommentFormProps) => { ref={ref} onAutocompleteChange={onAutocompleteChange} setAutocompleteHandler={setAutocompleteHandler} - onFocus={handleFocus} isLoading={isLoading} messageId={messageId} entityId={entityId} @@ -251,9 +206,6 @@ export const CommentForm = (props: CommentFormProps) => { onLayout={handleLayout} maxLength={400} maxMentions={10} - onAddMention={handleAddMention} - onAddTimestamp={handleAddTimestamp} - onAddLink={handleAddLink} styles={{ container: { borderTopLeftRadius: showHelperText ? 0 : spacing.unit1, diff --git a/packages/mobile/src/components/comments/CommentOverflowMenu.tsx b/packages/mobile/src/components/comments/CommentOverflowMenu.tsx index 672da9a72e2..ef67aa242ab 100644 --- a/packages/mobile/src/components/comments/CommentOverflowMenu.tsx +++ b/packages/mobile/src/components/comments/CommentOverflowMenu.tsx @@ -10,12 +10,7 @@ import { useMuteUser } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { - Name, - type Comment, - type ID, - type ReplyComment -} from '@audius/common/models' +import { type Comment, type ID, type ReplyComment } from '@audius/common/models' import { removeNullable } from '@audius/common/utils' import { Id } from '@audius/sdk' import { Portal } from '@gorhom/portal' @@ -23,7 +18,6 @@ import Clipboard from '@react-native-clipboard/clipboard' import { Hint, IconButton, IconKebabHorizontal } from '@audius/harmony-native' import { useToast } from 'app/hooks/useToast' -import { track as trackEvent, make } from 'app/services/analytics' import { env } from 'app/services/env' import { @@ -239,14 +233,7 @@ export const CommentOverflowMenu = (props: CommentOverflowMenuProps) => { const handlePress = useCallback(() => { setIsOpen(true) setIsVisible(true) - - trackEvent( - make({ - eventName: Name.COMMENTS_OPEN_COMMENT_OVERFLOW_MENU, - commentId: id - }) - ) - }, [id]) + }, []) return ( <> diff --git a/packages/mobile/src/components/comments/CommentText.tsx b/packages/mobile/src/components/comments/CommentText.tsx index 562896a11e9..84935c55118 100644 --- a/packages/mobile/src/components/comments/CommentText.tsx +++ b/packages/mobile/src/components/comments/CommentText.tsx @@ -1,20 +1,17 @@ import { useCallback, useState } from 'react' import { commentsMessages as messages } from '@audius/common/messages' -import { Name, type ID } from '@audius/common/models' +import { type ID } from '@audius/common/models' import { getDurationFromTimestampMatch, timestampRegex } from '@audius/common/utils' import type { CommentMention } from '@audius/sdk' import type { NavigationProp, ParamListBase } from '@react-navigation/native' -import type { GestureResponderEvent } from 'react-native' import { useToggle } from 'react-use' import { Flex, Text, TextLink } from '@audius/harmony-native' import { UserGeneratedText } from 'app/components/core' -import type { LinkKind } from 'app/harmony-native/components/TextLink/types' -import { make, track } from 'app/services/analytics' import { TimestampLink } from './TimestampLink' @@ -38,7 +35,6 @@ export const CommentText = (props: CommentTextProps) => { isEdited, isPreview, mentions, - commentId, trackDuration, onCloseDrawer, renderTimestamps = true, @@ -56,43 +52,9 @@ export const CommentText = (props: CommentTextProps) => { [isOverflowing] ) - const handlePressLink = useCallback( - (e: GestureResponderEvent, linkKind: LinkKind, linkEntityId?: ID) => { - if (linkKind === 'mention' && linkEntityId) { - track( - make({ - eventName: Name.COMMENTS_CLICK_MENTION, - userId: linkEntityId, - commentId - }) - ) - } else { - track( - make({ - eventName: Name.COMMENTS_CLICK_LINK, - commentId, - kind: linkKind as 'track' | 'collection' | 'user' | 'other', - entityId: linkEntityId - }) - ) - } - onCloseDrawer?.() - }, - [onCloseDrawer, commentId] - ) - - const handlePressTimestamp = useCallback( - (e: GestureResponderEvent, timestampSeconds: number) => { - track( - make({ - eventName: Name.COMMENTS_CLICK_TIMESTAMP, - commentId, - timestamp: timestampSeconds - }) - ) - }, - [commentId] - ) + const handlePressLink = useCallback(() => { + onCloseDrawer?.() + }, [onCloseDrawer]) return ( @@ -127,10 +89,7 @@ export const CommentText = (props: CommentTextProps) => { renderTimestamps && timestampSeconds <= trackDuration return showLink ? ( - + ) : ( {text} ) diff --git a/packages/mobile/src/components/comments/CommentThread.tsx b/packages/mobile/src/components/comments/CommentThread.tsx index 900ce5be8f2..edafd088fa5 100644 --- a/packages/mobile/src/components/comments/CommentThread.tsx +++ b/packages/mobile/src/components/comments/CommentThread.tsx @@ -1,14 +1,8 @@ import { useCallback, useEffect, useState } from 'react' import { useComment, useCommentReplies } from '@audius/common/api' -import { useCurrentCommentSection } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { - Name, - type Comment, - type ID, - type ReplyComment -} from '@audius/common/models' +import { type Comment, type ID, type ReplyComment } from '@audius/common/models' import type { LayoutChangeEvent } from 'react-native/types' import Animated, { useAnimatedStyle, @@ -24,7 +18,6 @@ import { PlainButton, useTheme } from '@audius/harmony-native' -import { make, track } from 'app/services/analytics' import LoadingSpinner from '../loading-spinner/LoadingSpinner' @@ -38,7 +31,6 @@ type CommentThreadProps = { export const CommentThread = (props: CommentThreadProps) => { const { commentId, highlightedComment } = props const { motion, spacing } = useTheme() - const { entityId } = useCurrentCommentSection() const { data: rootCommentData } = useComment(commentId) const rootComment = rootCommentData as Comment | null | undefined // May be null/undefined or a `{}` placeholder while the individual comment cache is (re)hydrating @@ -66,16 +58,6 @@ export const CommentThread = (props: CommentThreadProps) => { const newHiddenReplies = { ...hiddenReplies } newHiddenReplies[commentId] = !newHiddenReplies[commentId] setHiddenReplies(newHiddenReplies) - - track( - make({ - eventName: newHiddenReplies[commentId] - ? Name.COMMENTS_HIDE_REPLIES - : Name.COMMENTS_SHOW_REPLIES, - commentId, - trackId: entityId - }) - ) } const [hasRequestedMore, setHasRequestedMore] = useState(false) const { isFetching: isFetchingReplies } = useCommentReplies( diff --git a/packages/mobile/src/components/comments/RecentUserCommentsDrawer.tsx b/packages/mobile/src/components/comments/RecentUserCommentsDrawer.tsx index ee4fd3aa80c..96910aacf5c 100644 --- a/packages/mobile/src/components/comments/RecentUserCommentsDrawer.tsx +++ b/packages/mobile/src/components/comments/RecentUserCommentsDrawer.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef } from 'react' import type { CommentOrReply } from '@audius/common/api' import { useTrack, useUser, useUserComments } from '@audius/common/api' -import { Name, type ID } from '@audius/common/models' +import { type ID } from '@audius/common/models' import { dayjs } from '@audius/common/utils' import { BottomSheetBackdrop, @@ -23,7 +23,6 @@ import { } from '@audius/harmony-native' import { LoadingSpinner } from 'app/harmony-native/components/LoadingSpinner/LoadingSpinner' import { useNavigation } from 'app/hooks/useNavigation' -import { make, track as trackEvent } from 'app/services/analytics' import { ProfilePicture } from '../core/ProfilePicture' import { UserLink } from '../user-link' @@ -51,26 +50,13 @@ const CommentItem = ({ comment }: { comment: CommentOrReply }) => { const { data: track, isLoading: isTrackLoading } = useTrack(comment?.entityId) const { data: artist, isLoading: isArtistLoading } = useUser(track?.owner_id) - const trackUserCommentClick = useCallback(() => { - if (comment) { - trackEvent( - make({ - eventName: Name.COMMENTS_HISTORY_CLICK, - commentId: comment.id, - userId - }) - ) - } - }, [comment, userId]) - const handlePressView = useCallback(() => { if (track?.track_id) { - trackUserCommentClick() // @ts-ignore (bad types on useNavigation) navigation.push('Track', { trackId: track.track_id }) } onClose() - }, [navigation, track?.track_id, onClose, trackUserCommentClick]) + }, [navigation, track?.track_id, onClose]) if (isTrackLoading || isArtistLoading) { return diff --git a/packages/mobile/src/components/core/Link.tsx b/packages/mobile/src/components/core/Link.tsx index d8a466fa643..b526befb703 100644 --- a/packages/mobile/src/components/core/Link.tsx +++ b/packages/mobile/src/components/core/Link.tsx @@ -4,16 +4,14 @@ import type { GestureResponderEvent, PressableProps } from 'react-native' import { Linking, Pressable } from 'react-native' import { useToast } from 'app/hooks/useToast' -import { make, track } from 'app/services/analytics' -import { EventNames } from 'app/types/analytics' +import type { make } from 'app/services/analytics' +import { track } from 'app/services/analytics' const messages = { error: 'Unable to open this URL' } -export const useOnOpenLink = ( - source?: 'profile page' | 'track page' | 'collection page' -) => { +export const useOnOpenLink = () => { const { toast } = useToast() const handlePress = useCallback( @@ -28,15 +26,6 @@ export const useOnOpenLink = ( const supported = await Linking.canOpenURL(urlWithPrefix) if (supported) { await Linking.openURL(urlWithPrefix) - if (source) { - track( - make({ - eventName: EventNames.LINK_CLICKING, - url: urlWithPrefix, - source - }) - ) - } } else { toast(errorToastConfig) } @@ -44,7 +33,7 @@ export const useOnOpenLink = ( toast(errorToastConfig) } }, - [toast, source] + [toast] ) return handlePress diff --git a/packages/mobile/src/components/download-track-archive-drawer/DownloadTrackArchiveDrawer.tsx b/packages/mobile/src/components/download-track-archive-drawer/DownloadTrackArchiveDrawer.tsx index 269caeded20..2805a6b9801 100644 --- a/packages/mobile/src/components/download-track-archive-drawer/DownloadTrackArchiveDrawer.tsx +++ b/packages/mobile/src/components/download-track-archive-drawer/DownloadTrackArchiveDrawer.tsx @@ -8,7 +8,6 @@ import { } from '@audius/common/api' import { useAppContext } from '@audius/common/context' import type { ID } from '@audius/common/models' -import { Name } from '@audius/common/models' import type { DownloadFile } from '@audius/common/services' import { useDownloadTrackArchiveModal } from '@audius/common/store' @@ -96,10 +95,6 @@ const DownloadTrackArchiveDrawerContent = ({ onClose, onClosed }: DownloadTrackArchiveDrawerContentProps) => { - const { - analytics: { track, make } - } = useAppContext() - const { data: trackTitle } = useTrack(trackId, { select: (track) => track.title }) @@ -146,16 +141,6 @@ const DownloadTrackArchiveDrawerContent = ({ jobState?.state === 'failed' || (!!jobId && (isJobStatusError || isJobTimedOut))) - useEffect(() => { - if (hasError) { - track( - make({ - eventName: Name.TRACK_DOWNLOAD_FAILED_DOWNLOAD_ALL - }) - ) - } - }, [hasError, track, make]) - useEffect(() => { downloadTrackStems() }, [downloadTrackStems]) @@ -170,16 +155,11 @@ const DownloadTrackArchiveDrawerContent = ({ filename: `${trackTitle}.zip` } }) - track( - make({ - eventName: Name.TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_ALL - }) - ) onClose() } fetchResult() } - }, [jobState, onClose, jobId, downloadFile, trackTitle, make, track]) + }, [jobState, onClose, jobId, downloadFile, trackTitle]) // Close drawer automatically if download was successful useEffect(() => { diff --git a/packages/mobile/src/components/host-remix-contest-drawer/HostRemixContestDrawer.tsx b/packages/mobile/src/components/host-remix-contest-drawer/HostRemixContestDrawer.tsx index 6d8da27c33f..b147c330855 100644 --- a/packages/mobile/src/components/host-remix-contest-drawer/HostRemixContestDrawer.tsx +++ b/packages/mobile/src/components/host-remix-contest-drawer/HostRemixContestDrawer.tsx @@ -9,7 +9,6 @@ import { useRemixesLineup } from '@audius/common/api' import { remixMessages } from '@audius/common/messages' -import { Name } from '@audius/common/models' import { useHostRemixContestModal } from '@audius/common/store' import { EventEntityTypeEnum, EventEventTypeEnum } from '@audius/sdk' import dayjs from 'dayjs' @@ -23,7 +22,6 @@ import { Button, TextLink } from '@audius/harmony-native' -import { make, track } from 'app/services/analytics' import { makeStyles } from 'app/styles' import { DateTimeInput, TextInput } from '../core' @@ -159,14 +157,6 @@ export const HostRemixContestDrawer = () => { }, userId }) - - track( - make({ - eventName: Name.REMIX_CONTEST_UPDATE, - remixContestId: remixContest.eventId, - trackId - }) - ) } else { createEvent({ eventType: EventEventTypeEnum.RemixContest, @@ -181,13 +171,6 @@ export const HostRemixContestDrawer = () => { winners: [] } }) - - track( - make({ - eventName: Name.REMIX_CONTEST_CREATE, - trackId - }) - ) } onClose() @@ -212,18 +195,8 @@ export const HostRemixContestDrawer = () => { if (!remixContest || !userId) return deleteEvent({ eventId: remixContest.eventId, userId }) - if (trackId) { - track( - make({ - eventName: Name.REMIX_CONTEST_DELETE, - remixContestId: remixContest.eventId, - trackId - }) - ) - } - onClose() - }, [remixContest, userId, deleteEvent, onClose, trackId]) + }, [remixContest, userId, deleteEvent, onClose]) return ( { autoFocusInput: false, playbackSource }) - - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_COMMENT_STAT, - trackId, - source: 'lineup' - }) - ) }, [open, trackId, navigation, playbackSource]) if (commentCount === undefined || commentsDisabled) return null diff --git a/packages/mobile/src/components/rate-cta-drawer/RateCtaDrawer.tsx b/packages/mobile/src/components/rate-cta-drawer/RateCtaDrawer.tsx index 0da7a6e805a..e87a5f3077e 100644 --- a/packages/mobile/src/components/rate-cta-drawer/RateCtaDrawer.tsx +++ b/packages/mobile/src/components/rate-cta-drawer/RateCtaDrawer.tsx @@ -1,6 +1,5 @@ import { useCallback, useState } from 'react' -import { Name } from '@audius/common/models' import type { Nullable } from '@audius/common/utils' import AsyncStorage from '@react-native-async-storage/async-storage' import { Linking, View } from 'react-native' @@ -16,7 +15,6 @@ import { import { Text } from 'app/components/core' import { NativeDrawer } from 'app/components/drawer' import { RATE_CTA_STORAGE_KEY } from 'app/constants/storage-keys' -import { make, track } from 'app/services/analytics' import { makeStyles } from 'app/styles' import { isSolanaPhone } from 'app/utils/os' import { SOLANA_DAPP_STORE_LINK } from 'app/utils/playStore' @@ -68,7 +66,6 @@ export const RateCtaDrawer = () => { const handleReviewConfirm = useCallback(() => { const isAvailable = isSolanaPhone ? true : InAppReview.isAvailable() - track(make({ eventName: Name.RATE_CTA_RESPONSE_YES })) setUserRateResponse('YES') AsyncStorage.setItem(RATE_CTA_STORAGE_KEY, 'YES') @@ -88,7 +85,6 @@ export const RateCtaDrawer = () => { }, []) const handleReviewDeny = useCallback(() => { - track(make({ eventName: Name.RATE_CTA_RESPONSE_NO })) setUserRateResponse('NO') AsyncStorage.setItem(RATE_CTA_STORAGE_KEY, 'NO') }, []) diff --git a/packages/mobile/src/screens/app-drawer-screen/left-nav-drawer/MessagesNavItem.tsx b/packages/mobile/src/screens/app-drawer-screen/left-nav-drawer/MessagesNavItem.tsx index 31fa49329f7..086d218c966 100644 --- a/packages/mobile/src/screens/app-drawer-screen/left-nav-drawer/MessagesNavItem.tsx +++ b/packages/mobile/src/screens/app-drawer-screen/left-nav-drawer/MessagesNavItem.tsx @@ -1,11 +1,9 @@ -import React, { useCallback } from 'react' +import React from 'react' -import { Name } from '@audius/common/models' import { chatSelectors } from '@audius/common/store' import { useSelector } from 'react-redux' import { IconMessages, NotificationCount } from '@audius/harmony-native' -import { make } from 'app/services/analytics' import { LeftNavLink } from './LeftNavLink' @@ -15,17 +13,12 @@ export const MessagesNavItem = () => { const hasUnreadMessages = useSelector(getHasUnreadMessages) const unreadMessagesCount = useSelector(getUnreadMessagesCount) - const handleMessagesPress = useCallback(() => { - make({ eventName: Name.CHAT_ENTRY_POINT, source: 'navmenu' }) - }, []) - return ( {unreadMessagesCount > 0 ? ( diff --git a/packages/mobile/src/screens/chat-screen/ChatBlastCTA.tsx b/packages/mobile/src/screens/chat-screen/ChatBlastCTA.tsx index 1b65dd81c19..baec3e3afe8 100644 --- a/packages/mobile/src/screens/chat-screen/ChatBlastCTA.tsx +++ b/packages/mobile/src/screens/chat-screen/ChatBlastCTA.tsx @@ -1,7 +1,6 @@ import React, { useCallback } from 'react' import { useCanSendChatBlast } from '@audius/common/hooks' -import { Name } from '@audius/common/models' import { playbackSelectors } from '@audius/common/store' import { TouchableHighlight } from 'react-native-gesture-handler' import { useSelector } from 'react-redux' @@ -15,7 +14,6 @@ import { } from '@audius/harmony-native' import { KeyboardAvoidingView } from 'app/components/core' import { PLAY_BAR_HEIGHT } from 'app/components/now-playing-drawer/constants' -import { make, track } from 'app/services/analytics' import { useAppTabNavigation } from '../app-screen' @@ -39,7 +37,6 @@ export const ChatBlastCTA = () => { const handleClick = useCallback(() => { navigation.navigate('CreateChatBlast') - track(make({ eventName: Name.CHAT_BLAST_CTA_CLICKED })) }, [navigation]) const userMeetsRequirements = useCanSendChatBlast() diff --git a/packages/mobile/src/screens/chat-screen/ChatMessagePlaylist.tsx b/packages/mobile/src/screens/chat-screen/ChatMessagePlaylist.tsx index 18db0047ab0..25cc5713132 100644 --- a/packages/mobile/src/screens/chat-screen/ChatMessagePlaylist.tsx +++ b/packages/mobile/src/screens/chat-screen/ChatMessagePlaylist.tsx @@ -7,7 +7,7 @@ import { } from '@audius/common/api' import { usePlayTrack, usePauseTrack } from '@audius/common/hooks' import type { TrackPlayback } from '@audius/common/hooks' -import { Name, PlaybackSource, Kind } from '@audius/common/models' +import { PlaybackSource, Kind } from '@audius/common/models' import type { ID } from '@audius/common/models' import { QueueSource, playbackSelectors } from '@audius/common/store' import type { ChatMessageTileProps } from '@audius/common/store' @@ -120,11 +120,6 @@ export const ChatMessagePlaylist = ({ const collectionExists = !!collection useEffect(() => { if (collectionExists && uid) { - trackEvent( - make({ - eventName: Name.MESSAGE_UNFURL_PLAYLIST - }) - ) onSuccess?.() } else { onEmpty?.() diff --git a/packages/mobile/src/screens/chat-screen/ChatMessageTrack.tsx b/packages/mobile/src/screens/chat-screen/ChatMessageTrack.tsx index cecec992c3f..256ab441148 100644 --- a/packages/mobile/src/screens/chat-screen/ChatMessageTrack.tsx +++ b/packages/mobile/src/screens/chat-screen/ChatMessageTrack.tsx @@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo } from 'react' import { useTrackByPermalink, useUser } from '@audius/common/api' import { useGatedContentAccess, useToggleTrack } from '@audius/common/hooks' import type { TrackPlayback } from '@audius/common/hooks' -import { Name, PlaybackSource, Kind } from '@audius/common/models' +import { PlaybackSource, Kind } from '@audius/common/models' import type { ID } from '@audius/common/models' import { QueueSource } from '@audius/common/store' import type { ChatMessageTileProps } from '@audius/common/store' @@ -68,11 +68,6 @@ export const ChatMessageTrack = ({ useEffect(() => { if (trackExists && user && uid) { - trackEvent( - make({ - eventName: Name.MESSAGE_UNFURL_TRACK - }) - ) onSuccess?.() } else { onEmpty?.() diff --git a/packages/mobile/src/screens/chat-screen/ChatScreen.tsx b/packages/mobile/src/screens/chat-screen/ChatScreen.tsx index 8055adb86a7..bb1a7706d0f 100644 --- a/packages/mobile/src/screens/chat-screen/ChatScreen.tsx +++ b/packages/mobile/src/screens/chat-screen/ChatScreen.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef } from 'react' import { useCurrentUserId } from '@audius/common/api' import { useCanSendMessage } from '@audius/common/hooks' -import { Name, Status } from '@audius/common/models' +import { Status } from '@audius/common/models' import type { ChatMessageWithExtras } from '@audius/common/models' import { chatActions, @@ -16,7 +16,6 @@ import { } from '@audius/common/utils' import { OptionalHashId, OptionalId, type ChatBlast } from '@audius/sdk' import { Portal } from '@gorhom/portal' -import AsyncStorage from '@react-native-async-storage/async-storage' import { useFocusEffect } from '@react-navigation/native' import type { FlatListProps, LayoutChangeEvent } from 'react-native' import { @@ -41,11 +40,9 @@ import { } from 'app/components/core' import LoadingSpinner from 'app/components/loading-spinner' import { PLAY_BAR_HEIGHT } from 'app/components/now-playing-drawer' -import { VIEWED_BLAST_CHATS_KEY } from 'app/constants/storage-keys' import { light } from 'app/haptics' import { useRoute } from 'app/hooks/useRoute' import { useToast } from 'app/hooks/useToast' -import { make, track } from 'app/services/analytics' import { setVisibility } from 'app/store/drawers/slice' import { makeStyles } from 'app/styles' import { spacing } from 'app/styles/spacing' @@ -292,37 +289,6 @@ export const ChatScreen = () => { } }, [chatId, dispatch]) - // Track when a user opens a blast DM thread. Fires once per blast per user. - useEffect(() => { - if (!chatId || !chat?.is_blast) return - const blastChat = chat as ChatBlast - const trackBlastViewed = async () => { - try { - const raw = await AsyncStorage.getItem(VIEWED_BLAST_CHATS_KEY) - const viewed: string[] = raw ? JSON.parse(raw) : [] - if (!Array.isArray(viewed) || viewed.includes(chatId)) return - await AsyncStorage.setItem( - VIEWED_BLAST_CHATS_KEY, - JSON.stringify([...viewed, chatId]) - ) - track( - make({ - eventName: Name.CHAT_BLAST_MESSAGE_VIEWED, - isNativeMobile: true, - chatId, - audience: blastChat.audience, - audienceContentType: blastChat.audience_content_type, - audienceContentId: - OptionalHashId.parse(blastChat.audience_content_id) ?? undefined - }) - ) - } catch { - // Ignore storage failures; worst case the event fires again later. - } - } - trackBlastViewed() - }, [chatId, chat]) - // Fetch all permissions, blockers/blockees, and recheck_permissions flag useEffect(() => { dispatch(fetchBlockees()) diff --git a/packages/mobile/src/screens/collection-screen/CollectionScreenDetailsTile.tsx b/packages/mobile/src/screens/collection-screen/CollectionScreenDetailsTile.tsx index e43bcc3e4c7..67c486c2c52 100644 --- a/packages/mobile/src/screens/collection-screen/CollectionScreenDetailsTile.tsx +++ b/packages/mobile/src/screens/collection-screen/CollectionScreenDetailsTile.tsx @@ -153,30 +153,6 @@ const recordPlay = ( ) } -const recordPlaylistPlay = ({ - collectionId, - isAlbum, - trackCount, - isPreview -}: { - collectionId: Maybe - isAlbum: boolean - trackCount: number - isPreview?: boolean -}) => { - if (collectionId == null) return - track( - make({ - eventName: Name.PLAYLIST_PLAY, - id: String(collectionId), - source: PlaybackSource.PLAYLIST_PAGE, - isAlbum, - trackCount, - isPreview - }) - ) -} - export const CollectionScreenDetailsTile = ({ description, collectionId, @@ -329,12 +305,6 @@ export const CollectionScreenDetailsTile = ({ } else if (!isPlaying && isQueued) { dispatch(playbackActions.play()) recordPlay(playingTrackId, true, numericCollectionId) - recordPlaylistPlay({ - collectionId: numericCollectionId, - isAlbum: !!isAlbum, - trackCount, - isPreview - }) } else if (trackCount > 0 && collectionPlaybackQueue.length > 0) { dispatch( playbackActions.playFrom({ @@ -348,12 +318,6 @@ export const CollectionScreenDetailsTile = ({ true, numericCollectionId ) - recordPlaylistPlay({ - collectionId: numericCollectionId, - isAlbum: !!isAlbum, - trackCount, - isPreview - }) } }, [ @@ -364,8 +328,7 @@ export const CollectionScreenDetailsTile = ({ collectionPlaybackQueue, dispatch, playingTrackId, - numericCollectionId, - isAlbum + numericCollectionId ] ) diff --git a/packages/mobile/src/screens/contest-screen/ContestScreen.tsx b/packages/mobile/src/screens/contest-screen/ContestScreen.tsx index 91b4805b4b4..135123a79d5 100644 --- a/packages/mobile/src/screens/contest-screen/ContestScreen.tsx +++ b/packages/mobile/src/screens/contest-screen/ContestScreen.tsx @@ -3,7 +3,6 @@ import { useEffect, useLayoutEffect, useMemo, - useRef, useState } from 'react' @@ -21,7 +20,7 @@ import { useUnfollowEvent, useUser } from '@audius/common/api' -import { Name, ShareSource } from '@audius/common/models' +import { ShareSource } from '@audius/common/models' import { shareModalUIActions } from '@audius/common/store' import { dayjs, getLocalTimezone } from '@audius/common/utils' import { PortalHost } from '@gorhom/portal' @@ -42,7 +41,6 @@ import { import { UserLink } from 'app/components/user-link' import { useEnterContest } from 'app/hooks/useEnterContest' import { useRoute } from 'app/hooks/useRoute' -import { make, track as trackEvent } from 'app/services/analytics' import { setVisibility } from 'app/store/drawers/slice' import { ContestHero, CONTEST_HERO_HEIGHT } from './ContestHero' @@ -295,36 +293,8 @@ export const ContestScreen = () => { const enterContest = useEnterContest(trackId) const handleEnterContest = useCallback(async () => { - if (trackId != null && eventId != null) { - trackEvent( - make({ - eventName: Name.REMIX_CONTEST_ENTER, - remixContestId: eventId, - trackId - }) - ) - } await enterContest() - }, [enterContest, trackId, eventId]) - - // Fire a Remix Contest: View event the first time the screen resolves - // both a trackId and an eventId. The screen is mounted once per - // navigation push, so a ref guard makes the event idempotent across - // unrelated re-renders (followers count update, scroll-y reaction, - // etc.) while still firing on each fresh push. - const hasFiredViewRef = useRef(false) - useEffect(() => { - if (hasFiredViewRef.current) return - if (trackId == null || eventId == null) return - hasFiredViewRef.current = true - trackEvent( - make({ - eventName: Name.REMIX_CONTEST_VIEW, - remixContestId: eventId, - trackId - }) - ) - }, [trackId, eventId]) + }, [enterContest]) // Hide the stack navigator header — the in-hero back button is the // only back affordance in the Figma (2888-131647). Leaving the diff --git a/packages/mobile/src/screens/contest-screen/tabs/ContestSubmissionsTab.tsx b/packages/mobile/src/screens/contest-screen/tabs/ContestSubmissionsTab.tsx index 78a7ae09c30..72b56e1c105 100644 --- a/packages/mobile/src/screens/contest-screen/tabs/ContestSubmissionsTab.tsx +++ b/packages/mobile/src/screens/contest-screen/tabs/ContestSubmissionsTab.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useCallback, useMemo, useState } from 'react' import { getRemixesQueryKey, @@ -6,13 +6,10 @@ import { useRemixesCount, useRemixesLineup } from '@audius/common/api' -import { Name } from '@audius/common/models' import type { ID } from '@audius/common/models' -import { useFocusedTab } from 'react-native-collapsible-tab-view' import { Divider, FilterButton, Flex, Text } from '@audius/harmony-native' import { TrackLineup } from 'app/components/lineup/TrackLineup' -import { make, track as trackEvent } from 'app/services/analytics' import { useContestPage } from '../ContestPageContext' @@ -59,33 +56,10 @@ const SORT_OPTIONS = [ * gap by hydrating Redux from the tan-query cache immediately. */ export const ContestSubmissionsTab = () => { - const { trackId, eventId } = useContestPage() + const { trackId } = useContestPage() const { data: contest } = useRemixContest(trackId) const winnerCount = contest?.eventData?.winners?.length ?? 0 - // Fire a Remix Contest: View Submissions event the first time the - // user actually focuses this tab. Tabs are mounted eagerly - // (`lazy: false` in `CollapsibleTabNavigator`), so a plain mount - // effect would fire even for users who only ever look at the Details - // tab. `useFocusedTab` from react-native-collapsible-tab-view is the - // primitive the tab navigator already uses — it returns the - // currently-focused tab name and re-runs effects when that changes. - const focusedTab = useFocusedTab() - const hasFiredSubmissionsViewRef = useRef(false) - useEffect(() => { - if (hasFiredSubmissionsViewRef.current) return - if (focusedTab !== 'Submissions') return - if (trackId == null || eventId == null) return - hasFiredSubmissionsViewRef.current = true - trackEvent( - make({ - eventName: Name.REMIX_CONTEST_VIEW_SUBMISSIONS, - remixContestId: eventId, - trackId - }) - ) - }, [focusedTab, trackId, eventId]) - const [sortMethod, setSortMethod] = useState<'recent' | 'plays' | 'likes'>( 'recent' ) diff --git a/packages/mobile/src/screens/edit-track-screen/EditTrackForm.tsx b/packages/mobile/src/screens/edit-track-screen/EditTrackForm.tsx index c777720867f..c8e1feb0c2c 100644 --- a/packages/mobile/src/screens/edit-track-screen/EditTrackForm.tsx +++ b/packages/mobile/src/screens/edit-track-screen/EditTrackForm.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react' import { useUpdateTrack } from '@audius/common/api' -import { DownloadQuality, Name } from '@audius/common/models' +import { DownloadQuality } from '@audius/common/models' import type { TrackForUpload } from '@audius/common/store' import { useWaitForDownloadModal, @@ -30,7 +30,6 @@ import { PickArtworkField, TextField } from 'app/components/fields' import { useNavigation } from 'app/hooks/useNavigation' import { useTrackFileSelector } from 'app/hooks/useTrackFileSelector' import { FormScreen } from 'app/screens/form-screen' -import { make, track as trackEvent } from 'app/services/analytics' import { setVisibility } from 'app/store/drawers/slice' import { makeStyles } from 'app/styles' @@ -153,16 +152,7 @@ export const EditTrackForm = (props: EditTrackFormProps) => { } selectFile() - - // Track Replace event - trackEvent( - make({ - eventName: Name.TRACK_REPLACE_REPLACE, - trackId: values.track_id, - source: isUpload ? 'upload' : 'edit' - }) - ) - }, [selectFile, isUpload, values.track_id]) + }, [selectFile]) // Handle when a new track file is selected useEffect(() => { @@ -180,24 +170,8 @@ export const EditTrackForm = (props: EditTrackFormProps) => { ? selectedTrack.file.uri : selectedTrack.file.name setSelectedTrackFile(fileUri) - - // Track replace event - trackEvent( - make({ - eventName: Name.TRACK_REPLACE_REPLACE, - trackId: values.track_id, - source: isUpload ? 'upload' : 'edit' - }) - ) } - }, [ - selectedTrack, - setTitle, - setOrigFilename, - values.track_id, - isUpload, - isTitleTouched - ]) + }, [selectedTrack, setTitle, setOrigFilename, isUpload, isTitleTouched]) const handleDownload = useCallback(() => { if (!initialValues.track_id) { @@ -209,14 +183,6 @@ export const EditTrackForm = (props: EditTrackFormProps) => { trackIds: [initialValues.track_id], quality: DownloadQuality.ORIGINAL }) - - // Track Download event - trackEvent( - make({ - eventName: Name.TRACK_REPLACE_DOWNLOAD, - trackId: initialValues.track_id - }) - ) }, [openWaitForDownload, initialValues.track_id]) const handlePressBack = useCallback(() => { diff --git a/packages/mobile/src/screens/edit-track-screen/components/FileReplaceContainer.tsx b/packages/mobile/src/screens/edit-track-screen/components/FileReplaceContainer.tsx index a5e2d9ecbef..f3421fab990 100644 --- a/packages/mobile/src/screens/edit-track-screen/components/FileReplaceContainer.tsx +++ b/packages/mobile/src/screens/edit-track-screen/components/FileReplaceContainer.tsx @@ -1,7 +1,6 @@ import { useCallback, useContext } from 'react' import type { ID } from '@audius/common/models' -import { Name } from '@audius/common/models' import { Flex, @@ -13,7 +12,6 @@ import { useTheme } from '@audius/harmony-native' import { EditTrackFormPreviewContext } from 'app/screens/edit-track-screen/EditTrackFormPreviewContext' -import { make, track as trackEvent } from 'app/services/analytics' type FileReplaceContainerProps = { fileName: string @@ -27,8 +25,6 @@ type FileReplaceContainerProps = { export const FileReplaceContainer = ({ fileName, filePath, - trackId, - isUpload = false, onMenuButtonPress }: FileReplaceContainerProps) => { const { spacing } = useTheme() @@ -41,17 +37,8 @@ export const FileReplaceContainer = ({ stopPreview() } else { playPreview(filePath) - - // Track Preview event - trackEvent( - make({ - eventName: Name.TRACK_REPLACE_PREVIEW, - trackId, - source: isUpload ? 'upload' : 'edit' - }) - ) } - }, [filePath, isPlaying, isUpload, playPreview, stopPreview, trackId]) + }, [filePath, isPlaying, playPreview, stopPreview]) return ( { const { inView, InViewWrapper } = useDeferredElement() - const { trackEvent } = useAnalytics() - - useEffect(() => { - if (inView) { - trackEvent({ - eventName: Name.EXPLORE_SECTION_VIEW, - section: sectionName, - source: 'mobile' - }) - } - }, [inView, sectionName, trackEvent]) return { inView, InViewWrapper } } diff --git a/packages/mobile/src/screens/profile-screen/MessageButton.tsx b/packages/mobile/src/screens/profile-screen/MessageButton.tsx index 05a21d1438b..85e2bc7cae2 100644 --- a/packages/mobile/src/screens/profile-screen/MessageButton.tsx +++ b/packages/mobile/src/screens/profile-screen/MessageButton.tsx @@ -1,12 +1,10 @@ import { useCallback } from 'react' import type { ID } from '@audius/common/models' -import { Name } from '@audius/common/models' import { chatActions } from '@audius/common/store' import { useDispatch } from 'react-redux' import { IconMessage, Button } from '@audius/harmony-native' -import { make, track } from 'app/services/analytics' const { createChat } = chatActions @@ -24,7 +22,6 @@ export const MessageButton = (props: MessageButtonProps) => { const handlePress = useCallback(() => { dispatch(createChat({ userIds: [userId] })) - track(make({ eventName: Name.CHAT_ENTRY_POINT, source: 'profile' })) }, [dispatch, userId]) return ( diff --git a/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileInfoTiles.tsx b/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileInfoTiles.tsx index 184c2309ed1..2949025914e 100644 --- a/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileInfoTiles.tsx +++ b/packages/mobile/src/screens/profile-screen/ProfileHeader/ProfileInfoTiles.tsx @@ -10,7 +10,6 @@ import { useProfileUser } from '@audius/common/api' import type { UserMetadata } from '@audius/common/models' -import { Name } from '@audius/common/models' import { View, ScrollView } from 'react-native' import Animated, { FadeIn, @@ -32,7 +31,6 @@ import { ProfilePictureList, ProfilePictureListSkeleton } from 'app/screens/notifications-screen/Notification' -import { make, track as trackEvent } from 'app/services/analytics' import { makeStyles } from 'app/styles' import type { SvgProps } from 'app/types/svg' import { useThemePalette } from 'app/utils/theme' @@ -264,13 +262,7 @@ export const ProfileInfoTiles = () => { }, []) const onOpenRecentCommentsDrawer = useCallback(() => { setIsRecentCommentsDrawerOpen(true) - trackEvent( - make({ - eventName: Name.COMMENTS_HISTORY_DRAWER_OPEN, - userId: user_id - }) - ) - }, [user_id]) + }, []) const { data: accountId } = useCurrentUserId() diff --git a/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx b/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx index 343a0e674e1..065613e4f75 100644 --- a/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx +++ b/packages/mobile/src/screens/profile-screen/ProfileHeader/SocialLink.tsx @@ -14,9 +14,7 @@ import { } from '@audius/harmony-native' import type { LinkProps } from 'app/components/core' import { Link, UserGeneratedText } from 'app/components/core' -import { make } from 'app/services/analytics' import { makeStyles } from 'app/styles' -import { EventNames } from 'app/types/analytics' import { prependProtocol } from 'app/utils/prependProtocol' const useStyles = makeStyles(({ spacing }) => ({ @@ -117,26 +115,18 @@ export const SocialLink = (props: SocialLinkProps) => { type XSocialLinkProps = Partial export const XSocialLink = (props: XSocialLinkProps) => { - const { handle, x_handle } = + const { x_handle } = useProfileUser({ select: (user) => ({ - handle: user.handle, x_handle: user.twitter_handle }) }).user ?? {} - const sanitizedHandle = handle?.replace('@', '') - return ( ) @@ -145,26 +135,18 @@ export const XSocialLink = (props: XSocialLinkProps) => { type InstagramSocialLinkProps = Partial export const InstagramSocialLink = (props: InstagramSocialLinkProps) => { - const { handle, instagram_handle } = + const { instagram_handle } = useProfileUser({ select: (user) => ({ - handle: user.handle, instagram_handle: user.instagram_handle }) }).user ?? {} - const sanitizedHandle = handle?.replace('@', '') - return ( ) @@ -173,26 +155,18 @@ export const InstagramSocialLink = (props: InstagramSocialLinkProps) => { type TikTokSocialLinkProps = Partial export const TikTokSocialLink = (props: TikTokSocialLinkProps) => { - const { handle, tiktok_handle } = + const { tiktok_handle } = useProfileUser({ select: (user) => ({ - handle: user.handle, tiktok_handle: user.tiktok_handle }) }).user ?? {} - const sanitizedHandle = handle?.replace('@', '') - return ( ) diff --git a/packages/mobile/src/screens/rewards-screen/ChallengeRewardsTile.tsx b/packages/mobile/src/screens/rewards-screen/ChallengeRewardsTile.tsx index 111ab1c63f5..00a3c600ee0 100644 --- a/packages/mobile/src/screens/rewards-screen/ChallengeRewardsTile.tsx +++ b/packages/mobile/src/screens/rewards-screen/ChallengeRewardsTile.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { useCurrentAccount, useCurrentAccountUser } from '@audius/common/api' -import { Name, ChallengeName } from '@audius/common/models' +import { ChallengeName } from '@audius/common/models' import type { ChallengeRewardID } from '@audius/common/models' import { challengesSelectors, @@ -42,7 +42,6 @@ import LoadingSpinner from 'app/components/loading-spinner' import type { SummaryTableItem } from 'app/components/summary-table/SummaryTable' import { useNavigation } from 'app/hooks/useNavigation' import type { ProfileTabScreenParamList } from 'app/screens/app-screen/ProfileTabScreen' -import { make, track } from 'app/services/analytics' import { makeStyles } from 'app/styles' import { getChallengeConfig } from 'app/utils/challenges' import { isDarkTheme, useThemeVariant } from 'app/utils/theme' @@ -217,12 +216,6 @@ export const ChallengeRewardsTile = () => { const props = getChallengeConfig(id) const onPress = () => { openModal(id) - track( - make({ - eventName: Name.REWARDS_CLAIM_DETAILS_OPENED, - challengeId: id - }) - ) } return ( { const props = getChallengeConfig(id) const onPress = () => { openModal(id) - track( - make({ - eventName: Name.REWARDS_CLAIM_DETAILS_OPENED, - challengeId: id - }) - ) } return ( { const props = getChallengeConfig(id) const onPress = () => { openModal(id) - track( - make({ - eventName: Name.REWARDS_CLAIM_DETAILS_OPENED, - challengeId: id - }) - ) } return ( { const dispatch = useDispatch() - const [query] = useSearchQuery() const handlePress = useCallback(() => { dispatch(addRecentSearch({ searchItem: item })) - - record( - make({ - eventName: Name.SEARCH_RESULT_SELECT, - term: query, - source: 'search results page', - id: item.id, - kind: { - [Kind.COLLECTIONS]: item.isAlbum ? 'album' : 'playlist', - [Kind.TRACKS]: 'track', - [Kind.USERS]: 'profile' - }[item.kind] - }) - ) - }, [item, dispatch, query]) + }, [item, dispatch]) return item.isLoading ? ( diff --git a/packages/mobile/src/screens/search-screen/search-results/PlaylistResults.tsx b/packages/mobile/src/screens/search-screen/search-results/PlaylistResults.tsx index ade60ebb2ca..104bb6e9bd1 100644 --- a/packages/mobile/src/screens/search-screen/search-results/PlaylistResults.tsx +++ b/packages/mobile/src/screens/search-screen/search-results/PlaylistResults.tsx @@ -2,13 +2,12 @@ import { useCallback } from 'react' import { useSearchPlaylistResults } from '@audius/common/api' import type { ID } from '@audius/common/models' -import { Kind, Name } from '@audius/common/models' +import { Kind } from '@audius/common/models' import { searchActions } from '@audius/common/store' import { useDispatch } from 'react-redux' import { Flex, useTheme } from '@audius/harmony-native' import { CollectionList } from 'app/components/collection-list/CollectionList' -import { make, track as record } from 'app/services/analytics' import { NoResultsTile } from '../NoResultsTile' import { SearchCatalogTile } from '../SearchCatalogTile' @@ -46,18 +45,8 @@ export const PlaylistResults = () => { } }) ) - - record( - make({ - eventName: Name.SEARCH_RESULT_SELECT, - term: query, - source: 'search results page', - id, - kind: 'playlist' - }) - ) }, - [dispatch, query] + [dispatch] ) if (isEmptySearch) return diff --git a/packages/mobile/src/screens/search-screen/search-results/ProfileResults.tsx b/packages/mobile/src/screens/search-screen/search-results/ProfileResults.tsx index f3742582754..d703833bd7c 100644 --- a/packages/mobile/src/screens/search-screen/search-results/ProfileResults.tsx +++ b/packages/mobile/src/screens/search-screen/search-results/ProfileResults.tsx @@ -2,13 +2,12 @@ import { useCallback } from 'react' import { useSearchUserResults } from '@audius/common/api' import type { ID } from '@audius/common/models' -import { Kind, Name } from '@audius/common/models' +import { Kind } from '@audius/common/models' import { searchActions } from '@audius/common/store' import { useDispatch } from 'react-redux' import { Flex, useTheme } from '@audius/harmony-native' import { UserCardList } from 'app/components/user-card-list' -import { make, track as record } from 'app/services/analytics' import { NoResultsTile } from '../NoResultsTile' import { SearchCatalogTile } from '../SearchCatalogTile' @@ -46,18 +45,8 @@ export const ProfileResults = () => { } }) ) - - record( - make({ - eventName: Name.SEARCH_RESULT_SELECT, - term: query, - source: 'search results page', - id, - kind: 'profile' - }) - ) }, - [dispatch, query] + [dispatch] ) if (isEmptySearch) return diff --git a/packages/mobile/src/screens/search-screen/search-results/TrackResults.tsx b/packages/mobile/src/screens/search-screen/search-results/TrackResults.tsx index 43df225876d..5bd35ec944b 100644 --- a/packages/mobile/src/screens/search-screen/search-results/TrackResults.tsx +++ b/packages/mobile/src/screens/search-screen/search-results/TrackResults.tsx @@ -2,14 +2,13 @@ import { useCallback, useMemo } from 'react' import { useSearchTrackResults } from '@audius/common/api' import type { ID } from '@audius/common/models' -import { Kind, Name } from '@audius/common/models' +import { Kind } from '@audius/common/models' import { searchActions } from '@audius/common/store' import { Keyboard } from 'react-native' import { useDispatch } from 'react-redux' import { Flex } from '@audius/harmony-native' import { TrackLineup } from 'app/components/lineup/TrackLineup' -import { make, track as record } from 'app/services/analytics' import { NoResultsTile } from '../NoResultsTile' import { SearchCatalogTile } from '../SearchCatalogTile' @@ -50,18 +49,8 @@ export const TrackResults = () => { } }) ) - - record( - make({ - eventName: Name.SEARCH_RESULT_SELECT, - term: query, - source: 'search results page', - id, - kind: 'track' - }) - ) }, - [dispatch, query] + [dispatch] ) const querySource = useMemo( diff --git a/packages/mobile/src/screens/settings-screen/AppearanceSettingsRow.tsx b/packages/mobile/src/screens/settings-screen/AppearanceSettingsRow.tsx index f6789bd3baa..3cd2e47f511 100644 --- a/packages/mobile/src/screens/settings-screen/AppearanceSettingsRow.tsx +++ b/packages/mobile/src/screens/settings-screen/AppearanceSettingsRow.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react' import { useCurrentUserId } from '@audius/common/api' import { settingsMessages as messages } from '@audius/common/messages' -import { Name, Theme, ThemeMode, ThemePalette } from '@audius/common/models' +import { Theme, ThemeMode, ThemePalette } from '@audius/common/models' import { useTierAndVerifiedForUser, themeActions, @@ -13,7 +13,6 @@ import { useDispatch, useSelector } from 'react-redux' import { IconAppearance, Flex } from '@audius/harmony-native' import { SegmentedControl } from 'app/components/core' -import { make, track } from 'app/services/analytics' import { SettingsRowLabel } from './SettingRowLabel' import { SettingsRow } from './SettingsRow' @@ -69,13 +68,6 @@ export const AppearanceSettingsRow = () => { dispatch(setTheme({ theme: Theme.MATRIX })) dispatch(showMusicConfetti()) } - track( - make({ - eventName: Name.SETTINGS_CHANGE_THEME, - mode: 'palette', - palette: value - } as any) - ) }, [dispatch] ) @@ -90,12 +82,6 @@ export const AppearanceSettingsRow = () => { ? Theme.DARK : Theme.AUTO dispatch(setTheme({ theme: themeValue })) - track( - make({ - eventName: Name.SETTINGS_CHANGE_THEME, - mode: option.toLowerCase() as 'dark' | 'light' | 'auto' - }) - ) }, [dispatch] ) diff --git a/packages/mobile/src/screens/track-screen/DownloadSection.tsx b/packages/mobile/src/screens/track-screen/DownloadSection.tsx index ccaf7376a19..40c03510a4a 100644 --- a/packages/mobile/src/screens/track-screen/DownloadSection.tsx +++ b/packages/mobile/src/screens/track-screen/DownloadSection.tsx @@ -25,9 +25,6 @@ import { } from '@audius/harmony-native' import { Expandable, ExpandableArrowIcon } from 'app/components/expandable' import { useToast } from 'app/hooks/useToast' -import { make, track as trackEvent } from 'app/services/analytics' -import type { AllEvents } from 'app/types/analytics' -import { EventNames } from 'app/types/analytics' import { DownloadRow } from './DownloadRow' @@ -99,24 +96,6 @@ export const DownloadSection = ({ trackId }: { trackId: ID }) => { trackIds, quality: downloadQuality }) - - // Track download attempt event - let event: AllEvents - if (parentTrackId) { - event = { - eventName: EventNames.TRACK_DOWNLOAD_CLICKED_DOWNLOAD_ALL, - parentTrackId, - stemTrackIds: trackIds, - device: 'native' - } - } else { - event = { - eventName: EventNames.TRACK_DOWNLOAD_CLICKED_DOWNLOAD_SINGLE, - trackId: trackIds[0], - device: 'native' - } - } - trackEvent(make(event)) } }, [ diff --git a/packages/mobile/src/screens/track-screen/TrackScreenDetailsTile.tsx b/packages/mobile/src/screens/track-screen/TrackScreenDetailsTile.tsx index 589fa7c3908..e54987315db 100644 --- a/packages/mobile/src/screens/track-screen/TrackScreenDetailsTile.tsx +++ b/packages/mobile/src/screens/track-screen/TrackScreenDetailsTile.tsx @@ -428,13 +428,6 @@ export const TrackScreenDetailsTile = ({ navigation, playbackSource: 'TRACK_TRACKS' }) - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_COMMENT_STAT, - trackId, - source: 'track_page' - }) - ) }, [openCommentDrawer, trackId, navigation]) const handlePressSave = useToggleFavoriteTrack({ diff --git a/packages/mobile/src/screens/upload-screen/screens/UploadCompleteScreen.tsx b/packages/mobile/src/screens/upload-screen/screens/UploadCompleteScreen.tsx index 1ea2dc1200e..097460fbecc 100644 --- a/packages/mobile/src/screens/upload-screen/screens/UploadCompleteScreen.tsx +++ b/packages/mobile/src/screens/upload-screen/screens/UploadCompleteScreen.tsx @@ -1,10 +1,9 @@ import React, { useCallback } from 'react' import { useTrack } from '@audius/common/api' -import { Name, ShareSource } from '@audius/common/models' +import { ShareSource } from '@audius/common/models' import type { CommonState } from '@audius/common/store' import { shareModalUIActions, uploadActions } from '@audius/common/store' -import { make } from '@audius/web/src/common/store/analytics/actions' import { View, Image } from 'react-native' import { useDispatch, useSelector } from 'react-redux' @@ -105,7 +104,6 @@ export const UploadCompleteScreen = () => { defaultUserList: 'chats' }) ) - dispatch(make(Name.CHAT_ENTRY_POINT, { source: 'upload' })) handleClose() }, [dispatch, handleClose, navigation, trackRoute]) diff --git a/packages/mobile/src/services/analytics.ts b/packages/mobile/src/services/analytics.ts index 0556775c231..61b74627b01 100644 --- a/packages/mobile/src/services/analytics.ts +++ b/packages/mobile/src/services/analytics.ts @@ -4,16 +4,23 @@ import { setUserId, identify as amplitudeIdentify, Identify, + getDeviceId, Types as AmplitudeTypes } from '@amplitude/analytics-react-native' import type { IdentifyTraits } from '@audius/common/models' +import { + CORE_ANALYTICS_EVENTS, + getAnalyticsSampleRate +} from '@audius/common/models' +import AsyncStorage from '@react-native-async-storage/async-storage' +import { Platform } from 'react-native' import VersionNumber from 'react-native-version-number' import { env } from 'app/services/env' import packageInfo from '../../package.json' import type { Track, Screen, AllEvents } from '../types/analytics' -import { EventNames } from '../types/analytics' +import { EventNames, MOBILE_CORE_EVENTS } from '../types/analytics' const { version: clientVersion } = packageInfo @@ -23,6 +30,10 @@ const AmplitudeWriteKey = env.AMPLITUDE_API_KEY const AmplitudeProxy = env.AMPLITUDE_PROXY const IS_PRODUCTION_BUILD = process.env.NODE_ENV === 'production' +const IDENTIFY_TRAITS_KEY = 'amplitude:identifiedTraits' +const CLIENT_IDENTIFIED_KEY = 'amplitude:clientIdentified' +const WEEK_MS = 7 * 24 * 60 * 60 * 1000 + export const init = async () => { try { if (AmplitudeWriteKey && AmplitudeProxy) { @@ -39,6 +50,7 @@ export const init = async () => { minIdLength: 1 // By default amplitude rejects our handle ids if they're less than 5 characters }) analyticsSetupStatus = 'ready' + identifyClient().catch(() => {}) } else { analyticsSetupStatus = 'error' console.error( @@ -51,6 +63,24 @@ export const init = async () => { } } +const coreEvents: ReadonlySet = new Set([ + ...CORE_ANALYTICS_EVENTS, + ...MOBILE_CORE_EVENTS +]) + +// Which client the user is on, as a user property set once per install +const identifyClient = async () => { + const client = Platform.OS === 'ios' ? 'iOS App' : 'Android App' + const previous = await AsyncStorage.getItem(CLIENT_IDENTIFIED_KEY).catch( + () => null + ) + if (previous === client) return + const identifyObj = new Identify() + identifyObj.set('client', client) + await amplitudeIdentify(identifyObj) + await AsyncStorage.setItem(CLIENT_IDENTIFIED_KEY, client).catch(() => {}) +} + const isAudiusSetup = async () => { if (analyticsSetupStatus === 'pending') { const ready = await new Promise((resolve, reject) => { @@ -84,20 +114,45 @@ export const identify = async (traits: IdentifyTraits) => { if (traits.handle) { setUserId(traits.handle) } + + // User properties persist in Amplitude, so skip an identify that would set + // the same values again (it runs on every account load). Resend weekly in + // case an earlier one was dropped. + const serializedTraits = JSON.stringify([ + Math.floor(Date.now() / WEEK_MS), + Object.keys(traits) + .sort() + .map((k) => [k, traits[k as keyof IdentifyTraits]]) + ]) + const previousTraits = await AsyncStorage.getItem(IDENTIFY_TRAITS_KEY).catch( + () => null + ) + if (previousTraits === serializedTraits) return + const identifyObj = new Identify() Object.entries(traits).forEach(([key, value]) => { identifyObj.set(key, value) }) await amplitudeIdentify(identifyObj) + await AsyncStorage.setItem(IDENTIFY_TRAITS_KEY, serializedTraits).catch( + () => {} + ) } // Track Event export const track = async ({ eventName, properties }: Track) => { const isSetup = await isAudiusSetup() if (!isSetup) return + const sampleRate = getAnalyticsSampleRate( + eventName, + getDeviceId(), + coreEvents + ) + if (sampleRate === null) return const version = VersionNumber.appVersion const propertiesWithContext = { ...properties, + ...(sampleRate < 1 ? { sampleRate } : {}), clientVersion, isNativeMobile: true, mobileClientVersion: version diff --git a/packages/mobile/src/services/track-download.ts b/packages/mobile/src/services/track-download.ts index ffebfe478df..8f29192216f 100644 --- a/packages/mobile/src/services/track-download.ts +++ b/packages/mobile/src/services/track-download.ts @@ -14,9 +14,7 @@ import ReactNativeBlobUtil from 'react-native-blob-util' import { zip } from 'react-native-zip-archive' import { dedupFilenames } from '~/utils' -import { make, track as trackEvent } from 'app/services/analytics' import { dispatch } from 'app/store' -import { EventNames } from 'app/types/analytics' const { downloadFinished } = tracksSocialActions const { beginDownload, setDownloadError, setFetchCancel, setFileInfo } = @@ -69,14 +67,6 @@ const downloadOne = async ({ const fetchRes = await fetchTask await onFetchComplete?.(fetchRes.path()) - - // Track download success event - trackEvent( - make({ - eventName: EventNames.TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_SINGLE, - device: 'native' - }) - ) } catch (err) { console.error(err) dispatch( @@ -86,14 +76,6 @@ const downloadOne = async ({ ) // On failure attempt to delete the file removePathIfExists(filePath) - - // Track download failure event - trackEvent( - make({ - eventName: EventNames.TRACK_DOWNLOAD_FAILED_DOWNLOAD_SINGLE, - device: 'native' - }) - ) } } @@ -129,14 +111,6 @@ const downloadMany = async ({ await zip(tempDir, directory + '.zip') await onFetchComplete?.(directory + '.zip') - - // Track download success event - trackEvent( - make({ - eventName: EventNames.TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_ALL, - device: 'native' - }) - ) } catch (err) { console.error(err) dispatch( @@ -144,14 +118,6 @@ const downloadMany = async ({ err instanceof Error ? err : new Error(`Download failed: ${err}`) ) ) - - // Track download failure event - trackEvent( - make({ - eventName: EventNames.TRACK_DOWNLOAD_FAILED_DOWNLOAD_ALL, - device: 'native' - }) - ) } finally { // Remove source directory at the end of the process regardless of what happens removePathIfExists(tempDir) diff --git a/packages/mobile/src/store/offline-downloads/sagas/migrateOfflineDataPathSaga.ts b/packages/mobile/src/store/offline-downloads/sagas/migrateOfflineDataPathSaga.ts index d4ca88eca23..fb72c845b97 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/migrateOfflineDataPathSaga.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/migrateOfflineDataPathSaga.ts @@ -5,7 +5,6 @@ import ReactNativeBlobUtil from 'react-native-blob-util' import RNFS from 'react-native-fs' import { call, put, select } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' import { downloadsRoot } from 'app/services/offline-downloader' import { getOfflineCollectionsStatus, @@ -14,7 +13,6 @@ import { } from 'app/store/offline-downloads/selectors' import type { OfflineJob } from 'app/store/offline-downloads/slice' import { redownloadOfflineItems } from 'app/store/offline-downloads/slice' -import { EventNames } from 'app/types/analytics' import { DOWNLOAD_REASON_FAVORITES } from '../constants' @@ -31,26 +29,9 @@ export function* migrateOfflineDataPathSaga() { const legacyFilesExist = yield* call(exists, legacyDownloadsRoot) if (!legacyFilesExist) return - track( - make({ - eventName: EventNames.OFFLINE_MODE_FILEPATH_MIGRATION_STARTED - }) - ) - try { yield* call(copyRecursive, legacyDownloadsRoot, downloadsRoot) - - track( - make({ - eventName: EventNames.OFFLINE_MODE_FILEPATH_MIGRATION_SUCCESS - }) - ) } catch (e) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_FILEPATH_MIGRATION_FAILURE - }) - ) // If we fail, nuke the legacy directory to ensure we don't retry the process on every startup // also requeue everything for download yield* call(migrationRecovery) diff --git a/packages/mobile/src/store/offline-downloads/sagas/offlineQueueSagas/workers/downloadCollectionWorker.ts b/packages/mobile/src/store/offline-downloads/sagas/offlineQueueSagas/workers/downloadCollectionWorker.ts index cdc9d8045d5..df247458cf1 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/offlineQueueSagas/workers/downloadCollectionWorker.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/offlineQueueSagas/workers/downloadCollectionWorker.ts @@ -13,7 +13,6 @@ import { Id, OptionalId } from '@audius/sdk' import ReactNativeBlobUtil from 'react-native-blob-util' import { select, call, put, take, race, all } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' import { getCollectionCoverArtPath, getLocalCollectionDir, @@ -21,7 +20,6 @@ import { mkdirSafe } from 'app/services/offline-downloader' import { DOWNLOAD_REASON_FAVORITES } from 'app/store/offline-downloads/constants' -import { EventNames } from 'app/types/analytics' import { getCollectionOfflineDownloadStatus } from '../../../selectors' import type { CollectionId, OfflineJob } from '../../../slice' @@ -56,9 +54,6 @@ function* shouldAbortDownload(collectionId: CollectionId) { export function* downloadCollectionWorker(collectionId: CollectionId) { const queueItem: OfflineJob = { type: 'collection', id: collectionId } - track( - make({ eventName: EventNames.OFFLINE_MODE_DOWNLOAD_START, ...queueItem }) - ) yield* put(startJob(queueItem)) const { jobResult, cancel, abortDownload, abortJob } = yield* race({ @@ -80,32 +75,14 @@ export function* downloadCollectionWorker(collectionId: CollectionId) { yield* put(cancelJob(queueItem)) yield* call(removeDownloadedCollection, collectionId) } else if (jobResult === OfflineDownloadStatus.ERROR) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_FAILURE, - ...queueItem - }) - ) yield* put(errorJob(queueItem)) yield* call(removeDownloadedCollection, collectionId) yield* put(requestProcessNextJob()) } else if (jobResult === OfflineDownloadStatus.ABANDONED) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_FAILURE, - ...queueItem - }) - ) yield* put(abandonJob(queueItem)) yield* call(removeDownloadedCollection, collectionId) yield* put(requestProcessNextJob()) } else if (jobResult === OfflineDownloadStatus.SUCCESS) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_SUCCESS, - ...queueItem - }) - ) yield* put(completeJob(queueItem)) yield* put(requestProcessNextJob()) } diff --git a/packages/mobile/src/store/offline-downloads/sagas/offlineQueueSagas/workers/downloadTrackWorker.ts b/packages/mobile/src/store/offline-downloads/sagas/offlineQueueSagas/workers/downloadTrackWorker.ts index a00f63831f6..117e6d65544 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/offlineQueueSagas/workers/downloadTrackWorker.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/offlineQueueSagas/workers/downloadTrackWorker.ts @@ -11,14 +11,12 @@ import { Id, OptionalId } from '@audius/sdk' import ReactNativeBlobUtil from 'react-native-blob-util' import { select, call, put, all, take, race } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' import { getLocalAudioPath, getLocalTrackCoverArtDestination, getLocalTrackDir, getLocalTrackJsonPath } from 'app/services/offline-downloader' -import { EventNames } from 'app/types/analytics' import { getTrackOfflineDownloadStatus } from '../../../selectors' import type { OfflineJob } from '../../../slice' @@ -54,9 +52,6 @@ function* shouldAbortDownload(trackId: ID) { export function* downloadTrackWorker(trackId: ID, requeueCount?: number) { const queueItem: OfflineJob = { type: 'track', id: trackId, requeueCount } - track( - make({ eventName: EventNames.OFFLINE_MODE_DOWNLOAD_START, ...queueItem }) - ) yield* put(startJob(queueItem)) const { jobResult, cancel, abortDownload, abortJob } = yield* race({ @@ -78,12 +73,6 @@ export function* downloadTrackWorker(trackId: ID, requeueCount?: number) { yield* call(removeDownloadedTrack, trackId) yield* put(cancelJob(queueItem)) } else if (jobResult === OfflineDownloadStatus.ERROR) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_FAILURE, - ...queueItem - }) - ) yield* call(removeDownloadedTrack, trackId) if ((requeueCount ?? 0) < MAX_REQUEUE_COUNT - 1) { yield* put(errorJob(queueItem)) @@ -92,22 +81,10 @@ export function* downloadTrackWorker(trackId: ID, requeueCount?: number) { } yield* put(requestProcessNextJob()) } else if (jobResult === OfflineDownloadStatus.ABANDONED) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_FAILURE, - ...queueItem - }) - ) yield* put(abandonJob(queueItem)) yield* call(removeDownloadedTrack, trackId) yield* put(requestProcessNextJob()) } else if (jobResult === OfflineDownloadStatus.SUCCESS) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_SUCCESS, - ...queueItem - }) - ) yield* put(completeJob({ ...queueItem, completedAt: Date.now() })) yield* put(requestProcessNextJob()) } diff --git a/packages/mobile/src/store/offline-downloads/sagas/requestDownloadAllFavoritesSaga.ts b/packages/mobile/src/store/offline-downloads/sagas/requestDownloadAllFavoritesSaga.ts index f4ef2595dd0..de2554d882b 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/requestDownloadAllFavoritesSaga.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/requestDownloadAllFavoritesSaga.ts @@ -10,9 +10,7 @@ import { Id } from '@audius/sdk' import { fetchAllAccountCollections } from 'common/store/saved-collections/sagas' import { takeEvery, select, call, put } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' import { DOWNLOAD_REASON_FAVORITES } from 'app/store/offline-downloads/constants' -import { EventNames } from 'app/types/analytics' import type { OfflineEntry } from '../slice' import { addOfflineEntries, requestDownloadAllFavorites } from '../slice' @@ -24,7 +22,6 @@ export function* requestDownloadAllFavoritesSaga() { } function* downloadAllFavorites() { - track(make({ eventName: EventNames.OFFLINE_MODE_DOWNLOAD_ALL_TOGGLE_ON })) const currentUserId = yield* call(queryCurrentUserId) if (!currentUserId) return diff --git a/packages/mobile/src/store/offline-downloads/sagas/requestDownloadCollectionSaga.ts b/packages/mobile/src/store/offline-downloads/sagas/requestDownloadCollectionSaga.ts index 6fc473431de..d5542e3fc5e 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/requestDownloadCollectionSaga.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/requestDownloadCollectionSaga.ts @@ -8,9 +8,6 @@ import { collectionsSocialActions, getSDK } from '@audius/common/store' import { Id, OptionalId } from '@audius/sdk' import { takeEvery, put, call } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' -import { EventNames } from 'app/types/analytics' - import type { CollectionAction, OfflineEntry } from '../slice' import { addOfflineEntries, requestDownloadCollection } from '../slice' @@ -22,13 +19,6 @@ export function* requestDownloadCollectionSaga() { function* downloadCollection(action: CollectionAction) { const { collectionId } = action.payload - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_COLLECTION_TOGGLE_ON, - collectionId - }) - ) - const currentUserId = yield* call(queryCurrentUserId) if (!currentUserId) return diff --git a/packages/mobile/src/store/offline-downloads/sagas/requestRemoveAllDownloadedFavoritesSaga.ts b/packages/mobile/src/store/offline-downloads/sagas/requestRemoveAllDownloadedFavoritesSaga.ts index 65c84fe8905..982af7d866a 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/requestRemoveAllDownloadedFavoritesSaga.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/requestRemoveAllDownloadedFavoritesSaga.ts @@ -1,8 +1,6 @@ import { takeEvery, select, put } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' import { DOWNLOAD_REASON_FAVORITES } from 'app/store/offline-downloads/constants' -import { EventNames } from 'app/types/analytics' import { getOfflineCollectionMetadata, @@ -27,7 +25,6 @@ export function* requestRemoveAllDownloadedFavoritesSaga() { } function* removeAllDownloadedFavoritesWorker() { - track(make({ eventName: EventNames.OFFLINE_MODE_DOWNLOAD_ALL_TOGGLE_OFF })) const offlineItemsToRemove: OfflineEntry[] = [] const offlineCollectionMetadata = yield* select(getOfflineCollectionMetadata) const offlineCollectionIds = Object.keys(offlineCollectionMetadata).map( diff --git a/packages/mobile/src/store/offline-downloads/sagas/requestRemoveDownloadedCollectionSaga.ts b/packages/mobile/src/store/offline-downloads/sagas/requestRemoveDownloadedCollectionSaga.ts index 758dbcd5115..67c53fed850 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/requestRemoveDownloadedCollectionSaga.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/requestRemoveDownloadedCollectionSaga.ts @@ -1,8 +1,5 @@ import { takeEvery, select, put } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' -import { EventNames } from 'app/types/analytics' - import { getOfflineTrackMetadata } from '../selectors' import type { CollectionAction, OfflineEntry } from '../slice' import { removeOfflineItems, requestRemoveDownloadedCollection } from '../slice' @@ -16,13 +13,6 @@ export function* requestRemoveDownloadedCollectionSaga() { function* removeDownloadedCollectionWorker(action: CollectionAction) { const { collectionId } = action.payload - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_COLLECTION_TOGGLE_OFF, - collectionId - }) - ) - const offlineItemsToRemove: OfflineEntry[] = [] offlineItemsToRemove.push({ diff --git a/packages/mobile/src/store/offline-downloads/sagas/watchSaveCollectionSaga.ts b/packages/mobile/src/store/offline-downloads/sagas/watchSaveCollectionSaga.ts index a877e7b21ee..7a698092bb8 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/watchSaveCollectionSaga.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/watchSaveCollectionSaga.ts @@ -2,9 +2,6 @@ import { FavoriteSource } from '@audius/common/models' import { collectionsSocialActions } from '@audius/common/store' import { takeEvery, select, put } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' -import { EventNames } from 'app/types/analytics' - import { getIsFavoritesDownloadsEnabled } from '../selectors' import { requestDownloadFavoritedCollection } from '../slice' @@ -23,13 +20,6 @@ function* checkIfShouldDownload(action: ReturnType) { isFavoritesDownloadEnabled && source !== FavoriteSource.OFFLINE_DOWNLOAD ) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_REQUEST, - type: 'collection', - id: collectionId - }) - ) yield* put(requestDownloadFavoritedCollection({ collectionId })) } } diff --git a/packages/mobile/src/store/offline-downloads/sagas/watchSaveTrackSaga.ts b/packages/mobile/src/store/offline-downloads/sagas/watchSaveTrackSaga.ts index 5e7debe1902..dcdab7c4780 100644 --- a/packages/mobile/src/store/offline-downloads/sagas/watchSaveTrackSaga.ts +++ b/packages/mobile/src/store/offline-downloads/sagas/watchSaveTrackSaga.ts @@ -2,9 +2,7 @@ import { tracksSocialActions } from '@audius/common/store' import { dayjs } from '@audius/common/utils' import { put, takeEvery, select } from 'typed-redux-saga' -import { make, track } from 'app/services/analytics' import { DOWNLOAD_REASON_FAVORITES } from 'app/store/offline-downloads/constants' -import { EventNames } from 'app/types/analytics' import { getIsFavoritesDownloadsEnabled } from '../selectors' import { addOfflineEntries } from '../slice' @@ -22,13 +20,6 @@ function* downloadSavedTrack( ) if (isFavoritesDownloadEnabled) { - track( - make({ - eventName: EventNames.OFFLINE_MODE_DOWNLOAD_REQUEST, - type: 'track', - id: trackId - }) - ) yield* put( addOfflineEntries({ items: [ diff --git a/packages/mobile/src/store/rate-cta/sagas.ts b/packages/mobile/src/store/rate-cta/sagas.ts index cc06bbab7a2..13aa2072655 100644 --- a/packages/mobile/src/store/rate-cta/sagas.ts +++ b/packages/mobile/src/store/rate-cta/sagas.ts @@ -1,6 +1,4 @@ -import { Name } from '@audius/common/models' import { waitForWrite } from '@audius/web/src/utils/sagaHelpers' -import { make } from 'common/store/analytics/actions' import { call, put, takeEvery } from 'typed-redux-saga' import { setVisibility } from '../drawers/slice' @@ -10,7 +8,6 @@ import { requestReview } from './slice' function* displayRequestReviewDrawer() { yield* call(waitForWrite) yield put(setVisibility({ drawer: 'RateCallToAction', visible: true })) - yield* put(make(Name.RATE_CTA_DISPLAYED, {})) } function* watchRequestReview() { diff --git a/packages/mobile/src/store/sign-out/sagas.ts b/packages/mobile/src/store/sign-out/sagas.ts index 8f44d096183..7278dfedb3a 100644 --- a/packages/mobile/src/store/sign-out/sagas.ts +++ b/packages/mobile/src/store/sign-out/sagas.ts @@ -1,4 +1,3 @@ -import { Name } from '@audius/common/models' import { accountActions, tokenDashboardPageActions, @@ -10,7 +9,6 @@ import { waitForValue } from '@audius/common/utils' import { setupBackend } from '@audius/web/src/common/store/backend/actions' import { getIsSettingUp } from '@audius/web/src/common/store/backend/selectors' import { resetSignOn } from '@audius/web/src/common/store/pages/signon/actions' -import { make } from 'common/store/analytics/actions' import { takeLatest, put, call } from 'typed-redux-saga' import { @@ -31,7 +29,6 @@ const { signOut: signOutAction } = signOutActions const storageKeysToRemove = [THEME_STORAGE_KEY, ENTROPY_KEY, SEARCH_HISTORY_KEY] function* signOut() { - yield* put(make(Name.SETTINGS_LOG_OUT, {})) const authService = yield* getContext('authService') const queryClient = yield* getContext('queryClient') diff --git a/packages/mobile/src/store/wallet-connect/sagas/connectNewWalletSaga.ts b/packages/mobile/src/store/wallet-connect/sagas/connectNewWalletSaga.ts index 79a9f22ed9b..99ab72108cc 100644 --- a/packages/mobile/src/store/wallet-connect/sagas/connectNewWalletSaga.ts +++ b/packages/mobile/src/store/wallet-connect/sagas/connectNewWalletSaga.ts @@ -1,8 +1,6 @@ import { queryCurrentUserId } from '@audius/common/api' -import { Name, Chain } from '@audius/common/models' -import { tokenDashboardPageActions, getContext } from '@audius/common/store' -import { getErrorMessage } from '@audius/common/utils' -import type { Nullable } from '@audius/common/utils' +import { Chain } from '@audius/common/models' +import { tokenDashboardPageActions } from '@audius/common/store' import bs58 from 'bs58' import { checkIsNewWallet } from 'common/store/pages/token-dashboard/checkIsNewWallet' import { getWalletInfo } from 'common/store/pages/token-dashboard/getWalletInfo' @@ -11,8 +9,6 @@ import nacl from 'tweetnacl' import { takeEvery, select, put, call } from 'typed-redux-saga' import { getAddress } from 'viem' -import type { JsonMap } from 'app/types/analytics' - import { getDappKeyPair } from '../selectors' import { connect, @@ -34,11 +30,6 @@ function* connectNewWalletAsync(action: ConnectNewWalletAction) { yield* put(baseConnectNewWallet()) - let eventProperties: Nullable = null - - const analytics = yield* getContext('analytics') - analytics.track({ eventName: Name.CONNECT_WALLET_NEW_WALLET_START }) - switch (action.payload.connectionType) { case null: console.error('No connection type set') @@ -73,11 +64,6 @@ function* connectNewWalletAsync(action: ConnectNewWalletAction) { }) ) - eventProperties = { - chain: Chain.Sol, - walletAddress: public_key - } - const message = `AudiusUserID:${accountUserId}` const payload = { @@ -118,11 +104,6 @@ function* connectNewWalletAsync(action: ConnectNewWalletAction) { }) ) - eventProperties = { - chain: Chain.Sol, - walletAddress: publicKeyEncoded - } - break } case 'wallet-connect': { @@ -142,23 +123,11 @@ function* connectNewWalletAsync(action: ConnectNewWalletAction) { }) ) - eventProperties = { - chain: Chain.Eth, - walletAddress: wallet - } - yield* put(setConnectionStatus({ status: 'connected' })) break } } - - if (eventProperties) { - analytics.track({ - eventName: Name.CONNECT_WALLET_NEW_WALLET_CONNECTING, - properties: eventProperties - }) - } } // Connect a wallet to establish a session, but don't connect @@ -201,20 +170,9 @@ export function* watchConnectNewWallet() { yield* takeEvery( connectNewWallet.type, function* (action: ConnectNewWalletAction) { - const analytics = yield* getContext('analytics') try { yield* call(connectNewWalletAsync, action) - } catch (e) { - const error = `Caught error in connectNewWallet saga: ${getErrorMessage( - e - )}` - analytics.track({ - eventName: Name.CONNECT_WALLET_ERROR, - properties: { - error - } - }) - } + } catch {} } ) } diff --git a/packages/mobile/src/store/wallet-connect/sagas/signMessageSaga.ts b/packages/mobile/src/store/wallet-connect/sagas/signMessageSaga.ts index 2225b8ce158..4b64c69daba 100644 --- a/packages/mobile/src/store/wallet-connect/sagas/signMessageSaga.ts +++ b/packages/mobile/src/store/wallet-connect/sagas/signMessageSaga.ts @@ -1,7 +1,6 @@ -import { Name } from '@audius/common/models' import type { CommonState } from '@audius/common/store' -import { tokenDashboardPageSelectors, getContext } from '@audius/common/store' -import { getErrorMessage, waitForValue } from '@audius/common/utils' +import { tokenDashboardPageSelectors } from '@audius/common/store' +import { waitForValue } from '@audius/common/utils' import bs58 from 'bs58' import { addWalletToUser } from 'common/store/pages/token-dashboard/addWalletToUser' import { takeEvery, select, put, call } from 'typed-redux-saga' @@ -91,30 +90,12 @@ function* signMessageAsync(action: SignMessageAction) { yield* put(setConnectionStatus({ status: 'done' })) yield* put(setVisibility({ drawer: 'ConnectNewWallet', visible: false })) - - const analytics = yield* getContext('analytics') - analytics.track({ - eventName: Name.CONNECT_WALLET_NEW_WALLET_CONNECTED, - properties: { - chain, - walletAddress: wallet - } - }) } export function* watchSignMessage() { yield* takeEvery(signMessage.type, function* (action: SignMessageAction) { - const analytics = yield* getContext('analytics') try { yield* call(signMessageAsync, action) - } catch (e) { - const error = `Caught error in signMessageSaga: ${getErrorMessage(e)}` - analytics.track({ - eventName: Name.CONNECT_WALLET_ERROR, - properties: { - error - } - }) - } + } catch {} }) } diff --git a/packages/mobile/src/types/analytics.ts b/packages/mobile/src/types/analytics.ts index 355dda840ac..64635d41666 100644 --- a/packages/mobile/src/types/analytics.ts +++ b/packages/mobile/src/types/analytics.ts @@ -5,10 +5,7 @@ import type { } from '@audius/common/models' import { Name as CommonEventNames } from '@audius/common/models' -import type { OfflineJob } from 'app/store/offline-downloads/slice' - enum MobileEventNames { - APP_ERROR = 'App Unexpected Error', SHARE_TO_IG_STORY = 'Share to Instagram story - start', SHARE_TO_IG_STORY_CANCELLED = 'Share to Instagram story - cancelled', SHARE_TO_IG_STORY_ERROR = 'Share to Instagram story - error', @@ -23,23 +20,27 @@ enum MobileEventNames { SHARE_TO_TIKTOK_VIDEO_SUCCESS = 'Share to TikTok (video) - success', // Offline Mode - OFFLINE_MODE_DOWNLOAD_ALL_TOGGLE_ON = 'Offline Mode: Download All Toggle On', - OFFLINE_MODE_DOWNLOAD_ALL_TOGGLE_OFF = 'Offline Mode: Download All Toggle Off', - OFFLINE_MODE_DOWNLOAD_COLLECTION_TOGGLE_ON = 'Offline Mode: Download Collection Toggle On', - OFFLINE_MODE_DOWNLOAD_COLLECTION_TOGGLE_OFF = 'Offline Mode: Download Collection Toggle Off', - OFFLINE_MODE_DOWNLOAD_REQUEST = 'Offline Mode: Download Item Request', - OFFLINE_MODE_DOWNLOAD_START = 'Offline Mode: Download Item Start', - OFFLINE_MODE_DOWNLOAD_SUCCESS = 'Offline Mode: Download Item Success', - OFFLINE_MODE_DOWNLOAD_FAILURE = 'Offline Mode: Download Item Failure', - OFFLINE_MODE_REMOVE_ITEM = 'Offline Mode: Remove Item', - OFFLINE_MODE_PLAY = 'Offline Mode: Offline Play', - OFFLINE_MODE_FILEPATH_MIGRATION_STARTED = 'Offline Mode: File path migration started', - OFFLINE_MODE_FILEPATH_MIGRATION_SUCCESS = 'Offline Mode: File path migration succeeded', - OFFLINE_MODE_FILEPATH_MIGRATION_FAILURE = 'Offline Mode: File path migration failed' + OFFLINE_MODE_PLAY = 'Offline Mode: Offline Play' } export const EventNames = { ...CommonEventNames, ...MobileEventNames } +/** Mobile-only events that are never sampled (share channels) */ +export const MOBILE_CORE_EVENTS: readonly string[] = [ + MobileEventNames.SHARE_TO_IG_STORY, + MobileEventNames.SHARE_TO_IG_STORY_CANCELLED, + MobileEventNames.SHARE_TO_IG_STORY_ERROR, + MobileEventNames.SHARE_TO_IG_STORY_SUCCESS, + MobileEventNames.SHARE_TO_SNAPCHAT, + MobileEventNames.SHARE_TO_SNAPCHAT_CANCELLED, + MobileEventNames.SHARE_TO_SNAPCHAT_ERROR, + MobileEventNames.SHARE_TO_SNAPCHAT_STORY_SUCCESS, + MobileEventNames.SHARE_TO_TIKTOK_VIDEO, + MobileEventNames.SHARE_TO_TIKTOK_VIDEO_CANCELLED, + MobileEventNames.SHARE_TO_TIKTOK_VIDEO_ERROR, + MobileEventNames.SHARE_TO_TIKTOK_VIDEO_SUCCESS +] + type NotificationsOpenPushNotification = { eventName: Name.NOTIFICATIONS_OPEN_PUSH_NOTIFICATION title?: string @@ -96,86 +97,20 @@ type ShareToTikTokVideoError = { error: string } -type AppError = { - eventName: MobileEventNames.APP_ERROR - message?: string -} - -type OfflineModeDownloadAllToggleOn = { - eventName: MobileEventNames.OFFLINE_MODE_DOWNLOAD_ALL_TOGGLE_ON -} - -type OfflineModeDownloadAllToggleOff = { - eventName: MobileEventNames.OFFLINE_MODE_DOWNLOAD_ALL_TOGGLE_OFF -} - -type OfflineModeDownloadCollectionToggleOn = { - eventName: MobileEventNames.OFFLINE_MODE_DOWNLOAD_COLLECTION_TOGGLE_ON - collectionId: ID -} - -type OfflineModeDownloadCollectionToggleOff = { - eventName: MobileEventNames.OFFLINE_MODE_DOWNLOAD_COLLECTION_TOGGLE_OFF - collectionId: ID -} - -type OfflineModeDownloadRequest = OfflineJob & { - eventName: MobileEventNames.OFFLINE_MODE_DOWNLOAD_REQUEST -} - -type OfflineModeDownloadStart = OfflineJob & { - eventName: MobileEventNames.OFFLINE_MODE_DOWNLOAD_START -} - -type OfflineModeDownloadSuccess = OfflineJob & { - eventName: MobileEventNames.OFFLINE_MODE_DOWNLOAD_SUCCESS -} - -type OfflineModeDownloadFailure = OfflineJob & { - eventName: MobileEventNames.OFFLINE_MODE_DOWNLOAD_FAILURE -} - -type OfflineModeRemoveItem = OfflineJob & { - eventName: MobileEventNames.OFFLINE_MODE_REMOVE_ITEM -} - type OfflineModePlay = { eventName: MobileEventNames.OFFLINE_MODE_PLAY trackId: ID } -type OfflineFilePathMigrationStarted = { - eventName: MobileEventNames.OFFLINE_MODE_FILEPATH_MIGRATION_STARTED -} -type OfflineFilePathMigrationSucceess = { - eventName: MobileEventNames.OFFLINE_MODE_FILEPATH_MIGRATION_SUCCESS -} -type OfflineFilePathMigrationFailed = { - eventName: MobileEventNames.OFFLINE_MODE_FILEPATH_MIGRATION_FAILURE -} - type MobileTrackingEvents = | NotificationsOpenPushNotification - | AppError | ShareToIGStory | ShareToIGStoryError | ShareToSnapchat | ShareToSnapchatError | ShareToTikTokVideo | ShareToTikTokVideoError - | OfflineModeDownloadAllToggleOn - | OfflineModeDownloadAllToggleOff - | OfflineModeDownloadCollectionToggleOn - | OfflineModeDownloadCollectionToggleOff - | OfflineModeDownloadFailure - | OfflineModeDownloadRequest - | OfflineModeDownloadStart - | OfflineModeDownloadSuccess - | OfflineModeRemoveItem | OfflineModePlay - | OfflineFilePathMigrationStarted - | OfflineFilePathMigrationSucceess - | OfflineFilePathMigrationFailed export type AllEvents = CommonTrackingEvents | MobileTrackingEvents diff --git a/packages/web/src/common/store/cache/collections/addTrackToPlaylistSaga.ts b/packages/web/src/common/store/cache/collections/addTrackToPlaylistSaga.ts index 51671be2b29..b19aba654dc 100644 --- a/packages/web/src/common/store/cache/collections/addTrackToPlaylistSaga.ts +++ b/packages/web/src/common/store/cache/collections/addTrackToPlaylistSaga.ts @@ -8,13 +8,7 @@ import { queryTracks, updateCollectionData } from '@audius/common/api' -import { - Name, - Kind, - Collection, - ID, - ChallengeName -} from '@audius/common/models' +import { Kind, Collection, ID, ChallengeName } from '@audius/common/models' import { cacheCollectionsActions, cacheActions, @@ -34,7 +28,6 @@ import { import { Id } from '@audius/sdk' import { call, put, takeEvery } from 'typed-redux-saga' -import { make } from 'common/store/analytics/actions' import { ensureLoggedIn } from 'common/utils/ensureLoggedIn' import { waitForWrite } from 'utils/sagaHelpers' @@ -158,13 +151,6 @@ function* addTrackToPlaylistAsync(action: AddTrackToPlaylistAction) { }) ) - const event = make(Name.PLAYLIST_ADD, { - trackId: action.trackId, - playlistId: action.playlistId - }) - - yield* put(event) - if (!action.silent) { yield* put( toast({ diff --git a/packages/web/src/common/store/cache/collections/commonSagas.ts b/packages/web/src/common/store/cache/collections/commonSagas.ts index 0c0b46eabb9..b0cf4fa4b2c 100644 --- a/packages/web/src/common/store/cache/collections/commonSagas.ts +++ b/packages/web/src/common/store/cache/collections/commonSagas.ts @@ -12,7 +12,6 @@ import { updateCollectionData } from '@audius/common/api' import { - Name, Kind, PlaylistContents, ID, @@ -50,7 +49,6 @@ import { takeLatest } from 'typed-redux-saga' -import { make } from 'common/store/analytics/actions' import watchTrackErrors from 'common/store/cache/collections/errorSagas' import * as signOnActions from 'common/store/pages/signon/actions' import { getUSDCMetadata } from 'common/store/upload/sagaHelpers' @@ -553,9 +551,6 @@ function* publishPlaylistAsync( return } - const event = make(Name.PLAYLIST_MAKE_PUBLIC, { id: action.playlistId }) - yield* put(event) - const playlist = yield* queryCollection(action.playlistId) if (!playlist) return const playlistWithPublishing = { ...playlist, _is_publishing: true } diff --git a/packages/web/src/common/store/cache/collections/createAlbumSaga.ts b/packages/web/src/common/store/cache/collections/createAlbumSaga.ts index 3d18c27c9b4..3d963211b3c 100644 --- a/packages/web/src/common/store/cache/collections/createAlbumSaga.ts +++ b/packages/web/src/common/store/cache/collections/createAlbumSaga.ts @@ -12,13 +12,7 @@ import { primeCollectionDataSaga, persistAccountPlaylistLibrarySaga } from '@audius/common/api' -import { - Name, - Kind, - CollectionMetadata, - ID, - Track -} from '@audius/common/models' +import { Kind, CollectionMetadata, ID, Track } from '@audius/common/models' import { newCollectionMetadata } from '@audius/common/schemas' import { cacheCollectionsActions, @@ -32,7 +26,6 @@ import { makeKindId, Nullable, route } from '@audius/common/utils' import { Id, OptionalId } from '@audius/sdk' import { call, put, takeLatest } from 'typed-redux-saga' -import { make } from 'common/store/analytics/actions' import { ensureLoggedIn } from 'common/utils/ensureLoggedIn' import { waitForWrite } from 'utils/sagaHelpers' @@ -156,14 +149,6 @@ function* createAndConfirmAlbum( ) { const sdk = yield* getSDK() - const event = make(Name.PLAYLIST_START_CREATE, { - source, - artworkSource: formFields.artwork - ? formFields.artwork.source - : formFields.cover_art_sizes - }) - yield* put(event) - function* confirmAlbum() { const userId = yield* call(queryCurrentUserId) if (!userId) { @@ -215,13 +200,6 @@ function* createAndConfirmAlbum( yield* call(updateCollectionData, [reformattedAlbum]) - yield* put( - make(Name.PLAYLIST_COMPLETE_CREATE, { - source, - status: 'success' - }) - ) - yield* put(cacheCollectionsActions.createPlaylistSucceeded()) return confirmedAlbum @@ -229,12 +207,6 @@ function* createAndConfirmAlbum( function* onError(result: RequestConfirmationError) { const { message, error, timeout } = result - yield* put( - make(Name.PLAYLIST_COMPLETE_CREATE, { - source, - status: 'failure' - }) - ) yield* put( cacheCollectionsActions.createPlaylistFailed( error, diff --git a/packages/web/src/common/store/cache/collections/createPlaylistSaga.ts b/packages/web/src/common/store/cache/collections/createPlaylistSaga.ts index 65807519bf8..4fa561a6420 100644 --- a/packages/web/src/common/store/cache/collections/createPlaylistSaga.ts +++ b/packages/web/src/common/store/cache/collections/createPlaylistSaga.ts @@ -12,13 +12,7 @@ import { queryUser, updateCollectionData } from '@audius/common/api' -import { - Name, - Kind, - CollectionMetadata, - ID, - Track -} from '@audius/common/models' +import { Kind, CollectionMetadata, ID, Track } from '@audius/common/models' import { newCollectionMetadata } from '@audius/common/schemas' import { accountActions, @@ -34,7 +28,6 @@ import { makeKindId, Nullable, route } from '@audius/common/utils' import { Id, OptionalId } from '@audius/sdk' import { call, put, takeLatest } from 'typed-redux-saga' -import { make } from 'common/store/analytics/actions' import { ensureLoggedIn } from 'common/utils/ensureLoggedIn' import { waitForWrite } from 'utils/sagaHelpers' @@ -179,14 +172,6 @@ function* createAndConfirmPlaylist( ) { const sdk = yield* getSDK() - const event = make(Name.PLAYLIST_START_CREATE, { - source, - artworkSource: formFields.artwork - ? formFields.artwork.source - : formFields.cover_art_sizes - }) - yield* put(event) - function* confirmPlaylist() { const userId = yield* call(queryCurrentUserId) if (!userId) { @@ -240,13 +225,6 @@ function* createAndConfirmPlaylist( yield* call(updateCollectionData, [reformattedPlaylist]) - yield* put( - make(Name.PLAYLIST_COMPLETE_CREATE, { - source, - status: 'success' - }) - ) - yield* put(cacheCollectionsActions.createPlaylistSucceeded()) return confirmedPlaylist @@ -254,12 +232,6 @@ function* createAndConfirmPlaylist( function* onError(result: RequestConfirmationError) { const { message, error, timeout } = result - yield* put( - make(Name.PLAYLIST_COMPLETE_CREATE, { - source, - status: 'failure' - }) - ) yield* put( cacheCollectionsActions.createPlaylistFailed( error, diff --git a/packages/web/src/common/store/pages/audio-rewards/sagas.ts b/packages/web/src/common/store/pages/audio-rewards/sagas.ts index 2decdf7bcee..655ea981b11 100644 --- a/packages/web/src/common/store/pages/audio-rewards/sagas.ts +++ b/packages/web/src/common/store/pages/audio-rewards/sagas.ts @@ -25,7 +25,6 @@ import { modalsActions, getContext, musicConfettiActions, - CommonStoreContext, getSDK } from '@audius/common/store' import { waitForValue, isPlayCountChallenge } from '@audius/common/utils' @@ -213,48 +212,27 @@ async function claimRewardsForChallenge({ sdk, userId, challengeId, - specifiers, - track, - make + specifiers }: { sdk: AudiusSdk userId: string challengeId: ChallengeId specifiers: SpecifierWithAmount[] - track: CommonStoreContext['analytics']['track'] - make: CommonStoreContext['analytics']['make'] }): Promise<(SpecifierWithAmount | ErrorResult)[]> { return await Promise.all( specifiers.map(async (specifierWithAmount) => - track( - make({ - eventName: Name.REWARDS_CLAIM_REQUEST, - challengeId, - specifier: specifierWithAmount.specifier, - amount: specifierWithAmount.amount + sdk.rewards + .claimRewards({ + reward: { + challengeId, + specifier: specifierWithAmount.specifier, + userId + } }) - ) - .then(() => - sdk.rewards.claimRewards({ - reward: { - challengeId, - specifier: specifierWithAmount.specifier, - userId - } - }) - ) .then((res) => { if (res?.data?.[0]?.error) { throw new Error(res.data[0].error) } - track( - make({ - eventName: Name.REWARDS_CLAIM_SUCCESS, - challengeId, - specifier: specifierWithAmount.specifier, - amount: specifierWithAmount.amount - }) - ) return res }) .then(() => { @@ -277,7 +255,6 @@ function* claimSingleChallengeRewardAsync( const env = yield* getContext('env') const audiusSdk = yield* getContext('audiusSdk') const sdk = yield* call(audiusSdk) - const { track, make } = yield* getContext('analytics') const { claim } = action.payload const { specifiers, challengeId } = claim @@ -302,9 +279,7 @@ function* claimSingleChallengeRewardAsync( sdk, userId: Id.parse(userId), challengeId: challengeId as ChallengeId, - specifiers, - track, - make + specifiers }) const claimed = results.filter((r) => !('error' in r)) @@ -365,10 +340,6 @@ function* claimAllChallengeRewardsAsync( ) if (hasError) { yield* put(claimChallengeRewardFailed()) - yield* call( - track, - make({ eventName: Name.REWARDS_CLAIM_ALL_FAILURE, count: claims.length }) - ) } else { yield* put(claimAllChallengeRewardsSucceeded()) yield* call( diff --git a/packages/web/src/common/store/pages/deactivate-account/sagas.ts b/packages/web/src/common/store/pages/deactivate-account/sagas.ts index ee69facc4bc..b534fc0546b 100644 --- a/packages/web/src/common/store/pages/deactivate-account/sagas.ts +++ b/packages/web/src/common/store/pages/deactivate-account/sagas.ts @@ -1,5 +1,4 @@ import { queryAccountUser, queryCurrentUserId } from '@audius/common/api' -import { Name } from '@audius/common/models' import { deactivateAccountActions, signOutActions, @@ -11,7 +10,6 @@ import { import { waitForValue } from '@audius/common/utils' import { call, delay, put, takeEvery } from 'typed-redux-saga' -import { make } from 'common/store/analytics/actions' import { waitForWrite } from 'utils/sagaHelpers' const { afterDeactivationSignOut, deactivateAccount, deactivateAccountFailed } = @@ -35,7 +33,6 @@ function* handleDeactivateAccount() { requestConfirmation( DEACTIVATE_CONFIRMATION_UID, function* () { - yield* put(make(Name.DEACTIVATE_ACCOUNT_REQUEST, {})) yield* call(audiusBackendInstance.updateCreator, { metadata: { ...userMetadata, is_deactivated: true }, sdk @@ -43,19 +40,16 @@ function* handleDeactivateAccount() { }, // @ts-ignore: confirmer is untyped function* () { - yield* put(make(Name.DEACTIVATE_ACCOUNT_SUCCESS, {})) // Do the signout in another action so confirmer can clear yield* put(afterDeactivationSignOut()) }, function* () { - yield* put(make(Name.DEACTIVATE_ACCOUNT_FAILURE, {})) yield* put(deactivateAccountFailed()) } ) ) } catch (e) { console.error(e) - yield* put(make(Name.DEACTIVATE_ACCOUNT_FAILURE, {})) yield* put(deactivateAccountFailed()) } } diff --git a/packages/web/src/common/store/pages/signon/sagas.ts b/packages/web/src/common/store/pages/signon/sagas.ts index 703363e5a34..6efa9d72932 100644 --- a/packages/web/src/common/store/pages/signon/sagas.ts +++ b/packages/web/src/common/store/pages/signon/sagas.ts @@ -509,18 +509,7 @@ function* signUp() { oldUsername: email, oldPassword: TEMPORARY_PASSWORD }) - yield* put( - make(Name.SETTINGS_COMPLETE_CHANGE_PASSWORD, { - status: 'success' - }) - ) - } catch { - yield* put( - make(Name.SETTINGS_COMPLETE_CHANGE_PASSWORD, { - status: 'failure' - }) - ) - } + } catch {} } yield* fork(sendPostSignInRecoveryEmail, { handle, email }) diff --git a/packages/web/src/common/store/pages/token-dashboard/checkIsNewWallet.ts b/packages/web/src/common/store/pages/token-dashboard/checkIsNewWallet.ts index f8dccef8801..7d633d4c945 100644 --- a/packages/web/src/common/store/pages/token-dashboard/checkIsNewWallet.ts +++ b/packages/web/src/common/store/pages/token-dashboard/checkIsNewWallet.ts @@ -1,8 +1,7 @@ -import { Name, Chain } from '@audius/common/models' +import { Chain } from '@audius/common/models' import { tokenDashboardPageSelectors, tokenDashboardPageActions, - getContext, getSDK } from '@audius/common/store' import { HashId } from '@audius/sdk' @@ -37,15 +36,6 @@ export function* checkIsNewWallet(walletAddress: string, chain: Chain) { }) ) - const analytics = yield* getContext('analytics') - analytics.track({ - eventName: Name.CONNECT_WALLET_ALREADY_ASSOCIATED, - properties: { - chain, - walletAddress - } - }) - return false } return true diff --git a/packages/web/src/common/store/social/tracks/sagas.ts b/packages/web/src/common/store/social/tracks/sagas.ts index bb3a3545268..dcca9e44c8f 100644 --- a/packages/web/src/common/store/social/tracks/sagas.ts +++ b/packages/web/src/common/store/social/tracks/sagas.ts @@ -125,42 +125,6 @@ export function* repostTrackAsync( yield* call(updateTrackData, [ { track_id: action.trackId, ...eagerlyUpdatedMetadata } ]) - - if (remixTrack && isCoSign) { - const { - parent_track_id, - has_remix_author_reposted, - has_remix_author_saved - } = remixTrack - - // Track Cosign Event - const hasAlreadyCoSigned = - has_remix_author_reposted || has_remix_author_saved - - const parentTrack = yield* queryTrack(parent_track_id) - - if (parentTrack) { - const coSignIndicatorEvent = make(Name.REMIX_COSIGN_INDICATOR, { - id: action.trackId, - handle: user.handle, - original_track_id: parentTrack.track_id, - original_track_title: parentTrack.title, - action: 'reposted' - }) - yield* put(coSignIndicatorEvent) - - if (!hasAlreadyCoSigned) { - const coSignEvent = make(Name.REMIX_COSIGN, { - id: action.trackId, - handle: user.handle, - original_track_id: parentTrack.track_id, - original_track_title: parentTrack.title, - action: 'reposted' - }) - yield* put(coSignEvent) - } - } - } } export function* confirmRepostTrack( @@ -392,35 +356,6 @@ export function* saveTrackAsync( { track_id: action.trackId, ...eagerlyUpdatedMetadata } ]) yield* put(socialActions.saveTrackSucceeded(action.trackId)) - if (isCoSign) { - // Track Cosign Event - const parentTrackId = remixTrack.parent_track_id - const hasAlreadyCoSigned = - remixTrack.has_remix_author_reposted || remixTrack.has_remix_author_saved - - const parentTrack = yield* queryTrack(parentTrackId) - const accountUser = yield* call(queryAccountUser) - const handle = accountUser?.handle - const coSignIndicatorEvent = make(Name.REMIX_COSIGN_INDICATOR, { - id: action.trackId, - handle, - original_track_id: parentTrack?.track_id, - original_track_title: parentTrack?.title, - action: 'favorited' - }) - yield* put(coSignIndicatorEvent) - - if (!hasAlreadyCoSigned) { - const coSignEvent = make(Name.REMIX_COSIGN, { - id: action.trackId, - handle, - original_track_id: parentTrack?.track_id, - original_track_title: parentTrack?.title, - action: 'favorited' - }) - yield* put(coSignEvent) - } - } } export function* confirmSaveTrack( @@ -574,9 +509,6 @@ export function* watchSetArtistPick() { ) const user = yield* call(queryUser, userId) yield* fork(updateProfileAsync, { metadata: user }) - - const event = make(Name.ARTIST_PICK_SELECT_TRACK, { id: action.trackId }) - yield* put(event) } ) } @@ -599,9 +531,6 @@ export function* watchUnsetArtistPick() { ) const user = yield* call(queryUser, userId) yield* fork(updateProfileAsync, { metadata: user }) - - const event = make(Name.ARTIST_PICK_SELECT_TRACK, { id: 'none' }) - yield* put(event) }) } diff --git a/packages/web/src/common/store/upload/sagaHelpers.ts b/packages/web/src/common/store/upload/sagaHelpers.ts index e946ba4ecc4..35e5c56ac62 100644 --- a/packages/web/src/common/store/upload/sagaHelpers.ts +++ b/packages/web/src/common/store/upload/sagaHelpers.ts @@ -1,8 +1,6 @@ import { queryAccountUser } from '@audius/common/api' import { Name, - isContentFollowGated, - isContentTokenGated, isContentUSDCPurchaseGated, USDCPurchaseConditions } from '@audius/common/models' @@ -28,23 +26,7 @@ export function* recordGatedTracks( ? trackOrMetadata.metadata : trackOrMetadata if (isStreamGated && streamConditions) { - if (isContentFollowGated(streamConditions)) { - out.push( - make(Name.TRACK_UPLOAD_FOLLOW_GATED, { - kind: 'tracks', - downloadable: isDownloadable, - lossless: isOriginalAvailable - }) - ) - } else if (isContentTokenGated(streamConditions)) { - out.push( - make(Name.TRACK_UPLOAD_TOKEN_GATED, { - kind: 'tracks', - downloadable: isDownloadable, - lossless: isOriginalAvailable - }) - ) - } else if (isContentUSDCPurchaseGated(streamConditions)) { + if (isContentUSDCPurchaseGated(streamConditions)) { out.push( make(Name.TRACK_UPLOAD_USDC_GATED, { kind: 'tracks', @@ -55,23 +37,7 @@ export function* recordGatedTracks( ) } } else if (isDownloadGated && dowloadConditions) { - if (isContentFollowGated(dowloadConditions)) { - out.push( - make(Name.TRACK_UPLOAD_FOLLOW_GATED_DOWNLOAD, { - kind: 'tracks', - downloadable: isDownloadable, - lossless: isOriginalAvailable - }) - ) - } else if (isContentTokenGated(dowloadConditions)) { - out.push( - make(Name.TRACK_UPLOAD_TOKEN_GATED_DOWNLOAD, { - kind: 'tracks', - downloadable: isDownloadable, - lossless: isOriginalAvailable - }) - ) - } else if (isContentUSDCPurchaseGated(dowloadConditions)) { + if (isContentUSDCPurchaseGated(dowloadConditions)) { out.push( make(Name.TRACK_UPLOAD_USDC_GATED_DOWNLOAD, { kind: 'tracks', diff --git a/packages/web/src/components/app-cta-modal/AppCTAModal.tsx b/packages/web/src/components/app-cta-modal/AppCTAModal.tsx index 8eb03f0dcf8..a8ee3ef41a2 100644 --- a/packages/web/src/components/app-cta-modal/AppCTAModal.tsx +++ b/packages/web/src/components/app-cta-modal/AppCTAModal.tsx @@ -1,11 +1,9 @@ import { useCallback } from 'react' -import { Name } from '@audius/common/models' import { Modal, Button, IconCloudDownload } from '@audius/harmony' import { useDispatch } from 'react-redux' import QRCode from 'assets/img/imageQR.png' -import { make } from 'common/store/analytics/actions' import DownloadApp from 'services/download-app/DownloadApp' import { setVisibility } from 'store/application/ui/app-cta-modal/slice' import { getOS } from 'utils/clientUtil' @@ -36,10 +34,6 @@ const useCallbacks = () => { const isOpen = useSelector((state) => state.application.ui.appCTAModal.isOpen) - const recordDownloadDesktopApp = useCallback(() => { - dispatch(make(Name.ACCOUNT_HEALTH_DOWNLOAD_DESKTOP, { source: 'banner' })) - }, [dispatch]) - const onClose = useCallback( () => dispatch(setVisibility({ isOpen: false })), [dispatch] @@ -48,8 +42,7 @@ const useCallbacks = () => { const downloadDesktopApp = useCallback(() => { if (!os) return DownloadApp.start(os) - recordDownloadDesktopApp() - }, [recordDownloadDesktopApp]) + }, []) return { isOpen, downloadDesktopApp, onClose } } diff --git a/packages/web/src/components/artist-recommendations/ArtistRecommendations.tsx b/packages/web/src/components/artist-recommendations/ArtistRecommendations.tsx index a82a7841613..923fa3cad93 100644 --- a/packages/web/src/components/artist-recommendations/ArtistRecommendations.tsx +++ b/packages/web/src/components/artist-recommendations/ArtistRecommendations.tsx @@ -1,21 +1,13 @@ -import { - Fragment, - forwardRef, - ReactNode, - useCallback, - useEffect, - useState -} from 'react' +import { Fragment, forwardRef, ReactNode, useCallback, useState } from 'react' import { useRelatedArtistsUsers } from '@audius/common/api' -import { Name, FollowSource, SquareSizes, ID } from '@audius/common/models' +import { FollowSource, SquareSizes, ID } from '@audius/common/models' import { usersSocialActions as socialActions } from '@audius/common/store' import { route } from '@audius/common/utils' import { FollowButton, IconButton, IconClose, Image } from '@audius/harmony' import cn from 'classnames' import { useDispatch } from 'react-redux' -import { make, useRecord } from 'common/store/analytics/actions' import { ArtistPopover } from 'components/artist/ArtistPopover' import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' import UserBadges from 'components/user-badges/UserBadges' @@ -197,15 +189,6 @@ export const ArtistRecommendations = forwardRef< ) } - const record = useRecord() - useEffect(() => { - record( - make(Name.PROFILE_PAGE_SHOWN_ARTIST_RECOMMENDATIONS, { - userId: artistId - }) - ) - }, [record, artistId]) - return (
diff --git a/packages/web/src/components/banner/FanClubsLaunchBanner.tsx b/packages/web/src/components/banner/FanClubsLaunchBanner.tsx index 356d3bb04b5..6a31a4f0ce6 100644 --- a/packages/web/src/components/banner/FanClubsLaunchBanner.tsx +++ b/packages/web/src/components/banner/FanClubsLaunchBanner.tsx @@ -1,11 +1,8 @@ import { useCallback, useState } from 'react' -import { Name } from '@audius/common/models' import { route } from '@audius/common/utils' -import { useDispatch } from 'react-redux' import { useLocalStorage } from 'react-use' -import { make } from 'common/store/analytics/actions' import { useNavigateToPage } from 'hooks/useNavigateToPage' import { CallToActionBanner } from './CallToActionBanner' @@ -18,7 +15,6 @@ const messages = { } export const FanClubsLaunchBanner = () => { - const dispatch = useDispatch() const navigate = useNavigateToPage() const [isDismissed, setIsDismissed] = useLocalStorage( FAN_CLUB_BANNER_LOCAL_STORAGE_KEY, @@ -32,10 +28,9 @@ export const FanClubsLaunchBanner = () => { }, [setIsDismissed]) const handleAccept = useCallback(() => { - dispatch(make(Name.BANNER_FAN_CLUBS_LAUNCH_CLICKED, {})) navigate(route.CLUBS_EXPLORE_PAGE) handleClose() - }, [dispatch, handleClose, navigate]) + }, [handleClose, navigate]) return isVisible ? ( { - const dispatch = useDispatch() const hasDismissed = window.localStorage.getItem(TOS_BANNER_LOCAL_STORAGE_KEY) const [isVisible, setIsVisible] = useState(!hasDismissed) @@ -31,9 +26,8 @@ export const TermsOfServiceUpdateBanner = () => { const handleAccept = useCallback(() => { window.open(TERMS_OF_SERVICE) - dispatch(make(Name.BANNER_TOS_CLICKED, {})) handleClose() - }, [dispatch, handleClose]) + }, [handleClose]) return isVisible ? ( { - const dispatch = useDispatch() const [isDismissed, setIsDismissed] = useLocalStorage( TRADING_VOLUME_BANNER_LOCAL_STORAGE_KEY, false @@ -30,10 +25,9 @@ export const TradingVolumeLaunchBanner = () => { }, [setIsDismissed]) const handleAccept = useCallback(() => { - dispatch(make(Name.BANNER_TRADING_VOLUME_LAUNCH_CLICKED, {})) window.open('https://season1.audius.co', '_blank') handleClose() - }, [dispatch, handleClose]) + }, [handleClose]) return isVisible ? ( { - const dispatch = useDispatch() const navigate = useNavigateToPage() const [isDismissed, setIsDismissed] = useLocalStorage( YAK_COIN_LAUNCH_BANNER_LOCAL_STORAGE_KEY, @@ -33,10 +29,9 @@ export const YakCoinLaunchBanner = () => { }, [setIsDismissed]) const handleAccept = useCallback(() => { - dispatch(make(Name.BANNER_YAK_COIN_LAUNCH_CLICKED, {})) navigate(coinPage('YAK')) handleClose() - }, [dispatch, handleClose, navigate]) + }, [handleClose, navigate]) return isVisible ? ( { onSave={handleSaveDescription} /> ) : description ? ( - + {description} ) : null} diff --git a/packages/web/src/components/collection/desktop/EditableCollectionDescription.tsx b/packages/web/src/components/collection/desktop/EditableCollectionDescription.tsx index 72d82f6e1e6..82544cdaee3 100644 --- a/packages/web/src/components/collection/desktop/EditableCollectionDescription.tsx +++ b/packages/web/src/components/collection/desktop/EditableCollectionDescription.tsx @@ -85,11 +85,7 @@ export const EditableCollectionDescription = ({ > {value ? ( - + {value} ) : ( diff --git a/packages/web/src/components/collection/desktop/edit-mode/PlaylistEditModeContext.tsx b/packages/web/src/components/collection/desktop/edit-mode/PlaylistEditModeContext.tsx index a9c42f2511b..4289feea9ef 100644 --- a/packages/web/src/components/collection/desktop/edit-mode/PlaylistEditModeContext.tsx +++ b/packages/web/src/components/collection/desktop/edit-mode/PlaylistEditModeContext.tsx @@ -10,7 +10,7 @@ import { } from 'react' import { useCollection, useCollectionTracks } from '@audius/common/api' -import { AccessConditions, ID, Name } from '@audius/common/models' +import { AccessConditions, ID } from '@audius/common/models' import { cacheCollectionsActions, EditCollectionValues, @@ -21,8 +21,6 @@ import { isEqual } from 'lodash' import { useDispatch } from 'react-redux' import { useNavigate } from 'react-router' -import { track } from 'services/analytics' - import { isDraftCollection, removeDraftCollection } from './draftCollections' import { useCreateDraftPlaylist } from './useCreateDraftPlaylist' @@ -405,18 +403,6 @@ export const PlaylistEditModeProvider = ({ collection as Record, 'stream_conditions' ) - if (accessChanged) { - // Mirror the dedicated edit page: access changes get their own event. - track({ - eventName: Name.COLLECTION_EDIT_ACCESS_CHANGED, - properties: { - id: collection.playlist_id, - from: collection.stream_conditions, - to: draft.stream_conditions - } - }) - } - const savedDetails = draft.playlist_name !== undefined || draft.description !== undefined || diff --git a/packages/web/src/components/collection/mobile/CollectionHeader.tsx b/packages/web/src/components/collection/mobile/CollectionHeader.tsx index a7ef82a45a6..d85b054d7f9 100644 --- a/packages/web/src/components/collection/mobile/CollectionHeader.tsx +++ b/packages/web/src/components/collection/mobile/CollectionHeader.tsx @@ -299,10 +299,7 @@ const CollectionHeader = ({ /> ) : null} {description ? ( - + {description} ) : null} diff --git a/packages/web/src/components/comments/CommentActionBar.tsx b/packages/web/src/components/comments/CommentActionBar.tsx index eac3b9de9a8..b7bd1aa19f2 100644 --- a/packages/web/src/components/comments/CommentActionBar.tsx +++ b/packages/web/src/components/comments/CommentActionBar.tsx @@ -10,7 +10,7 @@ import { useMuteUser } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { Comment, ID, Name, ReplyComment } from '@audius/common/models' +import { Comment, ID, ReplyComment } from '@audius/common/models' import { Box, ButtonVariant, @@ -29,7 +29,6 @@ import { Id } from '@audius/sdk' import { ConfirmationModal } from 'components/confirmation-modal' import { ToastContext } from 'components/toast/ToastContext' import { useRequiresAccountCallback } from 'hooks/useRequiresAccount' -import { make, track as trackEvent } from 'services/analytics' import { env } from 'services/env' import { copyToClipboard } from 'utils/clipboardUtil' import { removeNullable } from 'utils/typeUtils' @@ -104,20 +103,9 @@ export const CommentActionBar = ({ useUpdateCommentNotificationSetting(commentId) // Handlers - const handleReact = useRequiresAccountCallback( - () => { - reactToComment(commentId, !isCurrentUserReacted) - }, - [commentId, isCurrentUserReacted, reactToComment], - () => { - trackEvent( - make({ - eventName: Name.COMMENTS_OPEN_AUTH_MODAL, - trackId: entityId - }) - ) - } - ) + const handleReact = useRequiresAccountCallback(() => { + reactToComment(commentId, !isCurrentUserReacted) + }, [commentId, isCurrentUserReacted, reactToComment]) const handleDelete = useCallback(() => { // note: we do some UI logic in the CommentBlock above this so we can't trigger directly from here @@ -157,13 +145,7 @@ export const CommentActionBar = ({ const [handleClickReply, mobileAppDrawer] = useCommentActionCallback(() => { onClickReply() - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_REPLY_BUTTON, - commentId - }) - ) - }, [onClickReply, commentId]) + }, [onClickReply]) const handleShare = useCallback(() => { const url = `${env.AUDIUS_URL}${track.permalink}?commentId=${Id.parse(comment.id)}` @@ -311,19 +293,9 @@ export const CommentActionBar = ({ ) const [handleClickOverflowMenu, replyMobileAppDrawer] = - useCommentActionCallback( - (triggerPopup: () => void) => { - triggerPopup() - - trackEvent( - make({ - eventName: Name.COMMENTS_OPEN_COMMENT_OVERFLOW_MENU, - commentId - }) - ) - }, - [commentId] - ) + useCommentActionCallback((triggerPopup: () => void) => { + triggerPopup() + }, []) return ( diff --git a/packages/web/src/components/comments/CommentForm.tsx b/packages/web/src/components/comments/CommentForm.tsx index 53860ed5bc3..46d07ffb911 100644 --- a/packages/web/src/components/comments/CommentForm.tsx +++ b/packages/web/src/components/comments/CommentForm.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from 'react' +import { useEffect, useState } from 'react' import { useCurrentCommentSection, @@ -6,7 +6,7 @@ import { usePostComment } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { ID, Name, SquareSizes } from '@audius/common/models' +import { ID, SquareSizes } from '@audius/common/models' import { playbackSelectors } from '@audius/common/src/store' import { Avatar, Flex } from '@audius/harmony' import { CommentMention } from '@audius/sdk' @@ -17,7 +17,6 @@ import { usePrevious } from 'react-use' import { ComposerInput } from 'components/composer-input/ComposerInput' import { useIsMobile } from 'hooks/useIsMobile' import { useProfilePicture } from 'hooks/useProfilePicture' -import { make, track } from 'services/analytics' import { audioPlayer } from 'services/audio-player' import { useCommentActionCallback } from './useCommentActionCallback' @@ -88,15 +87,8 @@ export const CommentForm = ({ } } - const [handleClickInput, mobileAppDrawer] = useCommentActionCallback(() => { - track( - make({ - eventName: Name.COMMENTS_FOCUS_COMMENT_INPUT, - trackId: entityId, - source: 'comment_input' - }) - ) - }, [entityId]) + const [handleClickInput, mobileAppDrawer] = + useCommentActionCallback(() => {}, []) const profileImage = useProfilePicture({ userId: currentUserId ?? undefined, @@ -118,37 +110,6 @@ export const CommentForm = ({ setMessageId((prev) => prev + 1) } - const handleAddMention = useCallback((userId: ID) => { - track( - make({ - eventName: Name.COMMENTS_ADD_MENTION, - userId - }) - ) - }, []) - - const handleAddTimestamp = useCallback((timestamp: number) => { - track( - make({ - eventName: Name.COMMENTS_ADD_TIMESTAMP, - timestamp - }) - ) - }, []) - - const handleAddLink = useCallback( - (entityId: ID, kind: 'track' | 'collection' | 'user') => { - track( - make({ - eventName: Name.COMMENTS_ADD_LINK, - entityId, - kind - }) - ) - }, - [] - ) - return ( <> @@ -175,9 +136,6 @@ export const CommentForm = ({ onSubmit={(value: string, _, mentions) => { handleSubmit({ commentMessage: value, mentions }) }} - onAddMention={handleAddMention} - onAddTimestamp={handleAddTimestamp} - onAddLink={handleAddLink} disabled={disabled} blurOnSubmit={true} /> diff --git a/packages/web/src/components/comments/CommentHeader.tsx b/packages/web/src/components/comments/CommentHeader.tsx index 93b2602b7f9..7a0aa623c30 100644 --- a/packages/web/src/components/comments/CommentHeader.tsx +++ b/packages/web/src/components/comments/CommentHeader.tsx @@ -1,4 +1,4 @@ -import { useCallback, useContext } from 'react' +import { useContext } from 'react' import { useCurrentCommentSection, @@ -6,7 +6,6 @@ import { useUpdateTrackCommentNotificationSetting } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { Name } from '@audius/common/models' import { Flex, IconButton, @@ -21,7 +20,6 @@ import { import { useTheme } from '@emotion/react' import { ToastContext } from 'components/toast/ToastContext' -import { track, make } from 'services/analytics' type CommentHeaderProps = { isLoading?: boolean @@ -62,19 +60,6 @@ export const CommentHeader = (props: CommentHeaderProps) => { } ] - const handleOpenTrackOverflowMenu = useCallback( - (triggerPopup: () => void) => { - triggerPopup() - track( - make({ - eventName: Name.COMMENTS_OPEN_TRACK_OVERFLOW_MENU, - trackId: entityId - }) - ) - }, - [entityId] - ) - return ( @@ -112,7 +97,7 @@ export const CommentHeader = (props: CommentHeaderProps) => { cursor: 'pointer', transition: motion.hover }} - onClick={() => handleOpenTrackOverflowMenu(triggerPopup)} + onClick={() => triggerPopup()} className='kebabIcon' /> )} diff --git a/packages/web/src/components/comments/CommentText.tsx b/packages/web/src/components/comments/CommentText.tsx index d7cc4d947e7..ad43cb1215b 100644 --- a/packages/web/src/components/comments/CommentText.tsx +++ b/packages/web/src/components/comments/CommentText.tsx @@ -1,7 +1,7 @@ -import { MouseEvent, useCallback, useEffect, useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { commentsMessages as messages } from '@audius/common/messages' -import { ID, Name } from '@audius/common/models' +import { ID } from '@audius/common/models' import { getDurationFromTimestampMatch, timestampRegex @@ -10,9 +10,7 @@ import { Flex, Text, TextLink } from '@audius/harmony' import { CommentMention } from '@audius/sdk' import { useToggle } from 'react-use' -import { LinkKind } from 'components/link' import { UserGeneratedTextV2 } from 'components/user-generated-text/UserGeneratedTextV2' -import { track as trackEvent, make } from 'services/analytics' import { TimestampLink } from './TimestampLink' @@ -26,7 +24,7 @@ type CommentTextProps = { } export const CommentText = (props: CommentTextProps) => { - const { children, isEdited, mentions, isPreview, commentId, duration } = props + const { children, isEdited, mentions, isPreview, duration } = props const textRef = useRef(undefined) const [isOverflowing, setIsOverflowing] = useState(false) const [isExpanded, toggleIsExpanded] = useToggle(false) @@ -39,43 +37,6 @@ export const CommentText = (props: CommentTextProps) => { ) }, [children]) - const handleClickLink = useCallback( - (e: MouseEvent, linkKind: LinkKind, linkEntityId?: ID) => { - if (linkKind === 'mention' && linkEntityId) { - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_MENTION, - userId: linkEntityId, - commentId - }) - ) - } else { - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_LINK, - commentId, - kind: linkKind as 'track' | 'collection' | 'user' | 'other', - entityId: linkEntityId - }) - ) - } - }, - [commentId] - ) - - const handleClickTimestamp = useCallback( - (e: MouseEvent, timestampSeconds: number) => { - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_TIMESTAMP, - commentId, - timestamp: timestampSeconds - }) - ) - }, - [commentId] - ) - return ( { suffix={ isEdited ? ({messages.edited}) : null } - linkProps={{ - onClick: handleClickLink - }} matchers={[ { pattern: timestampRegex, @@ -109,7 +67,6 @@ export const CommentText = (props: CommentTextProps) => { ) : null } diff --git a/packages/web/src/components/comments/CommentThread.tsx b/packages/web/src/components/comments/CommentThread.tsx index 5e35157a016..95a91a97bdf 100644 --- a/packages/web/src/components/comments/CommentThread.tsx +++ b/packages/web/src/components/comments/CommentThread.tsx @@ -1,9 +1,8 @@ import { useState } from 'react' import { useComment, useCommentReplies } from '@audius/common/api' -import { useCurrentCommentSection } from '@audius/common/context' import { commentsMessages as messages } from '@audius/common/messages' -import { Comment, ID, Name, ReplyComment } from '@audius/common/models' +import { Comment, ID, ReplyComment } from '@audius/common/models' import { Box, Flex, @@ -12,8 +11,6 @@ import { PlainButton } from '@audius/harmony' -import { track, make } from 'services/analytics' - import { CommentBlock } from './CommentBlock' import { useHighlightedComment } from './useHighlightedComment' @@ -26,7 +23,6 @@ export const CommentThread = ({ commentId }: { commentId: ID }) => { ? highlightedComment?.id : null - const { entityId } = useCurrentCommentSection() const [hasRequestedMore, setHasRequestedMore] = useState(false) const { isFetching: isFetchingReplies } = useCommentReplies( { commentId }, @@ -41,16 +37,6 @@ export const CommentThread = ({ commentId }: { commentId: ID }) => { const newHiddenReplies = { ...hiddenReplies } newHiddenReplies[commentId] = !newHiddenReplies[commentId] setHiddenReplies(newHiddenReplies) - - track( - make({ - eventName: newHiddenReplies[commentId] - ? Name.COMMENTS_HIDE_REPLIES - : Name.COMMENTS_SHOW_REPLIES, - commentId, - trackId: entityId - }) - ) } const handleLoadMoreReplies = () => { diff --git a/packages/web/src/components/download-track-archive-modal/DownloadTrackArchiveModal.tsx b/packages/web/src/components/download-track-archive-modal/DownloadTrackArchiveModal.tsx index 08bf3bdf299..594a58c6ecb 100644 --- a/packages/web/src/components/download-track-archive-modal/DownloadTrackArchiveModal.tsx +++ b/packages/web/src/components/download-track-archive-modal/DownloadTrackArchiveModal.tsx @@ -5,8 +5,7 @@ import { useDownloadTrackStems, useGetStemsArchiveJobStatus } from '@audius/common/api' -import { useAppContext } from '@audius/common/context' -import { ID, Name } from '@audius/common/models' +import { ID } from '@audius/common/models' import { registerNiceModalId } from '@audius/common/services' import { useDownloadTrackArchiveModal } from '@audius/common/store' import { @@ -59,9 +58,6 @@ const DownloadTrackArchiveModalContent = ({ onClose, onClosed }: DownloadTrackArchiveModalContentProps) => { - const { - analytics: { track, make } - } = useAppContext() const { mutate: downloadTrackStems, isError: initiateDownloadFailed, @@ -87,16 +83,6 @@ const DownloadTrackArchiveModalContent = ({ jobStatus?.state === 'failed' || (!!jobId && (isJobStatusError || isJobTimedOut))) - useEffect(() => { - if (hasError) { - track( - make({ - eventName: Name.TRACK_DOWNLOAD_FAILED_DOWNLOAD_ALL - }) - ) - } - }, [hasError, track, make]) - useEffect(() => { downloadTrackStems() }, [downloadTrackStems]) @@ -104,14 +90,9 @@ const DownloadTrackArchiveModalContent = ({ useEffect(() => { if (jobStatus?.state === 'completed') { triggerDownload(`${env.ARCHIVE_ENDPOINT}/archive/stems/download/${jobId}`) - track( - make({ - eventName: Name.TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_ALL - }) - ) onClose() } - }, [jobStatus, onClose, jobId, track, make]) + }, [jobStatus, onClose, jobId]) const handleClose = useCallback(() => { if (jobId) { diff --git a/packages/web/src/components/edit-folder-modal/EditFolderModal.tsx b/packages/web/src/components/edit-folder-modal/EditFolderModal.tsx index 92a47f46c81..fd653a6335a 100644 --- a/packages/web/src/components/edit-folder-modal/EditFolderModal.tsx +++ b/packages/web/src/components/edit-folder-modal/EditFolderModal.tsx @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react' import { useCurrentAccount, useUpdatePlaylistLibrary } from '@audius/common/api' -import { Name, PlaylistLibraryFolder } from '@audius/common/models' +import { PlaylistLibraryFolder } from '@audius/common/models' import { playlistLibraryHelpers } from '@audius/common/store' import { Modal, @@ -11,7 +11,6 @@ import { IconFolder } from '@audius/harmony' -import { make, useRecord } from 'common/store/analytics/actions' import FolderForm from 'components/create-playlist/FolderForm' import { DeleteFolderConfirmationModal } from 'components/nav/desktop/PlaylistLibrary/DeleteFolderConfirmationModal' import { zIndex } from 'utils/zIndex' @@ -33,7 +32,6 @@ type EditFolderModalProps = { export const EditFolderModal = (props: EditFolderModalProps) => { const { isOpen, onClose, folder } = props - const record = useRecord() const { data: playlistLibrary } = useCurrentAccount({ select: (account) => account?.playlistLibrary }) @@ -42,11 +40,6 @@ export const EditFolderModal = (props: EditFolderModalProps) => { const { mutate: updatePlaylistLibrary } = useUpdatePlaylistLibrary() - const handleCancel = useCallback(() => { - record(make(Name.FOLDER_CANCEL_EDIT, {})) - onClose() - }, [onClose, record]) - const handleSubmit = useCallback( (newName: string) => { if (playlistLibrary != null && newName !== folder.name) { @@ -57,10 +50,9 @@ export const EditFolderModal = (props: EditFolderModalProps) => { ) updatePlaylistLibrary(newLibrary) } - record(make(Name.FOLDER_SUBMIT_EDIT, {})) onClose() }, - [folder, onClose, playlistLibrary, record, updatePlaylistLibrary] + [folder, onClose, playlistLibrary, updatePlaylistLibrary] ) const handleConfirmDelete = useCallback(() => { @@ -91,7 +83,7 @@ export const EditFolderModal = (props: EditFolderModalProps) => { diff --git a/packages/web/src/components/edit-track/EditTrackForm.tsx b/packages/web/src/components/edit-track/EditTrackForm.tsx index fb594eb0f5d..6e6aa21eb1f 100644 --- a/packages/web/src/components/edit-track/EditTrackForm.tsx +++ b/packages/web/src/components/edit-track/EditTrackForm.tsx @@ -1,6 +1,6 @@ import { useCallback, useContext, useEffect, useMemo, useState } from 'react' -import { DownloadQuality, Name } from '@audius/common/models' +import { DownloadQuality } from '@audius/common/models' import { TrackMetadataFormSchema } from '@audius/common/schemas' import { TrackForUpload, @@ -49,7 +49,6 @@ import layoutStyles from 'components/layout/layout.module.css' import { NavigationPrompt } from 'components/navigation-prompt/NavigationPrompt' import { EditFormScrollContext } from 'pages/edit-page/EditTrackPage' import { processFiles } from 'pages/upload-page/store/utils/processFiles' -import { make, track as trackEvent } from 'services/analytics' import { removeNullable } from 'utils/typeUtils' import styles from './EditTrackForm.module.css' @@ -185,7 +184,6 @@ const TrackEditForm = ( const trackIdx = values.trackMetadatasIndex const [, , { setValue: setIndex }] = useField('trackMetadatasIndex') const initialTrackValues = initialValues.trackMetadatas[trackIdx] ?? {} - const initialTrackId = initialTrackValues.track_id const { values: formValues } = useFormikContext() as FormikContextType @@ -222,30 +220,11 @@ const TrackEditForm = ( }, [trackPreviewUrl]) const handleTogglePreview = useCallback(() => { - if (!isPreviewPlaying) { - // Track Preview event - trackEvent( - make({ - eventName: Name.TRACK_REPLACE_PREVIEW, - trackId: initialTrackId, - source: isUpload ? 'upload' : 'edit' - }) - ) - } - const currentPreview = (formValues.tracks[trackIdx] as TrackForUpload)?.preview ?? preview togglePreview(currentPreview, trackIdx) - }, [ - togglePreview, - formValues, - trackIdx, - preview, - isPreviewPlaying, - initialTrackId, - isUpload - ]) + }, [togglePreview, formValues, trackIdx, preview]) const getArtworkUrl = (artwork: typeof updatedArtwork) => { if (!artwork) return undefined @@ -297,15 +276,6 @@ const TrackEditForm = ( } setTrackValue(newFile) setOrigFilename(newFile.metadata.orig_filename) - - // Track replace event - trackEvent( - make({ - eventName: Name.TRACK_REPLACE_REPLACE, - trackId: initialTrackId, - source: isUpload ? 'upload' : 'edit' - }) - ) } }, [ @@ -318,7 +288,6 @@ const TrackEditForm = ( isArtworkSet, setTrackValue, setOrigFilename, - initialTrackId, setTitle, setArtworkValue ] @@ -336,14 +305,6 @@ const TrackEditForm = ( trackIds: [initialTrackValues.track_id], quality: DownloadQuality.ORIGINAL }) - - // Track Download event - trackEvent( - make({ - eventName: Name.TRACK_REPLACE_DOWNLOAD, - trackId: initialTrackValues.track_id - }) - ) }, [openWaitforDownload, initialTrackValues.track_id]) return ( diff --git a/packages/web/src/components/embed-modal/EmbedModal.tsx b/packages/web/src/components/embed-modal/EmbedModal.tsx index acb7e0ee6c9..bb04188cbb2 100644 --- a/packages/web/src/components/embed-modal/EmbedModal.tsx +++ b/packages/web/src/components/embed-modal/EmbedModal.tsx @@ -138,11 +138,6 @@ const EmbedModal = ({ isOpen, kind, id, close }: EmbedModalProps) => { // Configure analytics const record = useRecord() - useEffect(() => { - if (isOpen && kind && id) { - record(make(Name.EMBED_OPEN, { kind, id: `${id}` })) - } - }, [isOpen, kind, id, record]) const onCopy = useCallback(() => { if (kind && id) { record( diff --git a/packages/web/src/components/host-remix-contest-modal/HostRemixContestModal.tsx b/packages/web/src/components/host-remix-contest-modal/HostRemixContestModal.tsx index 47af02c9e1a..a3e5a735bc9 100644 --- a/packages/web/src/components/host-remix-contest-modal/HostRemixContestModal.tsx +++ b/packages/web/src/components/host-remix-contest-modal/HostRemixContestModal.tsx @@ -9,7 +9,6 @@ import { useUpdateEvent } from '@audius/common/api' import { remixMessages } from '@audius/common/messages' -import { Name } from '@audius/common/models' import { registerNiceModalId } from '@audius/common/services' import { useHostRemixContestModal } from '@audius/common/store' import { dayjs } from '@audius/common/utils' @@ -32,7 +31,6 @@ import NiceModal, { useModal } from '@ebay/nice-modal-react' import { DatePicker } from 'components/edit/fields/DatePickerField' import { mergeReleaseDateValues } from 'components/edit/fields/visibility/mergeReleaseDateValues' -import { track, make } from 'services/analytics' import { TimeInput, parseTime } from './TimeInput' @@ -155,14 +153,6 @@ export const HostRemixContestModal = NiceModal.create(() => { endDate, userId }) - - track( - make({ - eventName: Name.REMIX_CONTEST_UPDATE, - remixContestId: remixContest.eventId, - trackId - }) - ) } else { createEvent({ eventType: EventEventTypeEnum.RemixContest, @@ -172,13 +162,6 @@ export const HostRemixContestModal = NiceModal.create(() => { endDate, userId }) - - track( - make({ - eventName: Name.REMIX_CONTEST_CREATE, - trackId - }) - ) } onClose() @@ -202,18 +185,8 @@ export const HostRemixContestModal = NiceModal.create(() => { const handleDeleteEvent = useCallback(() => { if (!remixContest || !userId) return deleteEvent({ eventId: remixContest.eventId, userId }) - - if (trackId) { - track( - make({ - eventName: Name.REMIX_CONTEST_DELETE, - remixContestId: remixContest.eventId, - trackId - }) - ) - } onClose() - }, [remixContest, userId, deleteEvent, onClose, trackId]) + }, [remixContest, userId, deleteEvent, onClose]) return ( ) => void - source?: 'profile page' | 'track page' | 'collection page' ignoreWarning?: boolean children: ReactNode } export const ExternalLink = (props: ExternalLinkProps) => { - const { - to, - onClick, - source, - ignoreWarning = false, - children, - ...other - } = props + const { to, onClick, ignoreWarning = false, children, ...other } = props - const record = useRecord() const { onOpen: openLeavingAudiusModal } = useLeavingAudiusModal() const handleClick = useCallback( (event: MouseEvent) => { onClick?.(event) - if (source) { - record( - make(Name.LINK_CLICKING, { - // @ts-expect-error - url: event.target.href, - source - }) - ) - } if (to && !ignoreWarning && !isAllowedExternalLink(to)) { event.preventDefault() openLeavingAudiusModal({ link: to }) } }, - [onClick, record, source, openLeavingAudiusModal, to, ignoreWarning] + [onClick, openLeavingAudiusModal, to, ignoreWarning] ) return ( diff --git a/packages/web/src/components/link/ExternalTextLink.tsx b/packages/web/src/components/link/ExternalTextLink.tsx index 0b8206742c8..277b3036d9d 100644 --- a/packages/web/src/components/link/ExternalTextLink.tsx +++ b/packages/web/src/components/link/ExternalTextLink.tsx @@ -5,15 +5,10 @@ import { ExternalLink, ExternalLinkProps } from './ExternalLink' type ExternalTextLinkProps = Omit & ExternalLinkProps export const ExternalTextLink = (props: ExternalTextLinkProps) => { - const { to, onClick, source, ignoreWarning, children, ...other } = props + const { to, onClick, ignoreWarning, children, ...other } = props return ( - + {children} diff --git a/packages/web/src/components/nav/desktop/LeftNavLink.tsx b/packages/web/src/components/nav/desktop/LeftNavLink.tsx index 0ac528da1fb..2c0322d408b 100644 --- a/packages/web/src/components/nav/desktop/LeftNavLink.tsx +++ b/packages/web/src/components/nav/desktop/LeftNavLink.tsx @@ -1,11 +1,8 @@ import { ReactNode, useCallback, useMemo, useRef, useState } from 'react' -import { Name } from '@audius/common/models' import { NavItem, NavItemProps } from '@audius/harmony' -import { useDispatch } from 'react-redux' import { NavLink, useLocation } from 'react-router' -import { make } from 'common/store/analytics/actions' import { RestrictionType, useRequiresAccountOnClick @@ -72,7 +69,6 @@ export const LeftNavLink = (props: LeftNavLinkProps) => { ...other } = props const location = useLocation() - const dispatch = useDispatch() const { isCollapsed } = useNavSidebar() const [isFocusVisible, setIsFocusVisible] = useState(false) const isPointerFocusRef = useRef(false) @@ -88,18 +84,9 @@ export const LeftNavLink = (props: LeftNavLinkProps) => { const requiresAccountOnClick = useRequiresAccountOnClick( (e) => { - // Only dispatch analytics if we're actually navigating - if (to) { - dispatch( - make(Name.LINK_CLICKING, { - url: to, - source: 'left nav' - }) - ) - } onClick?.(e) }, - [onClick, to, dispatch], + [onClick], undefined, undefined, restriction diff --git a/packages/web/src/components/nav/desktop/PlaylistLibrary/CollectionNavItem.tsx b/packages/web/src/components/nav/desktop/PlaylistLibrary/CollectionNavItem.tsx index 0491d380388..a275a9b2d25 100644 --- a/packages/web/src/components/nav/desktop/PlaylistLibrary/CollectionNavItem.tsx +++ b/packages/web/src/components/nav/desktop/PlaylistLibrary/CollectionNavItem.tsx @@ -9,7 +9,6 @@ import { import { FavoriteSource, ID, - Name, PlaylistLibraryID, PlaylistLibraryKind, ShareSource @@ -36,7 +35,6 @@ import { useDispatch } from 'react-redux' import { useLocation, useNavigate } from 'react-router' import { useToggle } from 'react-use' -import { make, useRecord } from 'common/store/analytics/actions' import { Draggable } from 'components/dragndrop' import { DeleteCollectionConfirmationModal } from 'components/edit-collection/DeleteCollectionConfirmationModal' import { @@ -94,7 +92,6 @@ export const CollectionNavItem = (props: CollectionNavItemProps) => { const location = useLocation() const isSelected = location.pathname === url const dispatch = useDispatch() - const record = useRecord() const navigate = useNavigate() const { mutate: reorderLibrary } = useReorderLibrary() @@ -134,8 +131,7 @@ export const CollectionNavItem = (props: CollectionNavItemProps) => { const handleEdit = useCallback(() => { navigate(`${permalink}/edit`) - record(make(Name.PLAYLIST_OPEN_EDIT_FROM_LIBRARY, {})) - }, [navigate, permalink, record]) + }, [navigate, permalink]) const handleShare = useCallback(() => { dispatch( diff --git a/packages/web/src/components/nav/desktop/PlaylistLibrary/PlaylistFolderNavItem.tsx b/packages/web/src/components/nav/desktop/PlaylistLibrary/PlaylistFolderNavItem.tsx index 5df0652d52f..09be00b1031 100644 --- a/packages/web/src/components/nav/desktop/PlaylistLibrary/PlaylistFolderNavItem.tsx +++ b/packages/web/src/components/nav/desktop/PlaylistLibrary/PlaylistFolderNavItem.tsx @@ -4,11 +4,7 @@ import { useAddToPlaylistFolder, useAllPlaylistUpdateIds } from '@audius/common/api' -import { - Name, - PlaylistLibraryID, - PlaylistLibraryFolder -} from '@audius/common/models' +import { PlaylistLibraryID, PlaylistLibraryFolder } from '@audius/common/models' import { IconFolder, PopupMenuItem, @@ -22,7 +18,6 @@ import { import { ClassNames } from '@emotion/react' import { useToggle } from 'react-use' -import { make, useRecord } from 'common/store/analytics/actions' import { Draggable, Droppable } from 'components/dragndrop' import { EditFolderModal } from 'components/edit-folder-modal/EditFolderModal' import { DragDropKind, selectDraggingKind } from 'store/dragndrop/slice' @@ -67,7 +62,6 @@ export const PlaylistFolderNavItem = (props: PlaylistFolderNavItemProps) => { [setIsOpen] ) - const record = useRecord() const { mutate: addToPlaylistFolder } = useAddToPlaylistFolder() const [isDeleteConfirmationOpen, toggleDeleteConfirmationOpen] = useToggle(false) @@ -108,15 +102,11 @@ export const PlaylistFolderNavItem = (props: PlaylistFolderNavItemProps) => { setIsHoveringNested(false) }, []) - const handleClickEdit = useCallback( - (event: MouseEvent) => { - event.preventDefault() - event.stopPropagation() - setIsEditFolderOpen(true) - record(make(Name.FOLDER_OPEN_EDIT, {})) - }, - [record] - ) + const handleClickEdit = useCallback((event: MouseEvent) => { + event.preventDefault() + event.stopPropagation() + setIsEditFolderOpen(true) + }, []) const handleCloseEdit = useCallback(() => { setIsEditFolderOpen(false) diff --git a/packages/web/src/components/search-bar/SearchTag.tsx b/packages/web/src/components/search-bar/SearchTag.tsx index 6db09136784..2933750080a 100644 --- a/packages/web/src/components/search-bar/SearchTag.tsx +++ b/packages/web/src/components/search-bar/SearchTag.tsx @@ -1,38 +1,20 @@ -import { useCallback, MouseEvent } from 'react' +import { MouseEvent } from 'react' -import { Name, AllTrackingEvents } from '@audius/common/models' import { route } from '@audius/common/utils' import { Tag, TagProps } from '@audius/harmony' import { Link } from 'react-router' -import { make, useRecord } from 'common/store/analytics/actions' - -type TagClickingEvent = Extract< - AllTrackingEvents, - { eventName: Name.TAG_CLICKING } -> - type SearchTagProps = Extract & { onClick?: (e: MouseEvent) => void - source: TagClickingEvent['source'] } export const SearchTag = (props: SearchTagProps) => { - const { onClick, source, children, ...other } = props - const record = useRecord() - - const handleClick = useCallback( - (e: MouseEvent) => { - onClick?.(e) - record(make(Name.TAG_CLICKING, { tag: children, source })) - }, - [onClick, record, children, source] - ) + const { onClick, children, ...other } = props const linkTo = route.searchPage({ query: `#${children}` }) return ( - + {children} ) diff --git a/packages/web/src/components/track/DownloadSection.tsx b/packages/web/src/components/track/DownloadSection.tsx index 6662c367702..1de0bd1642c 100644 --- a/packages/web/src/components/track/DownloadSection.tsx +++ b/packages/web/src/components/track/DownloadSection.tsx @@ -6,7 +6,6 @@ import { useUploadingStems } from '@audius/common/hooks' import { - Name, ModalSource, DownloadQuality, ID, @@ -34,7 +33,6 @@ import { import { useDispatch } from 'react-redux' import { useModalState } from 'common/hooks/useModalState' -import { make, useRecord } from 'common/store/analytics/actions' import { Expandable } from 'components/expandable/Expandable' import { useIsMobile } from 'hooks/useIsMobile' import { @@ -68,7 +66,6 @@ type DownloadSectionProps = { export const DownloadSection = ({ trackId }: DownloadSectionProps) => { const dispatch = useDispatch() - const record = useRecord() const isMobile = useIsMobile() const { data: partialTrack } = useTrack(trackId, { select: (track) => { @@ -141,24 +138,6 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => { trackIds, quality: downloadQuality }) - - // Track download attempt event - if (parentTrackId) { - record( - make(Name.TRACK_DOWNLOAD_CLICKED_DOWNLOAD_ALL, { - parentTrackId, - stemTrackIds: trackIds, - device: 'web' - }) - ) - } else { - record( - make(Name.TRACK_DOWNLOAD_CLICKED_DOWNLOAD_SINGLE, { - trackId: trackIds[0], - device: 'web' - }) - ) - } } }, [ @@ -166,7 +145,6 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => { downloadQuality, isMobile, openWaitForDownloadModal, - record, shouldDisplayDownloadFollowGated, partialTrack ] diff --git a/packages/web/src/components/track/GiantTrackTile.tsx b/packages/web/src/components/track/GiantTrackTile.tsx index 9b3f9abbb36..b5736916def 100644 --- a/packages/web/src/components/track/GiantTrackTile.tsx +++ b/packages/web/src/components/track/GiantTrackTile.tsx @@ -418,9 +418,7 @@ export const GiantTrackTile = ({ .split(',') .filter((t) => t) .map((tag) => ( - - {tag} - + {tag} ))} ) diff --git a/packages/web/src/components/track/TrackStats.tsx b/packages/web/src/components/track/TrackStats.tsx index a00d2efb44a..9d8f5780895 100644 --- a/packages/web/src/components/track/TrackStats.tsx +++ b/packages/web/src/components/track/TrackStats.tsx @@ -1,5 +1,5 @@ import { useCurrentUserId, useTrack } from '@audius/common/api' -import { ID, Name } from '@audius/common/models' +import { ID } from '@audius/common/models' import { formatCount, isLongFormContent, pluralize } from '@audius/common/utils' import { Flex, @@ -12,7 +12,6 @@ import { import { pick } from 'lodash' import { useDispatch } from 'react-redux' -import { make, track as trackEvent } from 'services/analytics' import * as userListActions from 'store/application/ui/userListModal/slice' import { UserListEntityType, @@ -100,13 +99,6 @@ export const TrackStats = (props: TrackStatsProps) => { const handleClickComments = () => { scrollToCommentSection() - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_COMMENT_STAT, - trackId, - source: 'track_page' - }) - ) } const shouldUseMobileRules = forceMobileStyle diff --git a/packages/web/src/components/track/TrackTileMetrics.tsx b/packages/web/src/components/track/TrackTileMetrics.tsx index d4f4e7b6f0b..b8daff06dc3 100644 --- a/packages/web/src/components/track/TrackTileMetrics.tsx +++ b/packages/web/src/components/track/TrackTileMetrics.tsx @@ -1,7 +1,7 @@ import { useCallback } from 'react' import { useTrack } from '@audius/common/api' -import { FavoriteType, ID, Name } from '@audius/common/models' +import { FavoriteType, ID } from '@audius/common/models' import { favoritesUserListActions, repostsUserListActions, @@ -15,7 +15,6 @@ import { AvatarList } from 'components/avatar' import { UserName, VanityMetric } from 'components/entity/VanityMetrics' import { TrackTileSize } from 'components/track/types' import { useIsMobile } from 'hooks/useIsMobile' -import { make, track as trackEvent } from 'services/analytics' import { setUsers, setVisibility @@ -174,16 +173,6 @@ export const CommentMetric = (props: CommentMetricProps) => { }) const { commentCount = 0, permalink, commentsDisabled } = partialTrack ?? {} - const handleClick = useCallback(() => { - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_COMMENT_STAT, - trackId, - source: 'lineup' - }) - ) - }, [trackId]) - if (commentsDisabled) return null const url = isMobile @@ -192,7 +181,7 @@ export const CommentMetric = (props: CommentMetricProps) => { const isSmall = size === TrackTileSize.SMALL return ( - + {commentCount > 0 || isSmall ? formatCount(commentCount) diff --git a/packages/web/src/components/track/desktop/CollectionTile.tsx b/packages/web/src/components/track/desktop/CollectionTile.tsx index 7446e1707e4..abf5f2acda5 100644 --- a/packages/web/src/components/track/desktop/CollectionTile.tsx +++ b/packages/web/src/components/track/desktop/CollectionTile.tsx @@ -245,14 +245,6 @@ export const CollectionTile = ({ collectionId: `${id}` }) ) - record( - make(Name.PLAYLIST_PLAY, { - id: `${id}`, - source: PlaybackSource.PLAYLIST_TILE_TRACK, - isAlbum: !!isAlbum, - trackCount - }) - ) } } else { const trackId = tracks[0] ? tracks[0].track_id : null @@ -266,14 +258,6 @@ export const CollectionTile = ({ collectionId: `${id}` }) ) - record( - make(Name.PLAYLIST_PLAY, { - id: `${id}`, - source: PlaybackSource.PLAYLIST_TILE_TRACK, - isAlbum: !!isAlbum, - trackCount - }) - ) } } } else { @@ -298,8 +282,6 @@ export const CollectionTile = ({ playingTrackId, isUploading, id, - isAlbum, - trackCount, record ] ) diff --git a/packages/web/src/components/track/mobile/CollectionTile.tsx b/packages/web/src/components/track/mobile/CollectionTile.tsx index 4f802934763..011852a1384 100644 --- a/packages/web/src/components/track/mobile/CollectionTile.tsx +++ b/packages/web/src/components/track/mobile/CollectionTile.tsx @@ -490,14 +490,6 @@ export const CollectionTile = ({ collectionId: `${collection.playlist_id}` }) ) - record( - make(Name.PLAYLIST_PLAY, { - id: `${collection.playlist_id}`, - source, - isAlbum: !!collection.is_album, - trackCount: collection.track_count - }) - ) } else { const trackId = tracks[0] ? tracks[0].track_id : null if (!trackId) return @@ -509,14 +501,6 @@ export const CollectionTile = ({ collectionId: `${collection.playlist_id}` }) ) - record( - make(Name.PLAYLIST_PLAY, { - id: `${collection.playlist_id}`, - source, - isAlbum: !!collection.is_album, - trackCount: collection.track_count - }) - ) } } else { pauseTrack() @@ -538,8 +522,6 @@ export const CollectionTile = ({ playingTrackId, uploading, collection.playlist_id, - collection.is_album, - collection.track_count, record ]) diff --git a/packages/web/src/components/user-generated-text/UserGeneratedText.tsx b/packages/web/src/components/user-generated-text/UserGeneratedText.tsx index ec3948ec187..6d92c2cf647 100644 --- a/packages/web/src/components/user-generated-text/UserGeneratedText.tsx +++ b/packages/web/src/components/user-generated-text/UserGeneratedText.tsx @@ -42,7 +42,6 @@ const LinkifyText = forwardRef((props: LinkifyTextProps, ref) => { type UserGeneratedTextProps = TextProps & { linkProps?: Partial - linkSource?: 'profile page' | 'track page' | 'collection page' onClickLink?: (event: MouseEvent) => void } @@ -100,7 +99,6 @@ export const UserGeneratedText = forwardRef(function ( strength, lineHeight, tag = 'p', - linkSource, onClickLink, linkProps: textLinkProps, ...other @@ -110,7 +108,6 @@ export const UserGeneratedText = forwardRef(function ( () => ({ render: (linkProps) => , attributes: { - source: linkSource, onClick: onClickLink, textVariant: variant, size, @@ -119,15 +116,7 @@ export const UserGeneratedText = forwardRef(function ( ...textLinkProps } }), - [ - linkSource, - onClickLink, - variant, - size, - strength, - lineHeight, - textLinkProps - ] + [onClickLink, variant, size, strength, lineHeight, textLinkProps] ) const children = diff --git a/packages/web/src/hooks/useConnectAndAssociateWallets.ts b/packages/web/src/hooks/useConnectAndAssociateWallets.ts index 4a79952851f..9319423c9b3 100644 --- a/packages/web/src/hooks/useConnectAndAssociateWallets.ts +++ b/packages/web/src/hooks/useConnectAndAssociateWallets.ts @@ -6,8 +6,7 @@ import { useAddAssociatedWallet, useCurrentAccountUser } from '@audius/common/api' -import { useAppContext } from '@audius/common/context' -import { Name, Chain } from '@audius/common/models' +import { Chain } from '@audius/common/models' import type { NamespaceTypeMap } from '@reown/appkit' import type { EventsControllerState } from '@reown/appkit/react' import type { Provider as SolanaProvider } from '@reown/appkit-adapter-solana/react' @@ -83,9 +82,6 @@ export const useConnectAndAssociateWallets = ( onSuccess?: (wallets: ConnectedWallet[]) => void, onError?: (error: unknown) => void ) => { - const { - analytics: { track, make } - } = useAppContext() const { signMessageAgnostic } = useSignMessageAgnostic() const { data: currentUser } = useCurrentAccountUser() const { data: connectedWallets } = useAssociatedWallets() @@ -99,7 +95,6 @@ export const useConnectAndAssociateWallets = ( const associateConnectedWallets = useCallback(async () => { try { setIsAssociating(true) - track(make({ eventName: Name.CONNECT_WALLET_NEW_WALLET_START })) const activeAccount = appkitModal.getAccount() const originalAddress = currentUser?.wallet @@ -125,15 +120,6 @@ export const useConnectAndAssociateWallets = ( // Ensure there are wallets to associate if (filteredWallets.length === 0) { if (wallets.length > 0) { - for (const { chain, address } of wallets) { - track( - make({ - eventName: Name.CONNECT_WALLET_ALREADY_ASSOCIATED, - chain, - walletAddress: address - }) - ) - } throw new AlreadyAssociatedError('Wallets already added') } else { throw new Error('No wallets selected') @@ -147,13 +133,6 @@ export const useConnectAndAssociateWallets = ( address, chain }) - track( - make({ - eventName: Name.CONNECT_WALLET_NEW_WALLET_CONNECTING, - chain, - walletAddress: address - }) - ) const signature = await signMessageAgnostic( `AudiusUserID:${currentUser?.user_id}`, address, @@ -172,19 +151,11 @@ export const useConnectAndAssociateWallets = ( wallet: { address, chain }, signature }) - track( - make({ - eventName: Name.CONNECT_WALLET_NEW_WALLET_CONNECTED, - chain, - walletAddress: address - }) - ) } // DONE! onSuccess?.(filteredWallets) } catch (e) { - track(make({ eventName: Name.CONNECT_WALLET_ERROR, error: String(e) })) onError?.(e) } finally { setIsAssociating(false) @@ -194,11 +165,9 @@ export const useConnectAndAssociateWallets = ( connectedWallets, currentUser?.user_id, currentUser?.wallet, - make, onError, onSuccess, - signMessageAgnostic, - track + signMessageAgnostic ]) /** @@ -210,15 +179,9 @@ export const useConnectAndAssociateWallets = ( const handleConnectError = useCallback( (event: EventsControllerState) => { - track( - make({ - eventName: Name.CONNECT_WALLET_ERROR, - error: String(event.data) - }) - ) onError?.(event) }, - [make, onError, track] + [onError] ) const { isPending: isConnecting, openAppKitModal } = diff --git a/packages/web/src/hooks/useConnectExternalWallets.ts b/packages/web/src/hooks/useConnectExternalWallets.ts index 5f4f5dd2ff6..f308187136c 100644 --- a/packages/web/src/hooks/useConnectExternalWallets.ts +++ b/packages/web/src/hooks/useConnectExternalWallets.ts @@ -1,7 +1,6 @@ import { useState, useCallback, useEffect, useRef } from 'react' import { useCurrentAccountUser } from '@audius/common/api' -import { Name, Chain } from '@audius/common/models' import { isLightTheme } from '@audius/harmony' import { useTheme } from '@emotion/react' import type { NamespaceTypeMap } from '@reown/appkit' @@ -14,7 +13,6 @@ import { import { useSwitchAccount, useAccount } from 'wagmi' import { appkitModal, audiusChain } from 'app/ReownAppKitModal' -import { useRecord, make } from 'common/store/analytics/actions' /** * Error when trying to associate a wallet that was already associated */ @@ -46,7 +44,6 @@ export const useConnectExternalWallets = ( }) => void, onError?: (error: EventsControllerState) => void ) => { - const record = useRecord() const theme = useTheme() const { open: openAppKitModal, close: closeAppKitModal } = useAppKit() const { data: currentUser } = useCurrentAccountUser() @@ -80,7 +77,6 @@ export const useConnectExternalWallets = ( */ const openAppKitModalCallback = useCallback( async (namespace?: keyof NamespaceTypeMap) => { - record(make(Name.CONNECT_WALLET_NEW_WALLET_START, {})) setIsConnecting(true) // If previously connected, disconnect to give a "fresh" view of options if (isConnected) { @@ -93,7 +89,7 @@ export const useConnectExternalWallets = ( await appkitModal.switchNetwork(mainnet) await openAppKitModal({ view: 'Connect', namespace }) }, - [disconnect, isConnected, openAppKitModal, record, theme] + [disconnect, isConnected, openAppKitModal, theme] ) /** @@ -140,23 +136,6 @@ export const useConnectExternalWallets = ( const solAddress = solanaAccount?.address const ethAddress = ethAccount?.address - // Track analytics for connected wallets - if (solAddress) { - record( - make(Name.CONNECT_WALLET_NEW_WALLET_CONNECTED, { - chain: Chain.Sol, - walletAddress: solAddress - }) - ) - } - if (ethAddress) { - record( - make(Name.CONNECT_WALLET_NEW_WALLET_CONNECTED, { - chain: Chain.Eth, - walletAddress: ethAddress - }) - ) - } if (!solAddress && !ethAddress) { console.error( 'Connect Wallet Error', @@ -176,11 +155,6 @@ export const useConnectExternalWallets = ( closeAppKitModal() } else if (event.data.event === 'CONNECT_ERROR') { setIsConnecting(false) - record( - make(Name.CONNECT_WALLET_ERROR, { - error: String(event.data) - }) - ) console.error('Connect Wallet Error', new Error('Connect Wallet Error')) onError?.(event) } @@ -190,8 +164,7 @@ export const useConnectExternalWallets = ( reconnectExternalAuthWallet, isConnecting, closeAppKitModal, - onError, - record + onError ]) return { diff --git a/packages/web/src/pages/chat-page/ChatPage.tsx b/packages/web/src/pages/chat-page/ChatPage.tsx index 160ea1432ac..1c263eb30ed 100644 --- a/packages/web/src/pages/chat-page/ChatPage.tsx +++ b/packages/web/src/pages/chat-page/ChatPage.tsx @@ -1,9 +1,8 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { useCanSendMessage } from '@audius/common/hooks' -import { Name, Status } from '@audius/common/models' +import { Status } from '@audius/common/models' import { chatActions, chatSelectors, InboxTab } from '@audius/common/store' -import { ChatBlast, OptionalHashId } from '@audius/sdk' import cn from 'classnames' import { useDispatch } from 'react-redux' import { useParams, useLocation, useNavigate } from 'react-router' @@ -12,7 +11,6 @@ import Page from 'components/page/Page' import { useIsContainerNarrow } from 'hooks/useIsContainerNarrow' import { useIsMobile } from 'hooks/useIsMobile' import { useManagedAccountNotAllowedRedirect } from 'hooks/useManagedAccountNotAllowedRedirect' -import { make, track } from 'services/analytics' import { push } from 'utils/navigation' import { useSelector } from 'utils/reducer' import { chatPage } from 'utils/route' @@ -35,36 +33,6 @@ const messages = { const NARROW_LAYOUT_THRESHOLD_PX = 1080 -// Local-storage key tracking which blast chat threads the user has already -// viewed, so the `Chat Blast: Message Viewed` event fires only once per blast. -const VIEWED_BLAST_CHATS_LOCAL_STORAGE_KEY = 'viewedBlastChats' - -const getViewedBlastChats = (): string[] => { - try { - const raw = window.localStorage.getItem( - VIEWED_BLAST_CHATS_LOCAL_STORAGE_KEY - ) - const parsed = raw ? JSON.parse(raw) : [] - return Array.isArray(parsed) ? parsed : [] - } catch { - return [] - } -} - -const markBlastChatViewed = (chatId: string) => { - try { - const viewed = getViewedBlastChats() - if (!viewed.includes(chatId)) { - window.localStorage.setItem( - VIEWED_BLAST_CHATS_LOCAL_STORAGE_KEY, - JSON.stringify([...viewed, chatId]) - ) - } - } catch { - // Ignore local-storage write failures; worst case the event fires again. - } -} - export const ChatPage = () => { useManagedAccountNotAllowedRedirect() const params = useParams<{ id?: string }>() @@ -143,26 +111,6 @@ export const ChatPage = () => { } }, [dispatch, firstOtherUser, isMobile]) - // Track when a user opens a blast DM thread. Fires once per blast per user. - useEffect(() => { - if (!currentChatId || !chat?.is_blast) return - const viewed = getViewedBlastChats() - if (viewed.includes(currentChatId)) return - const blastChat = chat as ChatBlast - markBlastChatViewed(currentChatId) - track( - make({ - eventName: Name.CHAT_BLAST_MESSAGE_VIEWED, - isNativeMobile: false, - chatId: currentChatId, - audience: blastChat.audience, - audienceContentType: blastChat.audience_content_type, - audienceContentId: - OptionalHashId.parse(blastChat.audience_content_id) ?? undefined - }) - ) - }, [currentChatId, chat]) - if (isMobile) { return } diff --git a/packages/web/src/pages/chat-page/components/ChatBlastCTA.tsx b/packages/web/src/pages/chat-page/components/ChatBlastCTA.tsx index 10bafe7e408..40cc7eeb8fe 100644 --- a/packages/web/src/pages/chat-page/components/ChatBlastCTA.tsx +++ b/packages/web/src/pages/chat-page/components/ChatBlastCTA.tsx @@ -1,7 +1,6 @@ import { useCallback } from 'react' import { useCanSendChatBlast } from '@audius/common/hooks' -import { Name } from '@audius/common/models' import { useChatBlastModal } from '@audius/common/src/store' import { Box, @@ -14,7 +13,6 @@ import { IconTokenBronze } from '@audius/harmony' -import { make, track } from 'services/analytics' const messages = { title: 'Send a Message Blast', description: 'Send messages to your fans in bulk.', @@ -34,7 +32,6 @@ export const ChatBlastCTA = (props: ChatBlastCTAProps) => { const handleClick = useCallback(() => { onClick() openChatBlastModal() - track(make({ eventName: Name.CHAT_BLAST_CTA_CLICKED })) }, [onClick, openChatBlastModal]) const userMeetsRequirements = useCanSendChatBlast() diff --git a/packages/web/src/pages/chat-page/components/ChatMessagePlaylist.tsx b/packages/web/src/pages/chat-page/components/ChatMessagePlaylist.tsx index 4ec154bc304..745330ffa7d 100644 --- a/packages/web/src/pages/chat-page/components/ChatMessagePlaylist.tsx +++ b/packages/web/src/pages/chat-page/components/ChatMessagePlaylist.tsx @@ -7,13 +7,11 @@ import { useTracks } from '@audius/common/api' import { usePlayTrack, usePauseTrack } from '@audius/common/hooks' -import { Name, ModalSource } from '@audius/common/models' +import { ModalSource } from '@audius/common/models' import { QueueSource, ChatMessageTileProps } from '@audius/common/store' import { getPathFromPlaylistUrl } from '@audius/common/utils' import { useQuery } from '@tanstack/react-query' -import { useDispatch } from 'react-redux' -import { make } from 'common/store/analytics/actions' import { CollectionTile } from 'components/track/mobile/CollectionTile' import { TrackTileSize } from 'components/track/types' @@ -25,8 +23,6 @@ export const ChatMessagePlaylist = ({ onSuccess, className }: ChatMessageTileProps) => { - const dispatch = useDispatch() - const permalink = getPathFromPlaylistUrl(link) ?? '' const { data: playlist } = useCollectionByPermalink(permalink) @@ -77,7 +73,6 @@ export const ChatMessagePlaylist = ({ // resolving so the URL text doesn't flash before the tile or empty state. if (isPending) return if (hasResolvedCollection) { - dispatch(make(Name.MESSAGE_UNFURL_PLAYLIST, {})) onSuccess?.() } else { // Collection URL resolved to nothing playable (deleted or missing) — @@ -85,7 +80,7 @@ export const ChatMessagePlaylist = ({ // showing a misleading or generic preview. onEmpty?.() } - }, [isPending, hasResolvedCollection, onSuccess, onEmpty, dispatch]) + }, [isPending, hasResolvedCollection, onSuccess, onEmpty]) if (isPending) { return diff --git a/packages/web/src/pages/chat-page/components/ChatMessageTrack.tsx b/packages/web/src/pages/chat-page/components/ChatMessageTrack.tsx index bad26b3ce81..7e49a64bdfb 100644 --- a/packages/web/src/pages/chat-page/components/ChatMessageTrack.tsx +++ b/packages/web/src/pages/chat-page/components/ChatMessageTrack.tsx @@ -9,7 +9,7 @@ import { useGatedContentAccess, useToggleTrack } from '@audius/common/hooks' -import { Name, PlaybackSource, ID, ModalSource } from '@audius/common/models' +import { PlaybackSource, ID, ModalSource } from '@audius/common/models' import { QueueSource, ChatMessageTileProps } from '@audius/common/store' import { getPathFromTrackUrl } from '@audius/common/utils' import { useQuery } from '@tanstack/react-query' @@ -92,7 +92,6 @@ export const ChatMessageTrack = ({ // resolving so the URL text doesn't flash before the tile or empty state. if (isPending) return if (hasResolvedTrack) { - dispatch(make(Name.MESSAGE_UNFURL_TRACK, {})) onSuccess?.() } else { // Track URL resolved to nothing playable (deleted or missing) — @@ -100,7 +99,7 @@ export const ChatMessageTrack = ({ // showing a misleading or generic preview. onEmpty?.() } - }, [isPending, hasResolvedTrack, onSuccess, onEmpty, dispatch]) + }, [isPending, hasResolvedTrack, onSuccess, onEmpty]) if (isPending) { return diff --git a/packages/web/src/pages/collection-page/useCollectionPage.ts b/packages/web/src/pages/collection-page/useCollectionPage.ts index 3ea683de8f7..cf07cde56f7 100644 --- a/packages/web/src/pages/collection-page/useCollectionPage.ts +++ b/packages/web/src/pages/collection-page/useCollectionPage.ts @@ -668,17 +668,6 @@ export const useCollectionPage = ( ...(playlistId ? { collectionId: `${playlistId}` } : {}) }) ) - if (playlistId) { - dispatch( - make(Name.PLAYLIST_PLAY, { - id: `${playlistId}`, - source: PlaybackSource.PLAYLIST_PAGE, - isAlbum: !!collection?.is_album, - trackCount, - isPreview: shouldPreview - }) - ) - } } else if (tracks.entries.length > 0) { dispatch(playbackActions.stop({})) const firstEntry = tracks.entries[0] @@ -702,17 +691,6 @@ export const useCollectionPage = ( ...(playlistId ? { collectionId: `${playlistId}` } : {}) }) ) - if (playlistId) { - dispatch( - make(Name.PLAYLIST_PLAY, { - id: `${playlistId}`, - source: PlaybackSource.PLAYLIST_PAGE, - isAlbum: !!collection?.is_album, - trackCount, - isPreview: shouldPreview - }) - ) - } } }, [ @@ -724,7 +702,6 @@ export const useCollectionPage = ( tracks.entries, getPlayingId, playlistId, - trackCount, dispatch, collectionPlaybackQueue ] diff --git a/packages/web/src/pages/comment-history/components/desktop/CommentHistoryPage.tsx b/packages/web/src/pages/comment-history/components/desktop/CommentHistoryPage.tsx index 0f2246bf99f..beafeb7eeba 100644 --- a/packages/web/src/pages/comment-history/components/desktop/CommentHistoryPage.tsx +++ b/packages/web/src/pages/comment-history/components/desktop/CommentHistoryPage.tsx @@ -6,7 +6,6 @@ import { useUserByParams, useUserComments } from '@audius/common/api' -import { Name } from '@audius/common/models' import { profilePage } from '@audius/common/src/utils/route' import { dayjs } from '@audius/common/utils' import { @@ -33,7 +32,6 @@ import { TrackLink, UserLink } from 'components/link' import Page from 'components/page/Page' import { useMainContentRef } from 'pages/MainContentContext' import { useProfileParams } from 'pages/profile-page/useProfileParams' -import { make, track as trackEvent } from 'services/analytics' import { fullCommentHistoryPage } from 'utils/route' const messages = { @@ -67,24 +65,11 @@ const UserComment = ({ comment }: { comment: CommentOrReply }) => { [createdAt] ) - const trackUserCommentClick = useCallback(() => { - if (userId) { - trackEvent( - make({ - eventName: Name.COMMENTS_HISTORY_CLICK, - commentId: id, - userId - }) - ) - } - }, [id, userId]) - const goToTrackPage = useCallback(() => { if (track) { - trackUserCommentClick() navigate(track.permalink) } - }, [track, trackUserCommentClick, navigate]) + }, [track, navigate]) if (!comment || !userId) return null @@ -96,11 +81,7 @@ const UserComment = ({ comment }: { comment: CommentOrReply }) => { {track ? ( - + {messages.by} diff --git a/packages/web/src/pages/contest-page/components/desktop/ContestPage.tsx b/packages/web/src/pages/contest-page/components/desktop/ContestPage.tsx index c38bd4b4d90..bb4296f427a 100644 --- a/packages/web/src/pages/contest-page/components/desktop/ContestPage.tsx +++ b/packages/web/src/pages/contest-page/components/desktop/ContestPage.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import { getRemixesQueryKey, @@ -15,7 +15,7 @@ import { useUser } from '@audius/common/api' import type { ID } from '@audius/common/models' -import { Name, SquareSizes, ShareSource } from '@audius/common/models' +import { SquareSizes, ShareSource } from '@audius/common/models' import { remixesPageActions, remixesPageSelectors, @@ -52,7 +52,6 @@ import { useRequiresAccountCallback } from 'hooks/useRequiresAccount' import { useTrackCoverArt } from 'hooks/useTrackCoverArt' import { useRemixPageParams } from 'pages/remixes-page/hooks' import { useUpdateSearchParams } from 'pages/search-page/hooks' -import { make, track as trackEvent } from 'services/analytics' import { fullContestPage, hostRemixContestPage, @@ -314,24 +313,6 @@ const ContestPage = ({ containerRef: _containerRef }: ContestPageProps) => { } }, [dispatch]) - // Fire a Remix Contest: View event the first time the page resolves a - // trackId + eventId for the contest. Guard with a ref so navigating - // between contest tabs (which doesn't unmount the page) doesn't - // re-fire the event. - const hasFiredViewRef = useRef(false) - useEffect(() => { - if (hasFiredViewRef.current) return - if (trackId == null || eventId == null) return - hasFiredViewRef.current = true - trackEvent( - make({ - eventName: Name.REMIX_CONTEST_VIEW, - remixContestId: eventId, - trackId - }) - ) - }, [trackId, eventId]) - const isEnded = useMemo(() => { if (!contest?.endDate) return true return dayjs(contest.endDate).isBefore(dayjs()) @@ -384,17 +365,8 @@ const ContestPage = ({ containerRef: _containerRef }: ContestPageProps) => { // pre-filled form regardless of entry point. const enterContest = useEnterContest(trackId) const handleEnterContest = useCallback(async () => { - if (trackId != null && eventId != null) { - trackEvent( - make({ - eventName: Name.REMIX_CONTEST_ENTER, - remixContestId: eventId, - trackId - }) - ) - } await enterContest() - }, [enterContest, trackId, eventId]) + }, [enterContest]) const handleShareContest = useCallback(() => { if (!trackId) return @@ -740,15 +712,6 @@ const ContestPage = ({ containerRef: _containerRef }: ContestPageProps) => { isSelected={activeTab === 'submissions'} label={messages.submissionsTab(submissionsCount)} onClick={() => { - if (activeTab !== 'submissions' && trackId && eventId) { - trackEvent( - make({ - eventName: Name.REMIX_CONTEST_VIEW_SUBMISSIONS, - remixContestId: eventId, - trackId - }) - ) - } setActiveTab('submissions') }} /> diff --git a/packages/web/src/pages/deactivate-account-page/DeactivateAccountPage.tsx b/packages/web/src/pages/deactivate-account-page/DeactivateAccountPage.tsx index a57a25460a3..09b0615afef 100644 --- a/packages/web/src/pages/deactivate-account-page/DeactivateAccountPage.tsx +++ b/packages/web/src/pages/deactivate-account-page/DeactivateAccountPage.tsx @@ -1,6 +1,6 @@ import { ReactNode, useCallback, useEffect } from 'react' -import { Name, Status } from '@audius/common/models' +import { Status } from '@audius/common/models' import { deactivateAccountActions, deactivateAccountSelectors @@ -10,7 +10,6 @@ import cn from 'classnames' import { useDispatch, useSelector } from 'react-redux' import { useModalState } from 'common/hooks/useModalState' -import { make, useRecord } from 'common/store/analytics/actions' import LoadingSpinnerFullPage from 'components/loading-spinner-full-page/LoadingSpinnerFullPage' import { useIsMobile } from 'hooks/useIsMobile' import { push } from 'utils/navigation' @@ -145,10 +144,6 @@ export const DeactivateAccountPage = () => { }, [onConfirm, closeConfirmation] ) - const record = useRecord() - useEffect(() => { - record(make(Name.DEACTIVATE_ACCOUNT_PAGE_VIEW, {})) - }, [record]) useEffect(() => { if (deactivateAccountStatus === Status.ERROR) { diff --git a/packages/web/src/pages/edit-collection-page/desktop/EditCollectionPage.tsx b/packages/web/src/pages/edit-collection-page/desktop/EditCollectionPage.tsx index 2ccd113a066..082b5875571 100644 --- a/packages/web/src/pages/edit-collection-page/desktop/EditCollectionPage.tsx +++ b/packages/web/src/pages/edit-collection-page/desktop/EditCollectionPage.tsx @@ -2,13 +2,12 @@ import { useCollectionByPermalink, useCollectionTracks } from '@audius/common/api' -import { Name, SquareSizes } from '@audius/common/models' +import { SquareSizes } from '@audius/common/models' import { CollectionValues } from '@audius/common/schemas' import { EditCollectionValues, cacheCollectionsActions } from '@audius/common/store' -import { isEqual } from 'lodash' import { useDispatch } from 'react-redux' import { useParams, useMatch, useSearchParams } from 'react-router' @@ -19,7 +18,6 @@ import Page from 'components/page/Page' import { useCollectionCoverArt } from 'hooks/useCollectionCoverArt' import { useIsUnauthorizedForHandleRedirect } from 'hooks/useManagedAccountNotAllowedRedirect' import { useRequiresAccount } from 'hooks/useRequiresAccount' -import { track } from 'services/analytics' import { replace } from 'utils/navigation' import { getEditablePlaylistContents, updatePlaylistContents } from '../utils' @@ -75,25 +73,6 @@ export const EditCollectionPage = () => { const handleSubmit = (values: CollectionValues) => { const { playlist_contents, tracks, ...restValues } = values - track({ - eventName: Name.COLLECTION_EDIT, - properties: { - id: playlist_id - } - }) - - // We want to pay special attention to access condition changes - if (!isEqual(values.stream_conditions, initialValues.stream_conditions)) { - track({ - eventName: Name.COLLECTION_EDIT_ACCESS_CHANGED, - properties: { - id: playlist_id, - from: initialValues.stream_conditions, - to: values.stream_conditions - } - }) - } - const updatedPlaylistContents = updatePlaylistContents( tracks, playlist_contents diff --git a/packages/web/src/pages/edit-collection-page/mobile/EditCollectionPage.tsx b/packages/web/src/pages/edit-collection-page/mobile/EditCollectionPage.tsx index 79030932216..68e26a2edfe 100644 --- a/packages/web/src/pages/edit-collection-page/mobile/EditCollectionPage.tsx +++ b/packages/web/src/pages/edit-collection-page/mobile/EditCollectionPage.tsx @@ -8,7 +8,7 @@ import { } from '@audius/common/api' import { imageBlank as placeholderCoverArt } from '@audius/common/assets' import { useGatedContentAccessMap } from '@audius/common/hooks' -import { SquareSizes, Collection, ID, Name } from '@audius/common/models' +import { SquareSizes, Collection, ID } from '@audius/common/models' import { newCollectionMetadata } from '@audius/common/schemas' import { RandomImage } from '@audius/common/services' import { @@ -33,7 +33,6 @@ import { useCollectionCoverArt } from 'hooks/useCollectionCoverArt' import { useIsUnauthorizedForHandleRedirect } from 'hooks/useManagedAccountNotAllowedRedirect' import { useRequiresAccount } from 'hooks/useRequiresAccount' import UploadStub from 'pages/profile-page/components/mobile/UploadStub' -import { track } from 'services/analytics' import { AppState } from 'store/types' import { resizeImage } from 'utils/imageProcessingUtil' import { replace } from 'utils/navigation' @@ -235,13 +234,6 @@ const EditCollectionPage = g(({ removeTrack, editPlaylist, orderPlaylist }) => { editPlaylist(collection.playlist_id, formFields as EditCollectionValues) - track({ - eventName: Name.COLLECTION_EDIT, - properties: { - id: collection.playlist_id - } - }) - dispatch(replace(permalink)) } }, [ diff --git a/packages/web/src/pages/host-remix-contest-page/HostRemixContestPage.tsx b/packages/web/src/pages/host-remix-contest-page/HostRemixContestPage.tsx index 2d611f78bcf..14a6592851b 100644 --- a/packages/web/src/pages/host-remix-contest-page/HostRemixContestPage.tsx +++ b/packages/web/src/pages/host-remix-contest-page/HostRemixContestPage.tsx @@ -13,7 +13,7 @@ import { useUser } from '@audius/common/api' import { remixMessages } from '@audius/common/messages' -import { Name, SquareSizes } from '@audius/common/models' +import { SquareSizes } from '@audius/common/models' import { dayjs, getVideoThumbnailUrl, @@ -48,7 +48,6 @@ import { mergeReleaseDateValues } from 'components/edit/fields/visibility/mergeR import Page from 'components/page/Page' import { useRequiresAccount } from 'hooks/useRequiresAccount' import { useTrackCoverArt } from 'hooks/useTrackCoverArt' -import { track, make } from 'services/analytics' import { contestPage } from 'utils/route' import { @@ -535,14 +534,6 @@ export const HostRemixContestPage = () => { endDate, userId: currentUserId }) - - track( - make({ - eventName: Name.REMIX_CONTEST_UPDATE, - remixContestId: remixContest.eventId, - trackId: entityTrackId - }) - ) } else { try { await createEvent({ @@ -559,13 +550,6 @@ export const HostRemixContestPage = () => { // contest page. return } - - track( - make({ - eventName: Name.REMIX_CONTEST_CREATE, - trackId: entityTrackId - }) - ) } clearDraft() @@ -601,15 +585,6 @@ export const HostRemixContestPage = () => { if (!remixContest || !currentUserId) return deleteEvent({ eventId: remixContest.eventId, userId: currentUserId }) - if (primaryTrackId) { - track( - make({ - eventName: Name.REMIX_CONTEST_DELETE, - remixContestId: remixContest.eventId, - trackId: primaryTrackId - }) - ) - } clearDraft() if (primaryPermalink) { navigate(primaryPermalink) @@ -619,7 +594,6 @@ export const HostRemixContestPage = () => { remixContest, currentUserId, deleteEvent, - primaryTrackId, primaryPermalink, navigate ]) diff --git a/packages/web/src/pages/library-page/components/mobile/NewCollectionButton.tsx b/packages/web/src/pages/library-page/components/mobile/NewCollectionButton.tsx index 3a507f79f38..02ce1d69db8 100644 --- a/packages/web/src/pages/library-page/components/mobile/NewCollectionButton.tsx +++ b/packages/web/src/pages/library-page/components/mobile/NewCollectionButton.tsx @@ -1,12 +1,10 @@ import { useCallback } from 'react' -import { Name, CreatePlaylistSource } from '@audius/common/models' +import { CreatePlaylistSource } from '@audius/common/models' import { cacheCollectionsActions } from '@audius/common/store' import { connect } from 'react-redux' import { Dispatch } from 'redux' -import { useRecord, make } from 'common/store/analytics/actions' - import styles from './NewCollectionButton.module.css' const { createPlaylist, createAlbum } = cacheCollectionsActions @@ -29,8 +27,6 @@ const NewCollectionButton = ({ onClick, collectionType }: NewCollectionButtonProps) => { - const record = useRecord() - const handleClick = useCallback(() => { if (onClick) { onClick() @@ -41,12 +37,7 @@ const NewCollectionButton = ({ createNewPlaylist() } } - record( - make(Name.PLAYLIST_OPEN_CREATE, { - source: CreatePlaylistSource.LIBRARY_PAGE - }) - ) - }, [collectionType, createNewAlbum, createNewPlaylist, onClick, record]) + }, [collectionType, createNewAlbum, createNewPlaylist, onClick]) return ( - diff --git a/packages/web/src/pages/settings-page/components/mobile/AccountSettingsPage.tsx b/packages/web/src/pages/settings-page/components/mobile/AccountSettingsPage.tsx index b1b8424ba7c..349932f7051 100644 --- a/packages/web/src/pages/settings-page/components/mobile/AccountSettingsPage.tsx +++ b/packages/web/src/pages/settings-page/components/mobile/AccountSettingsPage.tsx @@ -5,7 +5,7 @@ import { useCurrentAccountUser, useCurrentUserEmail } from '@audius/common/api' -import { Name, SquareSizes } from '@audius/common/models' +import { SquareSizes } from '@audius/common/models' import { useTierAndVerifiedForUser } from '@audius/common/store' import { route } from '@audius/common/utils' import { @@ -26,7 +26,6 @@ import { import { debounce } from 'lodash' import { useDispatch } from 'react-redux' -import { make, useRecord } from 'common/store/analytics/actions' import MobilePageContainer from 'components/mobile-page-container/MobilePageContainer' import { ToastContext } from 'components/toast/ToastContext' import { useProfilePicture } from 'hooks/useProfilePicture' @@ -196,7 +195,6 @@ const AccountSettingsPage = () => { userId, size: SquareSizes.SIZE_480_BY_480 }) - const record = useRecord() const onClickRecover = useCallback( () => debounce( @@ -206,7 +204,6 @@ const AccountSettingsPage = () => { await authService.generateRecoveryInfo() ) toast(messages.emailSent) - record(make(Name.SETTINGS_RESEND_ACCOUNT_RECOVERY, {})) } catch (e) { toast(messages.emailNotSent) } @@ -214,7 +211,7 @@ const AccountSettingsPage = () => { 2000, { leading: true, trailing: false } )(), - [authService, identityService, toast, record] + [authService, identityService, toast] ) const onClickResendVerificationEmail = useCallback(async () => { diff --git a/packages/web/src/pages/settings-page/components/mobile/SettingsPage.tsx b/packages/web/src/pages/settings-page/components/mobile/SettingsPage.tsx index 0a476d8fa28..eda39c48043 100644 --- a/packages/web/src/pages/settings-page/components/mobile/SettingsPage.tsx +++ b/packages/web/src/pages/settings-page/components/mobile/SettingsPage.tsx @@ -3,7 +3,6 @@ import { useCallback, useContext, useEffect, useState, FC } from 'react' import { useCurrentAccountUser } from '@audius/common/api' import { settingsMessages } from '@audius/common/messages' import { - Name, SquareSizes, Theme, ThemeMode, @@ -36,7 +35,6 @@ import cn from 'classnames' import { useDispatch, useSelector } from 'react-redux' import { useSearchParams } from 'react-router' -import { make } from 'common/store/analytics/actions' import GroupableList from 'components/groupable-list/GroupableList' import Grouping from 'components/groupable-list/Grouping' import Row from 'components/groupable-list/Row' @@ -208,9 +206,6 @@ export const SettingsPage = (props: SettingsPageProps) => { window.localStorage.setItem(THEME_KEY, Theme.MATRIX) } } - dispatch( - make(Name.SETTINGS_CHANGE_THEME, { mode: 'palette', palette: value }) - ) } const onModeChange = (option: ThemeMode) => { @@ -226,11 +221,6 @@ export const SettingsPage = (props: SettingsPageProps) => { window.localStorage.setItem(THEME_MODE_KEY, option) window.localStorage.setItem(THEME_KEY, theme) } - dispatch( - make(Name.SETTINGS_CHANGE_THEME, { - mode: option.toLowerCase() as 'dark' | 'light' | 'auto' - }) - ) } const paletteOptions = [ diff --git a/packages/web/src/pages/settings-page/components/mobile/SignOutModal.tsx b/packages/web/src/pages/settings-page/components/mobile/SignOutModal.tsx index 56b2cba96e3..bf727a1299e 100644 --- a/packages/web/src/pages/settings-page/components/mobile/SignOutModal.tsx +++ b/packages/web/src/pages/settings-page/components/mobile/SignOutModal.tsx @@ -1,6 +1,5 @@ import { useCallback } from 'react' -import { Name } from '@audius/common/models' import { signOutActions } from '@audius/common/store' import { Button, @@ -14,8 +13,6 @@ import { } from '@audius/harmony' import { useDispatch } from 'react-redux' -import { make, useRecord } from 'common/store/analytics/actions' - const { signOut } = signOutActions const messages = { @@ -32,16 +29,11 @@ type SignOutModalProps = Omit const SignOutModal = (props: SignOutModalProps) => { const { onClose } = props - const record = useRecord() const dispatch = useDispatch() const handleSignOut = useCallback(() => { - record( - make(Name.SETTINGS_LOG_OUT, { - callback: () => dispatch(signOut()) - }) - ) - }, [record, dispatch]) + dispatch(signOut()) + }, [dispatch]) return ( diff --git a/packages/web/src/pages/settings-page/store/sagas.ts b/packages/web/src/pages/settings-page/store/sagas.ts index 178a7d3384b..ccd58e0013a 100644 --- a/packages/web/src/pages/settings-page/store/sagas.ts +++ b/packages/web/src/pages/settings-page/store/sagas.ts @@ -1,5 +1,4 @@ import { queryHasAccount } from '@audius/common/api' -import { Name } from '@audius/common/models' import { settingsPageSelectors, settingsPageActions as actions, @@ -10,7 +9,6 @@ import { import { getErrorMessage } from '@audius/common/utils' import { select, call, put, takeEvery } from 'typed-redux-saga' -import { make } from 'common/store/analytics/actions' import commonSettingsSagas from 'common/store/pages/settings/sagas' import { Permission, @@ -96,11 +94,6 @@ function* watchToogleBrowserPushNotification() { subscription }) } - const event = make(Name.BROWSER_NOTIFICATION_SETTINGS, { - provider: 'gcm', - enabled: action.enabled - }) - yield* put(event) } } else if (isSafariPushAvailable) { const pushPermission = getSafariPushBrowser() @@ -115,12 +108,6 @@ function* watchToogleBrowserPushNotification() { deviceType: 'safari' }) } - - const event = make(Name.BROWSER_NOTIFICATION_SETTINGS, { - provider: 'safari', - enabled: true - }) - yield* put(event) } else if ( !action.enabled && pushPermission.permission === Permission.GRANTED @@ -131,12 +118,6 @@ function* watchToogleBrowserPushNotification() { deviceToken: pushPermission.deviceToken }) } - - const event = make(Name.BROWSER_NOTIFICATION_SETTINGS, { - provider: 'safari', - enabled: false - }) - yield* put(event) } } } catch (error) { @@ -233,12 +214,6 @@ function* watchUpdateNotificationSettings() { sdk, settings: { [action.notificationType]: isOn } }) - - const event = make(Name.NOTIFICATIONS_TOGGLE_SETTINGS, { - settings: action.notificationType, - enabled: isOn - }) - yield* put(event) } catch (error) { console.error(error) yield* put( diff --git a/packages/web/src/pages/track-page/components/mobile/DownloadSection.tsx b/packages/web/src/pages/track-page/components/mobile/DownloadSection.tsx index 9d70b208afd..abeeeb13730 100644 --- a/packages/web/src/pages/track-page/components/mobile/DownloadSection.tsx +++ b/packages/web/src/pages/track-page/components/mobile/DownloadSection.tsx @@ -2,7 +2,7 @@ import { useCallback, useState } from 'react' import { useStems, useTrack } from '@audius/common/api' import { useDownloadableContentAccess } from '@audius/common/hooks' -import { Name, ModalSource, DownloadQuality, ID } from '@audius/common/models' +import { ModalSource, DownloadQuality, ID } from '@audius/common/models' import { usePremiumContentPurchaseModal, useWaitForDownloadModal, @@ -24,7 +24,6 @@ import { import { useDispatch } from 'react-redux' import { useModalState } from 'common/hooks/useModalState' -import { make, useRecord } from 'common/store/analytics/actions' import { Expandable } from 'components/expandable/Expandable' import { useIsMobile } from 'hooks/useIsMobile' import { @@ -58,7 +57,6 @@ type DownloadSectionProps = { export const DownloadSection = ({ trackId }: DownloadSectionProps) => { const dispatch = useDispatch() - const record = useRecord() const isMobile = useIsMobile() const { data: partialTrack } = useTrack(trackId, { select: (track) => { @@ -117,24 +115,6 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => { trackIds, quality: downloadQuality }) - - // Track download attempt event - if (parentTrackId) { - record( - make(Name.TRACK_DOWNLOAD_CLICKED_DOWNLOAD_ALL, { - parentTrackId, - stemTrackIds: trackIds, - device: 'web' - }) - ) - } else { - record( - make(Name.TRACK_DOWNLOAD_CLICKED_DOWNLOAD_SINGLE, { - trackId: trackIds[0], - device: 'web' - }) - ) - } } }, [ @@ -142,7 +122,6 @@ export const DownloadSection = ({ trackId }: DownloadSectionProps) => { downloadQuality, isMobile, openWaitForDownloadModal, - record, shouldDisplayDownloadFollowGated, partialTrack ] diff --git a/packages/web/src/pages/track-page/components/mobile/TrackDescription.tsx b/packages/web/src/pages/track-page/components/mobile/TrackDescription.tsx index 884db59c77e..48641363cc3 100644 --- a/packages/web/src/pages/track-page/components/mobile/TrackDescription.tsx +++ b/packages/web/src/pages/track-page/components/mobile/TrackDescription.tsx @@ -25,11 +25,7 @@ export const TrackDescription = ({ collapsedHeight={DEFAULT_LINE_HEIGHT * MAX_DESCRIPTION_LINES} > - + {description} diff --git a/packages/web/src/pages/track-page/components/mobile/TrackHeader.tsx b/packages/web/src/pages/track-page/components/mobile/TrackHeader.tsx index 74a64ffe5c5..7d6f7a1e276 100644 --- a/packages/web/src/pages/track-page/components/mobile/TrackHeader.tsx +++ b/packages/web/src/pages/track-page/components/mobile/TrackHeader.tsx @@ -258,9 +258,7 @@ const TrackHeader = ({ return ( {filteredTags.map((tag) => ( - - {tag} - + {tag} ))} ) diff --git a/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx b/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx index dd93e2df529..c9bde3f8136 100644 --- a/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx +++ b/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx @@ -8,7 +8,7 @@ import { useTrendingUnderground, usePopularGenres } from '@audius/common/api' -import { Name, TimeRange } from '@audius/common/models' +import { TimeRange } from '@audius/common/models' import { trendingPageActions, trendingPageSelectors @@ -22,7 +22,6 @@ import { } from '@audius/harmony' import { useDispatch, useSelector } from 'react-redux' -import { make, useRecord } from 'common/store/analytics/actions' import { openSignOn } from 'common/store/pages/signon/actions' import { MIN_DESKTOP_CONTENT_WIDTH_PX } from 'common/utils/layout' import { Header } from 'components/header/desktop/Header' @@ -196,7 +195,6 @@ const TrendingPageContent = ({ containerRef }: TrendingPageContentProps) => { }, [trendingGenre, replaceRouteCallback]) const { trendingTitle, pageTitle, trendingDescription } = TRENDING_MESSAGES - const record = useRecord() // ----- Tab logic ----------------------------------------------------------- const queryForRange = useCallback( @@ -267,28 +265,16 @@ const TrendingPageContent = ({ containerRef }: TrendingPageContentProps) => { (value: string) => { const tr = value as TimeRange setTrendingTimeRange(tr) - record( - make(Name.TRENDING_CHANGE_VIEW, { - timeframe: tr, - genre: trendingGenre ?? '' - }) - ) }, - [setTrendingTimeRange, record, trendingGenre] + [setTrendingTimeRange] ) const handleGenreChange = useCallback( (value: string) => { const next = value === 'all' ? null : value setTrendingGenre(next) - record( - make(Name.TRENDING_CHANGE_VIEW, { - timeframe: trendingTimeRange, - genre: next ?? '' - }) - ) }, - [setTrendingGenre, record, trendingTimeRange] + [setTrendingGenre] ) const timeRangeOptions = [ diff --git a/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.tsx b/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.tsx index 39f7e2197f3..18627a0dd39 100644 --- a/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.tsx +++ b/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.tsx @@ -15,7 +15,7 @@ import { useTrending, useTrendingUnderground } from '@audius/common/api' -import { Name, TimeRange } from '@audius/common/models' +import { TimeRange } from '@audius/common/models' import { trendingPageActions, trendingPageSelectors @@ -34,7 +34,6 @@ import { import cn from 'classnames' import { useDispatch, useSelector } from 'react-redux' -import { make, useRecord } from 'common/store/analytics/actions' import Header from 'components/header/mobile/Header' import { HeaderContext } from 'components/header/mobile/HeaderContextProvider' import { EndOfLineup } from 'components/lineup/EndOfLineup' @@ -188,8 +187,6 @@ const TrendingPageMobileContent = ({ setCenter(CenterPreset.LOGO) }, [setLeft, setCenter, setRight]) - const record = useRecord() - const setTrendingTimeRange = useCallback( (tr: TimeRange) => dispatch(trendingPageActions.setTrendingTimeRange(tr)), [dispatch] @@ -204,14 +201,8 @@ const TrendingPageMobileContent = ({ (timeRange: TimeRange) => { setTrendingTimeRange(timeRange) scrollWindowToTop() - record( - make(Name.TRENDING_CHANGE_VIEW, { - timeframe: timeRange, - genre: trendingGenre ?? '' - }) - ) }, - [setTrendingTimeRange, record, trendingGenre] + [setTrendingTimeRange] ) const queryForRange = useCallback( diff --git a/packages/web/src/pages/upload-page/components/ShareBanner.tsx b/packages/web/src/pages/upload-page/components/ShareBanner.tsx index ed12d33ab2d..0d6b284df38 100644 --- a/packages/web/src/pages/upload-page/components/ShareBanner.tsx +++ b/packages/web/src/pages/upload-page/components/ShareBanner.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react' import { useCurrentAccountUser } from '@audius/common/api' import { useUploadCompletionRoute } from '@audius/common/hooks' -import { Name, ShareSource } from '@audius/common/models' +import { ShareSource } from '@audius/common/models' import { UploadType, shareModalUIActions, @@ -12,7 +12,6 @@ import { Button, IconMessage, IconShare, Text } from '@audius/harmony' import { useDispatch } from 'react-redux' import backgroundPlaceholder from 'assets/img/1-Concert-3-1.jpg' -import { make } from 'common/store/analytics/actions' import { getCopyableLink } from 'utils/clipboardUtil' import { useSelector } from 'utils/reducer' @@ -113,7 +112,6 @@ export const ShareBanner = (props: ShareBannerProps) => { defaultUserList: 'chats' }) ) - dispatch(make(Name.CHAT_ENTRY_POINT, { source: 'upload' })) }, [accountUser, dispatch, shareLink]) return ( diff --git a/packages/web/src/pages/upload-page/pages/FinishPage.tsx b/packages/web/src/pages/upload-page/pages/FinishPage.tsx index 18fb9a88709..db7639677e6 100644 --- a/packages/web/src/pages/upload-page/pages/FinishPage.tsx +++ b/packages/web/src/pages/upload-page/pages/FinishPage.tsx @@ -3,7 +3,6 @@ import { useCallback, useMemo } from 'react' import { useCurrentAccountUser } from '@audius/common/api' import { imageBlank as placeholderArt } from '@audius/common/assets' import { useUploadCompletionRoute } from '@audius/common/hooks' -import { Name } from '@audius/common/models' import { uploadSelectors, UploadType, @@ -26,10 +25,9 @@ import { Flex, Image } from '@audius/harmony' -import { useDispatch, useSelector } from 'react-redux' +import { useSelector } from 'react-redux' import { Link } from 'react-router' -import { make } from 'common/store/analytics/actions' import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' import { Tile } from 'components/tile' @@ -140,7 +138,6 @@ export const FinishPage = (props: FinishPageProps) => { select: (user) => user?.handle }) const fullUploadPercent = useSelector(getCombinedUploadPercentage) - const dispatch = useDispatch() const uploadComplete = useMemo(() => { if ( @@ -189,10 +186,6 @@ export const FinishPage = (props: FinishPageProps) => { accountHandle: accountHandle! }) - const handleViewUpload = useCallback(() => { - dispatch(make(Name.TRACK_UPLOAD_VIEW_TRACK_PAGE, { uploadType })) - }, [dispatch, uploadType]) - const isUnlistedTrack = (formState.tracks && formState.tracks.length === 1 && @@ -265,7 +258,7 @@ export const FinishPage = (props: FinishPageProps) => { {messages.uploadMore} - + {visitButtonText}
diff --git a/packages/web/src/pages/visualizer/VisualizerProvider.tsx b/packages/web/src/pages/visualizer/VisualizerProvider.tsx index de1812d66b1..f05b2e07b3e 100644 --- a/packages/web/src/pages/visualizer/VisualizerProvider.tsx +++ b/packages/web/src/pages/visualizer/VisualizerProvider.tsx @@ -6,7 +6,6 @@ import { route } from '@audius/common/utils' import { - Name, SquareSizes, Track } from '@audius/common/models' @@ -36,10 +35,6 @@ import Toast from 'components/toast/Toast' import styles from './VisualizerProvider.module.css' -import { - make, - TrackEvent -} from 'common/store/analytics/actions' import { Image } from '@audius/harmony' import PlayingTrackInfo from 'components/play-bar/desktop/components/PlayingTrackInfo' import { @@ -295,8 +290,6 @@ const Visualizer = ({ playing, autoHideTrackDetails, onClose, - recordOpen, - recordClose, goToRoute }: VisualizerProps) => { const [toastText, setToastText] = useState('') @@ -451,7 +444,6 @@ const Visualizer = ({ useEffect(() => { if (isVisible) { ButterchurnVisualizer?.show() - recordOpen() setShowVisualizer(true) setTimeout(() => { setFadeVisualizer(true) @@ -466,7 +458,6 @@ const Visualizer = ({ const timer = setTimeout(() => { setShowVisualizer(false) ButterchurnVisualizer?.hide() - recordClose() }, 400) return () => clearTimeout(timer) } @@ -624,14 +615,6 @@ const makeMapStateToProps = () => { } const mapDispatchToProps = (dispatch: Dispatch) => ({ - recordOpen: () => { - const trackEvent: TrackEvent = make(Name.VISUALIZER_OPEN, {}) - dispatch(trackEvent) - }, - recordClose: () => { - const trackEvent: TrackEvent = make(Name.VISUALIZER_CLOSE, {}) - dispatch(trackEvent) - }, goToRoute: (route: string) => dispatch(push(route)) }) diff --git a/packages/web/src/services/analytics/amplitude.test.ts b/packages/web/src/services/analytics/amplitude.test.ts new file mode 100644 index 00000000000..ee8c50146a3 --- /dev/null +++ b/packages/web/src/services/analytics/amplitude.test.ts @@ -0,0 +1,117 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const sdk = vi.hoisted(() => { + const identify = vi.fn() + return { + init: vi.fn(() => ({ promise: Promise.resolve() })), + add: vi.fn(), + track: vi.fn(), + setUserId: vi.fn(), + identify, + getDeviceId: vi.fn((): string | undefined => 'device'), + Identify: class { + set = vi.fn() + } + } +}) + +vi.mock('@amplitude/analytics-browser', () => sdk) +vi.mock('@amplitude/plugin-session-replay-browser', () => ({ + sessionReplayPlugin: vi.fn(() => ({})) +})) +vi.mock('services/env', () => ({ + env: { AMPLITUDE_API_KEY: 'key', AMPLITUDE_PROXY: 'https://proxy' } +})) + +const loadAmplitude = async () => { + vi.resetModules() + return await import('./amplitude') +} + +describe('amplitude', () => { + beforeEach(() => { + window.localStorage.clear() + vi.restoreAllMocks() + vi.clearAllMocks() + // The test DOM reports itself as automated + vi.spyOn(window.navigator, 'webdriver', 'get').mockReturnValue(false) + }) + + it('turns off the automatic events', async () => { + const amplitude = await loadAmplitude() + await amplitude.init(false) + + expect(sdk.init).toHaveBeenCalledWith( + 'key', + expect.objectContaining({ + defaultTracking: expect.objectContaining({ + pageViews: false, + sessions: false, + formInteractions: false, + fileDownloads: false + }) + }) + ) + }) + + it('sets the client user property once per device', async () => { + await (await loadAmplitude()).init(false) + await (await loadAmplitude()).init(false) + expect(sdk.identify).toHaveBeenCalledTimes(1) + expect(sdk.track).not.toHaveBeenCalled() + }) + + it('always sends core events and samples the rest by device', async () => { + const amplitude = await loadAmplitude() + await amplitude.init(false) + const { getAnalyticsSampleRate } = await import('@audius/common/models') + + await amplitude.track('Playback: Play', { id: 1 }) + expect(sdk.track).toHaveBeenLastCalledWith('Playback: Play', { id: 1 }) + + const devices = Array.from({ length: 1000 }, (_, i) => `device-${i}`) + const kept = devices.filter( + (d) => getAnalyticsSampleRate('Play Queue: Open', d) !== null + ) + expect(kept.length).toBeGreaterThan(60) + expect(kept.length).toBeLessThan(140) + + sdk.getDeviceId.mockReturnValue(kept[0]) + await amplitude.track('Play Queue: Open', { id: 2 }) + expect(sdk.track).toHaveBeenLastCalledWith('Play Queue: Open', { + id: 2, + sampleRate: 0.1 + }) + + const dropped = devices.find((d) => !kept.includes(d)) + sdk.getDeviceId.mockReturnValue(dropped!) + sdk.track.mockClear() + await amplitude.track('Play Queue: Open') + expect(sdk.track).not.toHaveBeenCalled() + }) + + it('skips identify when traits are unchanged', async () => { + const amplitude = await loadAmplitude() + await amplitude.init(false) + sdk.identify.mockClear() + const traits = { handle: 'someone', userId: 1, name: 'Someone' } + + await amplitude.identify(traits) + await amplitude.identify({ ...traits }) + expect(sdk.identify).toHaveBeenCalledTimes(1) + expect(sdk.setUserId).toHaveBeenCalledTimes(2) + + await amplitude.identify({ ...traits, name: 'Someone Else' }) + expect(sdk.identify).toHaveBeenCalledTimes(2) + }) + + it('does nothing for bots', async () => { + vi.spyOn(window.navigator, 'webdriver', 'get').mockReturnValue(true) + const amplitude = await loadAmplitude() + await amplitude.init(false) + await amplitude.track('Playback: Play') + + expect(sdk.init).not.toHaveBeenCalled() + expect(sdk.track).not.toHaveBeenCalled() + }) +}) diff --git a/packages/web/src/services/analytics/amplitude.ts b/packages/web/src/services/analytics/amplitude.ts index b95ee38b07e..0c88da95707 100644 --- a/packages/web/src/services/analytics/amplitude.ts +++ b/packages/web/src/services/analytics/amplitude.ts @@ -1,12 +1,42 @@ -import { Name, MobileOS, IdentifyTraits } from '@audius/common/models' +import { + MobileOS, + IdentifyTraits, + getAnalyticsSampleRate +} from '@audius/common/models' import { env } from 'services/env' -import { isElectron as getIsElectron, getMobileOS } from 'utils/clientUtil' +import { + isElectron as getIsElectron, + getMobileOS, + isLikelyBot +} from 'utils/clientUtil' const AMP_API_KEY = env.AMPLITUDE_API_KEY const AMPLITUDE_PROXY = env.AMPLITUDE_PROXY -const isAmplitudeConfigured = !!AMP_API_KEY && !!AMPLITUDE_PROXY +// Crawlers load pages but never use them, so they get no analytics at all +const isAmplitudeConfigured = + !!AMP_API_KEY && !!AMPLITUDE_PROXY && !isLikelyBot() + +const CLIENT_KEY = 'amplitude:client' +const IDENTIFY_TRAITS_KEY = 'amplitude:identifiedTraits' +const WEEK_MS = 7 * 24 * 60 * 60 * 1000 + +const readStorage = (key: string) => { + try { + return window.localStorage.getItem(key) + } catch { + return null + } +} + +const writeStorage = (key: string, value: string) => { + try { + window.localStorage.setItem(key, value) + } catch { + // Storage can be unavailable (private mode), in which case we just resend + } +} // Lazy-loaded Amplitude SDK let amplitudeInstance: typeof import('@amplitude/analytics-browser') | null = @@ -66,18 +96,32 @@ export const init = async (isMobile: boolean) => { getSessionReplayPlugin() ]) - amplitude.init(AMP_API_KEY, { + // Every option left out of defaultTracking defaults to on. Amplitude + // derives sessions from session ids without the automatic events, and + // attribution stays on for utm/referrer user properties. + await amplitude.init(AMP_API_KEY, { serverUrl: AMPLITUDE_PROXY, defaultTracking: { - sessions: true + attribution: true, + pageViews: false, + sessions: false, + formInteractions: false, + fileDownloads: false } - }) + }).promise const sessionReplayTracking = sessionReplayPlugin.sessionReplayPlugin() amplitude.add(sessionReplayTracking) - const source = getSource(isMobile) - amplitude.track(Name.SESSION_START, { source }) + // Which client the user is on, as a user property. Only sent when it + // changes for this device. + const client = getSource(isMobile) ?? 'Desktop Web' + if (readStorage(CLIENT_KEY) !== client) { + const identifyObj = new amplitude.Identify() + identifyObj.set('client', client) + amplitude.identify(identifyObj) + writeStorage(CLIENT_KEY, client) + } isInitialized = true } @@ -108,9 +152,21 @@ export const identify = async ( amplitude.setUserId(traits.handle) } if (traits && Object.keys(traits).length > 0) { - const identifyObj = new amplitude.Identify() - Object.entries(traits).map(([k, v]) => identifyObj.set(k, v)) - amplitude.identify(identifyObj) + // User properties persist in Amplitude, so skip an identify that would + // set the same values again (it runs on every account load). Resend + // weekly in case an earlier one was dropped. + const serializedTraits = JSON.stringify([ + Math.floor(Date.now() / WEEK_MS), + Object.keys(traits) + .sort() + .map((k) => [k, traits[k as keyof IdentifyTraits]]) + ]) + if (readStorage(IDENTIFY_TRAITS_KEY) !== serializedTraits) { + const identifyObj = new amplitude.Identify() + Object.entries(traits).map(([k, v]) => identifyObj.set(k, v)) + amplitude.identify(identifyObj) + writeStorage(IDENTIFY_TRAITS_KEY, serializedTraits) + } } if (callback) callback() } catch (err) { @@ -132,7 +188,13 @@ export const track = async ( try { const amplitude = await getAmplitude() - amplitude.track(event, properties) + const sampleRate = getAnalyticsSampleRate(event, amplitude.getDeviceId()) + if (sampleRate !== null) { + amplitude.track( + event, + sampleRate < 1 ? { ...properties, sampleRate } : properties + ) + } if (callback) { callback() } diff --git a/packages/web/src/services/track-download.ts b/packages/web/src/services/track-download.ts index 60db2613be4..1d883aec3f7 100644 --- a/packages/web/src/services/track-download.ts +++ b/packages/web/src/services/track-download.ts @@ -1,4 +1,3 @@ -import { Name } from '@audius/common/models' import { DownloadFile, TrackDownload as TrackDownloadBase, @@ -8,8 +7,6 @@ import { tracksSocialActions, downloadsActions } from '@audius/common/store' import { dedupFilenames } from '@audius/common/utils' import { downloadZip } from 'client-zip' -import { track as trackEvent } from './analytics/amplitude' - const { downloadFinished } = tracksSocialActions const { beginDownload, setDownloadError } = downloadsActions @@ -116,13 +113,6 @@ class TrackDownload extends TrackDownloadBase { } browserDownload({ url, filename }) dispatch(downloadFinished()) - - // Track download success event - const eventName = - available.length === 1 - ? Name.TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_SINGLE - : Name.TRACK_DOWNLOAD_SUCCESSFUL_DOWNLOAD_ALL - trackEvent(eventName, { device: 'web' }) } catch (e) { if ((e as Error).name === 'AbortError') { console.info('Download aborted by the user') @@ -133,13 +123,6 @@ class TrackDownload extends TrackDownloadBase { ) ) - // Track download failure event - const eventName = - files.length === 1 - ? Name.TRACK_DOWNLOAD_FAILED_DOWNLOAD_SINGLE - : Name.TRACK_DOWNLOAD_FAILED_DOWNLOAD_ALL - trackEvent(eventName, { device: 'web' }) - throw e } } diff --git a/packages/web/src/store/application/ui/stemsUpload/sagas.ts b/packages/web/src/store/application/ui/stemsUpload/sagas.ts index 7453032dc60..da193f75c27 100644 --- a/packages/web/src/store/application/ui/stemsUpload/sagas.ts +++ b/packages/web/src/store/application/ui/stemsUpload/sagas.ts @@ -3,14 +3,11 @@ import { queryCurrentUserId, queryTrack } from '@audius/common/api' -import { Name, StemCategory } from '@audius/common/models' import { publishStems } from '@audius/common/src/api/tan-query/upload/usePublishStems' import { getContext, stemsUploadActions } from '@audius/common/store' import { Id } from '@audius/sdk' import { takeEvery, put, call } from 'typed-redux-saga' -import { make } from 'common/store/analytics/actions' - const { startStemUploads, stemUploadsSucceeded } = stemsUploadActions function* watchUploadStems() { @@ -67,18 +64,10 @@ function* watchUploadStems() { if (results) { for (let i = 0; i < results.length; i += 1) { - const { trackId, error } = results[i] + const { error } = results[i] if (error) { console.error(`Error uploading stem ${i}:`, error) - continue } - const category = uploads[i].category ?? StemCategory.OTHER - const recordEvent = make(Name.STEM_COMPLETE_UPLOAD, { - id: trackId, - parent_track_id: parentId, - category - }) - yield* put(recordEvent) } } diff --git a/packages/web/src/store/errors/sagas.ts b/packages/web/src/store/errors/sagas.ts index c2153f905d2..67220e2fe9c 100644 --- a/packages/web/src/store/errors/sagas.ts +++ b/packages/web/src/store/errors/sagas.ts @@ -1,9 +1,6 @@ -import { Name } from '@audius/common/models' import { toastActions } from '@audius/common/store' import { takeEvery, put } from 'redux-saga/effects' -import { make } from 'common/store/analytics/actions' - import * as errorActions from './actions' const { toast } = toastActions @@ -11,11 +8,6 @@ function* handleError(action: errorActions.HandleErrorAction) { console.debug(`Handling error: ${action.message}`) if (action.shouldReport) { console.error(action.name ?? 'Error', action.message, action.additionalInfo) - yield put( - make(Name.APP_ERROR, { - errorMessage: action?.message ?? 'Unknown Error' - }) - ) } // Toast error at the top of the page diff --git a/packages/web/src/store/sign-out/sagas.ts b/packages/web/src/store/sign-out/sagas.ts index cddb02c2d1a..0ca843caf9b 100644 --- a/packages/web/src/store/sign-out/sagas.ts +++ b/packages/web/src/store/sign-out/sagas.ts @@ -1,4 +1,3 @@ -import { Name } from '@audius/common/models' import { TRENDING_PAGE } from '@audius/common/src/utils/route' import { accountActions, @@ -9,7 +8,6 @@ import { disconnect } from '@wagmi/core' import { takeLatest, put, call } from 'redux-saga/effects' import { getLoadedAppKit } from 'app/appkit' -import { make } from 'common/store/analytics/actions' import { signOut } from 'store/sign-out/signOut' import { push } from 'utils/navigation' const { resetAccount, unsubscribeBrowserPushNotifications } = accountActions @@ -35,11 +33,7 @@ function* watchSignOut() { queryClient.resetQueries() queryClient.clear() // ORDER MATTERS HERE - clear() must be called after resetQueries() yield put(unsubscribeBrowserPushNotifications()) - yield put( - make(Name.SETTINGS_LOG_OUT, { - callback: () => signOut(localStorage, authService) - }) - ) + signOut(localStorage, authService) if (!action?.payload?.fromOAuth) { yield put(push(TRENDING_PAGE)) } diff --git a/packages/web/src/utils/clientUtil.ts b/packages/web/src/utils/clientUtil.ts index a70dc5f8d49..795fe628c4b 100644 --- a/packages/web/src/utils/clientUtil.ts +++ b/packages/web/src/utils/clientUtil.ts @@ -55,6 +55,20 @@ export const isMobile = () => { ) } +const BOT_USER_AGENT_REGEX = + /bot|crawl|spider|slurp|headless|lighthouse|pagespeed|prerender|phantomjs|puppeteer|playwright|selenium|facebookexternalhit|embedly|bingpreview|inspectiontool/i + +/** + * Crawlers and automated browsers. Automation drivers set navigator.webdriver. + */ +export const isLikelyBot = () => { + if (typeof navigator === 'undefined') return false + if (navigator.webdriver === true) return true + const userAgent = navigator.userAgent ?? '' + // Cubot is a phone brand, not a crawler + return BOT_USER_AGENT_REGEX.test(userAgent) && !/cubot/i.test(userAgent) +} + export const isElectron = () => { if (typeof navigator === 'undefined') { return false