From 55740d550ffa23981faf0d1361e231887d2bcf22 Mon Sep 17 00:00:00 2001 From: Dylan Audius Date: Wed, 23 Sep 2026 17:24:27 -0700 Subject: [PATCH 1/2] chore(analytics): cut duplicate and automatic Amplitude events - Web: turn off the SDK's automatic session_start/session_end, page view, form and file download events. Everything left out of defaultTracking defaults to on, and session_start and [Amplitude] Page Viewed are deleted in the project, so they were sent and counted by the proxy but dropped. - Web: send Session Start once per Amplitude session instead of every page load. - Web and mobile: skip identify when the traits have not changed (resent weekly). - Web and embed: no analytics for crawlers and automated browsers. - Embed: drop the per-load Session Start; Embed: Open Player already fires on every load and now carries source. - Mobile: only report Buffering Time for buffers of at least 1s. - Explore: Section View once per section per app session. Co-Authored-By: Claude Opus 5.5 --- packages/embed/src/analytics/analytics.js | 37 ++++++-- packages/embed/src/components/app.jsx | 10 +- .../src/components/audio/AudioPlayer.tsx | 11 ++- .../hooks/useExploreSectionTracking.ts | 6 +- packages/mobile/src/services/analytics.ts | 22 +++++ .../desktop/useExploreSectionTracking.ts | 6 +- .../src/services/analytics/amplitude.test.ts | 94 +++++++++++++++++++ .../web/src/services/analytics/amplitude.ts | 71 ++++++++++++-- packages/web/src/utils/clientUtil.ts | 14 +++ 9 files changed, 239 insertions(+), 32 deletions(-) create mode 100644 packages/web/src/services/analytics/amplitude.test.ts diff --git a/packages/embed/src/analytics/analytics.js b/packages/embed/src/analytics/analytics.js index 2c0d9facdd4..74b3b05646c 100644 --- a/packages/embed/src/analytics/analytics.js +++ b/packages/embed/src/analytics/analytics.js @@ -8,16 +8,26 @@ 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 + +// No separate Session Start: every load already sends Embed: Open Player +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 } } catch (err) { logError(err) @@ -33,14 +43,21 @@ 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 }) + track(OPEN, { + id: `${id}`, + handle, + title, + path, + source: SOURCE, + referrer: document.referrer + }) } export const recordError = () => { diff --git a/packages/embed/src/components/app.jsx b/packages/embed/src/components/app.jsx index d089c5cd0a0..f2ad5c91bc5 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, recordOpen, recordError } from '../analytics/analytics' import { ID_ROUTE, HASH_ID_ROUTE, PERMALINK_ROUTE } from '../routes' import { getCollection, @@ -161,9 +157,9 @@ const App = (props) => { } }, [didError]) - // Record this session with analytics + // Set up analytics useEffect(() => { - initTrackSessionStart() + initAnalytics() }, []) // TODO: pull these out into separate functions? diff --git a/packages/mobile/src/components/audio/AudioPlayer.tsx b/packages/mobile/src/components/audio/AudioPlayer.tsx index 4452f26a251..6df23be6956 100644 --- a/packages/mobile/src/components/audio/AudioPlayer.tsx +++ b/packages/mobile/src/components/audio/AudioPlayer.tsx @@ -108,6 +108,8 @@ const longFormContentCapabilities = [ Capability.JumpBackward ] +const MIN_REPORTED_BUFFER_MS = 1000 + const updatePlayerOptions = async (isLongForm = false) => { const coreCapabilities = isLongForm ? longFormContentCapabilities @@ -517,9 +519,12 @@ const usePlaybackEvents = ({ dispatch(playbackActions.setBuffering({ buffering: bufferingDuringPlay })) if (!bufferingDuringPlay && bufferStartTime) { const bufferDuration = Math.ceil(performance.now() - bufferStartTime) - analyticsTrack( - make({ eventName: Name.BUFFERING_TIME, duration: bufferDuration }) - ) + // Short buffers are routine and were over half of these events + if (bufferDuration >= MIN_REPORTED_BUFFER_MS) { + analyticsTrack( + make({ eventName: Name.BUFFERING_TIME, duration: bufferDuration }) + ) + } setBufferStartTime(undefined) } } diff --git a/packages/mobile/src/screens/explore-screen/hooks/useExploreSectionTracking.ts b/packages/mobile/src/screens/explore-screen/hooks/useExploreSectionTracking.ts index 14554fcea17..8e074932c98 100644 --- a/packages/mobile/src/screens/explore-screen/hooks/useExploreSectionTracking.ts +++ b/packages/mobile/src/screens/explore-screen/hooks/useExploreSectionTracking.ts @@ -6,6 +6,9 @@ import { Name } from '@audius/common/models' import { useDeferredElement } from 'app/hooks/useDeferredElement' +// Sections already reported during this app session +const trackedSections = new Set() + /** * Hook to track explore section impressions when they come into view on mobile */ @@ -14,7 +17,8 @@ export const useExploreSectionTracking = (sectionName: ExploreSectionName) => { const { trackEvent } = useAnalytics() useEffect(() => { - if (inView) { + if (inView && !trackedSections.has(sectionName)) { + trackedSections.add(sectionName) trackEvent({ eventName: Name.EXPLORE_SECTION_VIEW, section: sectionName, diff --git a/packages/mobile/src/services/analytics.ts b/packages/mobile/src/services/analytics.ts index 0556775c231..df0f6bd6364 100644 --- a/packages/mobile/src/services/analytics.ts +++ b/packages/mobile/src/services/analytics.ts @@ -7,6 +7,7 @@ import { Types as AmplitudeTypes } from '@amplitude/analytics-react-native' import type { IdentifyTraits } from '@audius/common/models' +import AsyncStorage from '@react-native-async-storage/async-storage' import VersionNumber from 'react-native-version-number' import { env } from 'app/services/env' @@ -23,6 +24,9 @@ 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 WEEK_MS = 7 * 24 * 60 * 60 * 1000 + export const init = async () => { try { if (AmplitudeWriteKey && AmplitudeProxy) { @@ -84,11 +88,29 @@ 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 diff --git a/packages/web/src/pages/search-explore-page/components/desktop/useExploreSectionTracking.ts b/packages/web/src/pages/search-explore-page/components/desktop/useExploreSectionTracking.ts index b5237ea450b..664d3180eb6 100644 --- a/packages/web/src/pages/search-explore-page/components/desktop/useExploreSectionTracking.ts +++ b/packages/web/src/pages/search-explore-page/components/desktop/useExploreSectionTracking.ts @@ -7,6 +7,9 @@ import { useIsMobile } from 'hooks/useIsMobile' import { useDeferredElement } from './useDeferredElement' +// Sections already reported during this app session +const trackedSections = new Set() + /** * Hook to track explore section impressions when they come into view */ @@ -16,7 +19,8 @@ export const useExploreSectionTracking = (sectionName: ExploreSectionName) => { const isMobile = useIsMobile() useEffect(() => { - if (inView) { + if (inView && !trackedSections.has(sectionName)) { + trackedSections.add(sectionName) trackEvent({ eventName: Name.EXPLORE_SECTION_VIEW, section: sectionName, 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..f35cfbf2273 --- /dev/null +++ b/packages/web/src/services/analytics/amplitude.test.ts @@ -0,0 +1,94 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const sdk = vi.hoisted(() => { + let sessionId = 1 + const identify = vi.fn() + return { + init: vi.fn(() => ({ promise: Promise.resolve() })), + add: vi.fn(), + track: vi.fn(), + setUserId: vi.fn(), + identify, + getSessionId: vi.fn(() => sessionId), + setSessionId: (id: number) => { + sessionId = id + }, + 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() + sdk.setSessionId(1) + // 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('tracks Session Start once per Amplitude session', async () => { + await (await loadAmplitude()).init(false) + await (await loadAmplitude()).init(false) + expect(sdk.track).toHaveBeenCalledTimes(1) + + sdk.setSessionId(2) + await (await loadAmplitude()).init(false) + expect(sdk.track).toHaveBeenCalledTimes(2) + }) + + it('skips identify when traits are unchanged', async () => { + const amplitude = await loadAmplitude() + const traits = { handle: 'someone', userId: 1, isVerified: false } + + await amplitude.identify(traits) + await amplitude.identify({ ...traits }) + expect(sdk.identify).toHaveBeenCalledTimes(1) + expect(sdk.setUserId).toHaveBeenCalledTimes(2) + + await amplitude.identify({ ...traits, isVerified: true }) + 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..a5401159396 100644 --- a/packages/web/src/services/analytics/amplitude.ts +++ b/packages/web/src/services/analytics/amplitude.ts @@ -1,12 +1,38 @@ import { Name, MobileOS, IdentifyTraits } 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 SESSION_START_KEY = 'amplitude:sessionStartSessionId' +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 +92,31 @@ export const init = async (isMobile: boolean) => { getSessionReplayPlugin() ]) - amplitude.init(AMP_API_KEY, { + // Every option left out of defaultTracking defaults to on. The + // automatic session_start and [Amplitude] Page Viewed events are + // deleted in the Amplitude project, so they were only ever sent, + // counted by the proxy, and dropped. Session Start below covers + // sessions, 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 }) + // Once per Amplitude session rather than once per page load + const sessionId = String(amplitude.getSessionId() ?? '') + if (!sessionId || readStorage(SESSION_START_KEY) !== sessionId) { + amplitude.track(Name.SESSION_START, { source: getSource(isMobile) }) + writeStorage(SESSION_START_KEY, sessionId) + } isInitialized = true } @@ -108,9 +147,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) { 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 From 5321bb9f781d871c923e75825544814ce38e6776 Mon Sep 17 00:00:00 2001 From: Dylan Audius Date: Thu, 24 Sep 2026 12:09:09 -0700 Subject: [PATCH 2/2] chore(analytics): drop unused events and sample the rest - Remove Session Start everywhere. The platform it carried is now a `client` user property, set when it changes for a device (web, mobile, embed). - Remove every event that is not core and is not used by an Amplitude chart or dashboard viewed or edited in the last 12 months, with its call sites, enum entry and type. Embed: Open Player and Embed: Player Error go too. - Send non-core events from a fixed 10% of devices, picked by a hash of the Amplitude device id, with a `sampleRate` property. Core events are an explicit allowlist in @audius/common (CORE_ANALYTICS_EVENTS) and are always sent. - Drop the analytics-only `source` props on SearchTag, ExternalLink and UserGeneratedText. Chat Entry Point is still fired from ShareModal and ShareDrawer, which are being changed in a separate PR; the metrics proxy drops it. Co-Authored-By: Claude Opus 5.5 --- .../collection/useDeleteCollection.ts | 17 +- .../api/tan-query/search/useSearchResults.ts | 24 +- .../api/tan-query/tracks/useDeleteTrack.ts | 30 +- .../api/tan-query/tracks/useFavoriteTrack.ts | 39 - .../api/tan-query/tracks/useUpdateTrack.ts | 126 +- .../api/tan-query/upload/usePublishStems.ts | 19 +- .../src/api/tan-query/upload/useUpload.ts | 25 +- .../users/account/useReorderLibrary.ts | 8 - .../users/account/useResendRecoveryEmail.ts | 10 +- .../src/context/comments/commentsContext.tsx | 29 +- .../src/context/comments/commentsHooks.ts | 104 +- .../src/hooks/chats/useSetInboxPermissions.ts | 22 +- .../common/src/hooks/useAccountSwitcher.ts | 13 +- packages/common/src/models/Analytics.ts | 1361 +---------------- .../common/src/models/AnalyticsSampling.ts | 199 +++ packages/common/src/models/index.ts | 1 + .../src/services/audius-backend/solana.ts | 17 - .../common/src/store/gated-content/sagas.ts | 13 +- packages/common/src/store/pages/chat/sagas.ts | 65 - packages/common/src/store/ui/modals/sagas.ts | 35 +- packages/embed/src/analytics/analytics.js | 33 +- packages/embed/src/components/app.jsx | 21 +- packages/mobile/src/app/ErrorBoundary.tsx | 8 - .../src/components/audio/AudioPlayer.tsx | 25 +- .../components/comments/CommentActionBar.tsx | 17 +- .../src/components/comments/CommentBlock.tsx | 23 +- .../comments/CommentDrawerContext.tsx | 38 +- .../comments/CommentDrawerHeader.tsx | 8 - .../src/components/comments/CommentForm.tsx | 52 +- .../comments/CommentOverflowMenu.tsx | 17 +- .../src/components/comments/CommentText.tsx | 51 +- .../src/components/comments/CommentThread.tsx | 20 +- .../comments/RecentUserCommentsDrawer.tsx | 18 +- packages/mobile/src/components/core/Link.tsx | 19 +- .../DownloadTrackArchiveDrawer.tsx | 22 +- .../HostRemixContestDrawer.tsx | 29 +- .../lineup-tile/TrackTileMetrics.tsx | 11 +- .../rate-cta-drawer/RateCtaDrawer.tsx | 4 - .../left-nav-drawer/MessagesNavItem.tsx | 9 +- .../src/screens/chat-screen/ChatBlastCTA.tsx | 3 - .../chat-screen/ChatMessagePlaylist.tsx | 7 +- .../screens/chat-screen/ChatMessageTrack.tsx | 7 +- .../src/screens/chat-screen/ChatScreen.tsx | 36 +- .../CollectionScreenDetailsTile.tsx | 39 +- .../screens/contest-screen/ContestScreen.tsx | 34 +- .../tabs/ContestSubmissionsTab.tsx | 30 +- .../edit-track-screen/EditTrackForm.tsx | 40 +- .../components/FileReplaceContainer.tsx | 15 +- .../hooks/useExploreSectionTracking.ts | 19 - .../screens/profile-screen/MessageButton.tsx | 3 - .../ProfileHeader/ProfileInfoTiles.tsx | 10 +- .../ProfileHeader/SocialLink.tsx | 32 +- .../rewards-screen/ChallengeRewardsTile.tsx | 21 +- .../search-results/AllResults.tsx | 22 +- .../search-results/PlaylistResults.tsx | 15 +- .../search-results/ProfileResults.tsx | 15 +- .../search-results/TrackResults.tsx | 15 +- .../settings-screen/AppearanceSettingsRow.tsx | 16 +- .../screens/track-screen/DownloadSection.tsx | 21 - .../track-screen/TrackScreenDetailsTile.tsx | 7 - .../screens/UploadCompleteScreen.tsx | 4 +- packages/mobile/src/services/analytics.ts | 35 +- .../mobile/src/services/track-download.ts | 34 - .../sagas/migrateOfflineDataPathSaga.ts | 19 - .../workers/downloadCollectionWorker.ts | 23 - .../workers/downloadTrackWorker.ts | 23 - .../sagas/requestDownloadAllFavoritesSaga.ts | 3 - .../sagas/requestDownloadCollectionSaga.ts | 10 - ...requestRemoveAllDownloadedFavoritesSaga.ts | 3 - .../requestRemoveDownloadedCollectionSaga.ts | 10 - .../sagas/watchSaveCollectionSaga.ts | 10 - .../sagas/watchSaveTrackSaga.ts | 9 - packages/mobile/src/store/rate-cta/sagas.ts | 3 - packages/mobile/src/store/sign-out/sagas.ts | 3 - .../sagas/connectNewWalletSaga.ts | 48 +- .../wallet-connect/sagas/signMessageSaga.ts | 25 +- packages/mobile/src/types/analytics.ts | 99 +- .../collections/addTrackToPlaylistSaga.ts | 16 +- .../store/cache/collections/commonSagas.ts | 5 - .../cache/collections/createAlbumSaga.ts | 30 +- .../cache/collections/createPlaylistSaga.ts | 30 +- .../common/store/pages/audio-rewards/sagas.ts | 47 +- .../store/pages/deactivate-account/sagas.ts | 6 - .../src/common/store/pages/signon/sagas.ts | 13 +- .../pages/token-dashboard/checkIsNewWallet.ts | 12 +- .../src/common/store/social/tracks/sagas.ts | 71 - .../src/common/store/upload/sagaHelpers.ts | 38 +- .../components/app-cta-modal/AppCTAModal.tsx | 9 +- .../ArtistRecommendations.tsx | 21 +- .../banner/FanClubsLaunchBanner.tsx | 7 +- .../banner/TermsOfServiceUpdateBanner.tsx | 8 +- .../banner/TradingVolumeLaunchBanner.tsx | 8 +- .../components/banner/YakCoinLaunchBanner.tsx | 7 +- .../collection/desktop/CollectionHeader.tsx | 6 +- .../desktop/EditableCollectionDescription.tsx | 6 +- .../edit-mode/PlaylistEditModeContext.tsx | 16 +- .../collection/mobile/CollectionHeader.tsx | 5 +- .../components/comments/CommentActionBar.tsx | 44 +- .../src/components/comments/CommentForm.tsx | 50 +- .../src/components/comments/CommentHeader.tsx | 19 +- .../src/components/comments/CommentText.tsx | 49 +- .../src/components/comments/CommentThread.tsx | 16 +- .../DownloadTrackArchiveModal.tsx | 23 +- .../edit-folder-modal/EditFolderModal.tsx | 14 +- .../components/edit-track/EditTrackForm.tsx | 43 +- .../src/components/embed-modal/EmbedModal.tsx | 5 - .../HostRemixContestModal.tsx | 29 +- .../web/src/components/link/ExternalLink.tsx | 25 +- .../src/components/link/ExternalTextLink.tsx | 9 +- .../components/nav/desktop/LeftNavLink.tsx | 15 +- .../PlaylistLibrary/CollectionNavItem.tsx | 6 +- .../PlaylistLibrary/PlaylistFolderNavItem.tsx | 22 +- .../src/components/search-bar/SearchTag.tsx | 24 +- .../src/components/track/DownloadSection.tsx | 22 - .../src/components/track/GiantTrackTile.tsx | 4 +- .../web/src/components/track/TrackStats.tsx | 10 +- .../src/components/track/TrackTileMetrics.tsx | 15 +- .../track/desktop/CollectionTile.tsx | 18 - .../track/mobile/CollectionTile.tsx | 18 - .../user-generated-text/UserGeneratedText.tsx | 13 +- .../hooks/useConnectAndAssociateWallets.ts | 43 +- .../src/hooks/useConnectExternalWallets.ts | 31 +- packages/web/src/pages/chat-page/ChatPage.tsx | 54 +- .../chat-page/components/ChatBlastCTA.tsx | 3 - .../components/ChatMessagePlaylist.tsx | 9 +- .../chat-page/components/ChatMessageTrack.tsx | 5 +- .../collection-page/useCollectionPage.ts | 23 - .../components/desktop/CommentHistoryPage.tsx | 23 +- .../components/desktop/ContestPage.tsx | 43 +- .../DeactivateAccountPage.tsx | 7 +- .../desktop/EditCollectionPage.tsx | 23 +- .../mobile/EditCollectionPage.tsx | 10 +- .../HostRemixContestPage.tsx | 28 +- .../components/mobile/NewCollectionButton.tsx | 13 +- .../src/pages/not-found-page/NotFoundPage.tsx | 6 - .../pick-winners-page/PickWinnersPage.tsx | 13 +- .../AdvancedWalletDetails.tsx | 32 +- .../PrivateKeyExporterModal.tsx | 20 +- .../PrivateKeyExporterPage.tsx | 23 +- .../profile-page/components/SocialLink.tsx | 2 +- .../components/desktop/ProfileBio.tsx | 100 +- .../components/desktop/ProfileTopTags.tsx | 4 +- .../components/desktop/RecentComments.tsx | 16 - .../components/mobile/ProfileHeader.tsx | 41 - .../components/mobile/SocialLink.tsx | 2 +- .../src/pages/profile-page/useProfilePage.ts | 36 +- .../components/desktop/RemixesPage.tsx | 17 +- .../ChallengeRewards/RewardPanel.tsx | 5 - .../components/desktop/CollectionArtCard.tsx | 35 +- .../components/desktop/TrackArtCard.tsx | 25 +- .../components/desktop/UserArtCard.tsx | 26 +- .../desktop/useExploreSectionTracking.ts | 27 +- .../search-results/AlbumResults.tsx | 16 +- .../search-page/search-results/AllResults.tsx | 13 +- .../search-results/PlaylistResults.tsx | 16 +- .../search-results/ProfileResults.tsx | 15 +- .../search-results/TrackResults.tsx | 13 +- .../RemoveAppConfirmationPage.tsx | 24 +- .../DeveloperApps/CreateNewAppPage.tsx | 29 +- .../DeleteAppConfirmationPage.tsx | 24 +- .../desktop/DeveloperApps/EditAppPage.tsx | 34 +- .../AccountListItem/ManagedUserListItem.tsx | 22 +- .../AccountListItem/ManagerListItem.tsx | 15 +- .../RemoveManagerConfirmationContent.tsx | 13 +- .../components/desktop/SettingsPage.tsx | 39 +- .../components/mobile/AccountSettingsPage.tsx | 7 +- .../components/mobile/SettingsPage.tsx | 10 - .../components/mobile/SignOutModal.tsx | 12 +- .../src/pages/settings-page/store/sagas.ts | 25 - .../components/mobile/DownloadSection.tsx | 23 +- .../components/mobile/TrackDescription.tsx | 6 +- .../components/mobile/TrackHeader.tsx | 4 +- .../desktop/TrendingPageContent.tsx | 20 +- .../components/mobile/TrendingPageContent.tsx | 13 +- .../upload-page/components/ShareBanner.tsx | 4 +- .../pages/upload-page/pages/FinishPage.tsx | 11 +- .../pages/visualizer/VisualizerProvider.tsx | 17 - .../src/services/analytics/amplitude.test.ts | 49 +- .../web/src/services/analytics/amplitude.ts | 37 +- packages/web/src/services/track-download.ts | 17 - .../store/application/ui/stemsUpload/sagas.ts | 13 +- packages/web/src/store/errors/sagas.ts | 8 - packages/web/src/store/sign-out/sagas.ts | 8 +- 183 files changed, 592 insertions(+), 4914 deletions(-) create mode 100644 packages/common/src/models/AnalyticsSampling.ts 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 74b3b05646c..bad2a7cb9d6 100644 --- a/packages/embed/src/analytics/analytics.js +++ b/packages/embed/src/analytics/analytics.js @@ -22,12 +22,25 @@ const isLikelyBot = () => { let isEnabled = false -// No separate Session Start: every load already sends Embed: Open Player +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 && !isLikelyBot()) { amp.init(AMP_API_KEY, undefined, { apiEndpoint: AMP_PROXY }) isEnabled = true + identifyClient() } } catch (err) { logError(err) @@ -36,8 +49,6 @@ export const initAnalytics = () => { 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' @@ -48,22 +59,6 @@ const track = (event, properties) => { } } -/** id param is the numeric id */ -export const recordOpen = (id, title, handle, path) => { - track(OPEN, { - id: `${id}`, - handle, - title, - path, - source: SOURCE, - 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 f2ad5c91bc5..c6b54f853e8 100644 --- a/packages/embed/src/components/app.jsx +++ b/packages/embed/src/components/app.jsx @@ -7,7 +7,7 @@ import { CSSTransition } from 'react-transition-group' import '@audius/harmony/dist/harmony.css' -import { initAnalytics, recordOpen, recordError } from '../analytics/analytics' +import { initAnalytics } from '../analytics/analytics' import { ID_ROUTE, HASH_ID_ROUTE, PERMALINK_ROUTE } from '../routes' import { getCollection, @@ -19,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' @@ -151,12 +150,6 @@ const App = (props) => { const [dominantColor, setDominantColor] = useState(null) const playerContainerRef = useRef(null) - useEffect(() => { - if (didError) { - recordError() - } - }, [didError]) - // Set up analytics useEffect(() => { initAnalytics() @@ -203,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 @@ -250,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 6df23be6956..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, @@ -108,8 +107,6 @@ const longFormContentCapabilities = [ Capability.JumpBackward ] -const MIN_REPORTED_BUFFER_MS = 1000 - const updatePlayerOptions = async (isLongForm = false) => { const coreCapabilities = isLongForm ? longFormContentCapabilities @@ -506,7 +503,6 @@ const usePlaybackEvents = ({ getUserTrackPositions(state, { userId: currentUserId }) ) - const [bufferStartTime, setBufferStartTime] = useState() const { bufferingDuringPlay } = useIsPlaying() const previousBufferingState = usePrevious(bufferingDuringPlay) @@ -517,24 +513,8 @@ const usePlaybackEvents = ({ bufferingDuringPlay !== previousBufferingState ) { dispatch(playbackActions.setBuffering({ buffering: bufferingDuringPlay })) - if (!bufferingDuringPlay && bufferStartTime) { - const bufferDuration = Math.ceil(performance.now() - bufferStartTime) - // Short buffers are routine and were over half of these events - if (bufferDuration >= MIN_REPORTED_BUFFER_MS) { - analyticsTrack( - make({ eventName: Name.BUFFERING_TIME, duration: bufferDuration }) - ) - } - setBufferStartTime(undefined) - } } - }, [ - bufferStartTime, - bufferingDuringPlay, - dispatch, - previousBufferingState, - track - ]) + }, [bufferingDuringPlay, dispatch, previousBufferingState, track]) const seekToRef = useRef(null) @@ -631,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 ( () - /** * Hook to track explore section impressions when they come into view on mobile */ export const useExploreSectionTracking = (sectionName: ExploreSectionName) => { const { inView, InViewWrapper } = useDeferredElement() - const { trackEvent } = useAnalytics() - - useEffect(() => { - if (inView && !trackedSections.has(sectionName)) { - trackedSections.add(sectionName) - 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 df0f6bd6364..61b74627b01 100644 --- a/packages/mobile/src/services/analytics.ts +++ b/packages/mobile/src/services/analytics.ts @@ -4,17 +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 @@ -25,6 +31,7 @@ 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 () => { @@ -43,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( @@ -55,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) => { @@ -117,9 +143,16 @@ export const identify = async (traits: IdentifyTraits) => { 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 index f35cfbf2273..ee8c50146a3 100644 --- a/packages/web/src/services/analytics/amplitude.test.ts +++ b/packages/web/src/services/analytics/amplitude.test.ts @@ -1,7 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' const sdk = vi.hoisted(() => { - let sessionId = 1 const identify = vi.fn() return { init: vi.fn(() => ({ promise: Promise.resolve() })), @@ -9,10 +8,7 @@ const sdk = vi.hoisted(() => { track: vi.fn(), setUserId: vi.fn(), identify, - getSessionId: vi.fn(() => sessionId), - setSessionId: (id: number) => { - sessionId = id - }, + getDeviceId: vi.fn((): string | undefined => 'device'), Identify: class { set = vi.fn() } @@ -37,7 +33,6 @@ describe('amplitude', () => { window.localStorage.clear() vi.restoreAllMocks() vi.clearAllMocks() - sdk.setSessionId(1) // The test DOM reports itself as automated vi.spyOn(window.navigator, 'webdriver', 'get').mockReturnValue(false) }) @@ -59,26 +54,54 @@ describe('amplitude', () => { ) }) - it('tracks Session Start once per Amplitude session', async () => { + it('sets the client user property once per device', async () => { await (await loadAmplitude()).init(false) await (await loadAmplitude()).init(false) - expect(sdk.track).toHaveBeenCalledTimes(1) + expect(sdk.identify).toHaveBeenCalledTimes(1) + expect(sdk.track).not.toHaveBeenCalled() + }) - sdk.setSessionId(2) - await (await loadAmplitude()).init(false) - expect(sdk.track).toHaveBeenCalledTimes(2) + 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() - const traits = { handle: 'someone', userId: 1, isVerified: false } + 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, isVerified: true }) + await amplitude.identify({ ...traits, name: 'Someone Else' }) expect(sdk.identify).toHaveBeenCalledTimes(2) }) diff --git a/packages/web/src/services/analytics/amplitude.ts b/packages/web/src/services/analytics/amplitude.ts index a5401159396..0c88da95707 100644 --- a/packages/web/src/services/analytics/amplitude.ts +++ b/packages/web/src/services/analytics/amplitude.ts @@ -1,4 +1,8 @@ -import { Name, MobileOS, IdentifyTraits } from '@audius/common/models' +import { + MobileOS, + IdentifyTraits, + getAnalyticsSampleRate +} from '@audius/common/models' import { env } from 'services/env' import { @@ -14,7 +18,7 @@ const AMPLITUDE_PROXY = env.AMPLITUDE_PROXY const isAmplitudeConfigured = !!AMP_API_KEY && !!AMPLITUDE_PROXY && !isLikelyBot() -const SESSION_START_KEY = 'amplitude:sessionStartSessionId' +const CLIENT_KEY = 'amplitude:client' const IDENTIFY_TRAITS_KEY = 'amplitude:identifiedTraits' const WEEK_MS = 7 * 24 * 60 * 60 * 1000 @@ -92,11 +96,9 @@ export const init = async (isMobile: boolean) => { getSessionReplayPlugin() ]) - // Every option left out of defaultTracking defaults to on. The - // automatic session_start and [Amplitude] Page Viewed events are - // deleted in the Amplitude project, so they were only ever sent, - // counted by the proxy, and dropped. Session Start below covers - // sessions, and attribution stays on for utm/referrer user properties. + // 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: { @@ -111,11 +113,14 @@ export const init = async (isMobile: boolean) => { const sessionReplayTracking = sessionReplayPlugin.sessionReplayPlugin() amplitude.add(sessionReplayTracking) - // Once per Amplitude session rather than once per page load - const sessionId = String(amplitude.getSessionId() ?? '') - if (!sessionId || readStorage(SESSION_START_KEY) !== sessionId) { - amplitude.track(Name.SESSION_START, { source: getSource(isMobile) }) - writeStorage(SESSION_START_KEY, sessionId) + // 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 @@ -183,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)) }