From 4e9c9d8f7e3762533c00a0b3ff019d5d4cd6ab01 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 24 Aug 2026 13:29:13 -0700 Subject: [PATCH 1/4] feat(client): surface Discover Weekly on Explore (web) Wires GET /users/:id/discover-weekly into the Explore page as a collection card, so the mix reads like a playlist even though it isn't one. sdk.users.getDiscoverWeekly is hand-written pending the next SDK regen, same as getSuggestedFollows in #14562, since npm run gen pulls the spec from a running node. The artwork is a checked-in asset rather than entity cover art: the mix has no playlist_id to hang an image on. Same reason there's no permalink -- clicking plays the mix in place (all 30 queued, starting at the top) rather than navigating. Rendered without a Carousel wrapper: there's exactly one card, so the scroll affordance is dead weight and a section heading would repeat the card's own title. Web only for now -- the native mobile app has a separate Explore screen. Depends on AudiusProject/api#1025 (merged). Co-Authored-By: Claude Opus 5 --- packages/common/src/api/index.ts | 1 + .../tan-query/lineups/useDiscoverWeekly.ts | 82 ++++++++++++++++++ .../common/src/api/tan-query/queryKeys.ts | 1 + packages/common/src/messages/explore.ts | 4 + packages/common/src/models/Analytics.ts | 1 + packages/sdk/src/sdk/api/users/UsersApi.ts | 69 ++++++++++++++- packages/sdk/src/sdk/api/users/types.ts | 17 ++++ .../web/src/assets/img/discoverWeekly.jpg | Bin 0 -> 76646 bytes .../components/desktop/DiscoverWeeklyCard.tsx | 64 ++++++++++++++ .../desktop/DiscoverWeeklySection.tsx | 36 ++++++++ .../components/desktop/SearchExplorePage.tsx | 6 ++ .../components/mobile/SearchExplorePage.tsx | 4 + 12 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 packages/common/src/api/tan-query/lineups/useDiscoverWeekly.ts create mode 100644 packages/web/src/assets/img/discoverWeekly.jpg create mode 100644 packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklyCard.tsx create mode 100644 packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklySection.tsx diff --git a/packages/common/src/api/index.ts b/packages/common/src/api/index.ts index 431c75327b8..ce42e24032f 100644 --- a/packages/common/src/api/index.ts +++ b/packages/common/src/api/index.ts @@ -48,6 +48,7 @@ export * from './tan-query/lineups/useProfileReposts' export * from './tan-query/lineups/useProfileTracks' export * from './tan-query/lineups/useTrending' export * from './tan-query/lineups/useTrendingUnderground' +export * from './tan-query/lineups/useDiscoverWeekly' export * from './tan-query/lineups/useTrendingWinners' export * from './tan-query/lineups/useTrackPageLineup' diff --git a/packages/common/src/api/tan-query/lineups/useDiscoverWeekly.ts b/packages/common/src/api/tan-query/lineups/useDiscoverWeekly.ts new file mode 100644 index 00000000000..a7ce2b84d7b --- /dev/null +++ b/packages/common/src/api/tan-query/lineups/useDiscoverWeekly.ts @@ -0,0 +1,82 @@ +import { Id, OptionalId, EntityType } from '@audius/sdk' +import { useQuery, useQueryClient } from '@tanstack/react-query' + +import { transformAndCleanList, userTrackMetadataFromSDK } from '~/adapters' +import { useQueryContext } from '~/api/tan-query/utils' +import { ID } from '~/models/Identifiers' + +import { QUERY_KEYS } from '../queryKeys' +import { QueryKey, QueryOptions, LineupData } from '../types' +import { useCurrentUserId } from '../users/account/useCurrentUserId' +import { primeTrackData } from '../utils/primeTrackData' + +const DEFAULT_LIMIT = 30 + +export type UseDiscoverWeeklyArgs = { + limit?: number +} + +export const getDiscoverWeeklyQueryKey = ({ + userId, + limit = DEFAULT_LIMIT +}: UseDiscoverWeeklyArgs & { userId: ID | null | undefined }) => + [QUERY_KEYS.discoverWeekly, userId, { limit }] as unknown as QueryKey< + LineupData[] + > + +/** + * The current user's Discover Weekly mix: tracks they haven't heard, weighted + * toward artists they don't already follow. + * + * Deliberately a plain `useQuery` rather than an infinite one — the mix is a + * fixed-size artifact, not a lineup you scroll. There is no page 2. + * + * The server holds the mix constant for the ISO week, so the client cache can + * be long-lived; the staleness that matters is the week boundary, not minutes. + * Refetch-on-mount is left off for the same reason. + */ +export const useDiscoverWeekly = ( + { limit = DEFAULT_LIMIT }: UseDiscoverWeeklyArgs = {}, + options?: QueryOptions +) => { + const { audiusSdk } = useQueryContext() + const { data: currentUserId } = useCurrentUserId() + const queryClient = useQueryClient() + + const query = useQuery({ + queryKey: getDiscoverWeeklyQueryKey({ userId: currentUserId, limit }), + queryFn: async () => { + const sdk = await audiusSdk() + const { data = [] } = await sdk.users.getDiscoverWeekly({ + id: Id.parse(currentUserId), + limit, + userId: OptionalId.parse(currentUserId) + }) + const tracks = transformAndCleanList(data, userTrackMetadataFromSDK) + primeTrackData({ tracks, queryClient }) + return tracks.map((t) => ({ + id: t.track_id, + type: EntityType.TRACK + })) + }, + staleTime: Infinity, + refetchOnMount: false, + ...options, + enabled: options?.enabled !== false && !!currentUserId + }) + + const data = query.data ?? [] + const trackIds = data + .filter((d) => d.type === EntityType.TRACK) + .map((d) => d.id as ID) + + return { + data, + trackIds, + isPending: query.isPending, + isLoading: query.isLoading, + isFetching: query.isFetching, + isSuccess: query.isSuccess, + isError: query.isError + } +} diff --git a/packages/common/src/api/tan-query/queryKeys.ts b/packages/common/src/api/tan-query/queryKeys.ts index 4e3715d502c..344931caee7 100644 --- a/packages/common/src/api/tan-query/queryKeys.ts +++ b/packages/common/src/api/tan-query/queryKeys.ts @@ -53,6 +53,7 @@ export const QUERY_KEYS = { trending: 'trending', suggestedArtists: 'suggestedArtists', suggestedFollows: 'suggestedFollows', + discoverWeekly: 'discoverWeekly', topArtistsInGenre: 'topArtistsInGenre', audioTransactions: 'audioTransactions', audioTransactionsCount: 'audioTransactionsCount', diff --git a/packages/common/src/messages/explore.ts b/packages/common/src/messages/explore.ts index 3e0158613e7..9248d419649 100644 --- a/packages/common/src/messages/explore.ts +++ b/packages/common/src/messages/explore.ts @@ -27,6 +27,10 @@ export const exploreMessages = { feelingLucky: 'Feeling Lucky?', imFeelingLucky: "I'm Feeling Lucky", recentlyPlayed: 'Recently Played', + discoverWeekly: 'Your Discover Weekly', + discoverWeeklySubtitle: 'Updated every Monday', + discoverWeeklyTrackCount: (count: number) => + `${count} ${count === 1 ? 'track' : 'tracks'}`, undergroundTrending: 'Underground Trending', verified: 'Verified' } diff --git a/packages/common/src/models/Analytics.ts b/packages/common/src/models/Analytics.ts index bcb30c408c7..4aff496a838 100644 --- a/packages/common/src/models/Analytics.ts +++ b/packages/common/src/models/Analytics.ts @@ -1312,6 +1312,7 @@ export type ExploreSectionName = | 'Recommended Tracks' | 'Artist Coin Tracks' | 'Recently Played' + | 'Discover Weekly' | 'Quick Search' | 'Featured Playlists' | 'Fan Clubs' diff --git a/packages/sdk/src/sdk/api/users/UsersApi.ts b/packages/sdk/src/sdk/api/users/UsersApi.ts index dc04a39c904..33b34685545 100644 --- a/packages/sdk/src/sdk/api/users/UsersApi.ts +++ b/packages/sdk/src/sdk/api/users/UsersApi.ts @@ -23,7 +23,9 @@ import { DownloadUSDCWithdrawalsAsCSVRequest, UsersApi as GeneratedUsersApi, RelatedArtistResponseFromJSON, + TracksResponseFromJSON, type RelatedArtistResponse, + type TracksResponse, type UserPlaylistLibrary } from '../generated/default' import * as runtime from '../generated/default/runtime' @@ -58,7 +60,8 @@ import { type UserFileUploadParams, type EntityManagerPlaylistLibraryContents, type UsersApiServicesConfig, - type GetSuggestedFollowsRequest + type GetSuggestedFollowsRequest, + type GetDiscoverWeeklyRequest } from './types' export class UsersApi extends GeneratedUsersApi { @@ -933,4 +936,68 @@ export class UsersApi extends GeneratedUsersApi { RelatedArtistResponseFromJSON(jsonValue) ).value() } + + /** + * Gets the user's Discover Weekly mix: tracks they have not heard, + * weighted toward artists they do not already follow. The mix is fixed for + * the calendar week (ISO week, UTC) and rotates when the week rolls over. + * + * Unlike `getSuggestedFollows`, this returns results for a listener with no + * history, so callers do not need a non-personalized fallback. + * + * Hand-written for the same reason as `getSuggestedFollows`: this endpoint + * is newer than the checked-in generated client. It mirrors what the + * generator would emit, so replacing it later is a no-op for callers. + */ + async getDiscoverWeekly( + params: GetDiscoverWeeklyRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + if (params.id === null || params.id === undefined) { + throw new runtime.RequiredError( + 'id', + 'Required parameter params.id was null or undefined when calling getDiscoverWeekly.' + ) + } + + const queryParameters: any = {} + + if (params.limit !== undefined) { + queryParameters.limit = params.limit + } + + if (params.userId !== undefined) { + queryParameters.user_id = params.userId + } + + const headerParameters: runtime.HTTPHeaders = {} + + if ( + !headerParameters.Authorization && + this.configuration && + this.configuration.accessToken + ) { + const token = await this.configuration.accessToken('OAuth2', ['read']) + if (token) { + headerParameters.Authorization = token + } + } + + const response = await this.request( + { + path: `/users/{id}/discover-weekly`.replace( + `{${'id'}}`, + encodeURIComponent(String(params.id)) + ), + method: 'GET', + headers: headerParameters, + query: queryParameters + }, + initOverrides + ) + + return await new runtime.JSONApiResponse(response, (jsonValue) => + TracksResponseFromJSON(jsonValue) + ).value() + } } diff --git a/packages/sdk/src/sdk/api/users/types.ts b/packages/sdk/src/sdk/api/users/types.ts index 457694c7414..85910821ec5 100644 --- a/packages/sdk/src/sdk/api/users/types.ts +++ b/packages/sdk/src/sdk/api/users/types.ts @@ -339,3 +339,20 @@ export type GetSuggestedFollowsRequest = { /** The user ID of the user making the request */ userId?: string } + +/** + * Params for `UsersApi.getDiscoverWeekly`. + * + * Hand-written for the same reason as `GetSuggestedFollowsRequest`: the + * endpoint post-dates the last SDK regeneration. Delete this and use the + * generated request type once `npm run gen` has been re-run against a node + * serving /users/{id}/discover-weekly. + */ +export type GetDiscoverWeeklyRequest = { + /** A User ID */ + id: string + /** The number of tracks to fetch (default 30, max 50) */ + limit?: number + /** The user ID of the user making the request */ + userId?: string +} diff --git a/packages/web/src/assets/img/discoverWeekly.jpg b/packages/web/src/assets/img/discoverWeekly.jpg new file mode 100644 index 0000000000000000000000000000000000000000..34bb5380ffe0db2b8acf393d704423e85aba2ad6 GIT binary patch literal 76646 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

9^jl_q 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 literal 0 HcmV?d00001 diff --git a/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklyCard.tsx b/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklyCard.tsx new file mode 100644 index 00000000000..db1dc4d8a53 --- /dev/null +++ b/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklyCard.tsx @@ -0,0 +1,64 @@ +import { useMemo } from 'react' + +import { useToggleTrack } from '@audius/common/hooks' +import { exploreMessages as messages } from '@audius/common/messages' +import { ID } from '@audius/common/models' +import { QueueSource } from '@audius/common/store' +import { Artwork, Flex, Text } from '@audius/harmony' + +import discoverWeeklyArt from 'assets/img/discoverWeekly.jpg' +import { Card, CardContent, CardFooter } from 'components/card' +import { useIsMobile } from 'hooks/useIsMobile' + +type DiscoverWeeklyCardProps = { + trackIds: ID[] +} + +/** + * Renders the Discover Weekly mix as a collection card, so it reads like a + * playlist even though it isn't one. + * + * The artwork is a checked-in asset rather than an entity's cover art: + * Discover Weekly has no playlist_id to hang an image on, since Audius + * playlists are on-chain entities and the mix is computed per request. Same + * reason there's no permalink — clicking plays the mix in place instead of + * navigating, which is the closest we can get to playlist behavior without a + * route. + */ +export const DiscoverWeeklyCard = ({ trackIds }: DiscoverWeeklyCardProps) => { + const isMobile = useIsMobile() + + // Queue the whole mix, starting at the top, so playback continues through + // all 30 rather than stopping after the first track. + const entries = useMemo( + () => trackIds.map((id) => ({ id, source: QueueSource.EXPLORE })), + [trackIds] + ) + + const { togglePlay } = useToggleTrack({ + id: trackIds[0] ?? null, + source: QueueSource.EXPLORE, + entries + }) + + return ( + + + + + + {messages.discoverWeekly} + + + {messages.discoverWeeklySubtitle} + + + + + + {messages.discoverWeeklyTrackCount(trackIds.length)} + + + + ) +} diff --git a/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklySection.tsx b/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklySection.tsx new file mode 100644 index 00000000000..8fb1920865e --- /dev/null +++ b/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklySection.tsx @@ -0,0 +1,36 @@ +import { useDiscoverWeekly } from '@audius/common/api' +import { Flex } from '@audius/harmony' + +import { CollectionCardSkeleton } from 'components/collection' +import { useIsMobile } from 'hooks/useIsMobile' + +import { DiscoverWeeklyCard } from './DiscoverWeeklyCard' +import { useExploreSectionTracking } from './useExploreSectionTracking' + +/** + * Deliberately not wrapped in a Carousel like the sibling sections: there is + * exactly one card, so the scroll affordance is dead weight and a section + * heading would just repeat the card's own title. + */ +export const DiscoverWeeklySection = () => { + const { ref, inView } = useExploreSectionTracking('Discover Weekly') + const isMobile = useIsMobile() + const { trackIds, isLoading, isError, isSuccess } = useDiscoverWeekly( + { limit: 30 }, + { enabled: inView } + ) + + if (isError || (isSuccess && trackIds.length === 0)) { + return null + } + + return ( + + {!inView || isLoading || !trackIds.length ? ( + + ) : ( + + )} + + ) +} diff --git a/packages/web/src/pages/search-explore-page/components/desktop/SearchExplorePage.tsx b/packages/web/src/pages/search-explore-page/components/desktop/SearchExplorePage.tsx index c1c8c280892..a9ff918d0ce 100644 --- a/packages/web/src/pages/search-explore-page/components/desktop/SearchExplorePage.tsx +++ b/packages/web/src/pages/search-explore-page/components/desktop/SearchExplorePage.tsx @@ -40,6 +40,7 @@ import { CategoryView } from 'pages/search-page/types' import { ArtistSpotlightSection } from './ArtistSpotlightSection' import { BestSellingAlbumsSection } from './BestSellingAlbumsSection' +import { DiscoverWeeklySection } from './DiscoverWeeklySection' import { FanClubsExploreSection } from './FanClubsExploreSection' import { FeaturedPlaylistsSection } from './FeaturedPlaylistsSection' import { FeaturedRemixContestsSection } from './FeaturedRemixContestsSection' @@ -221,6 +222,11 @@ const SearchExplorePage = ({ shouldRender: showTrackContent && showUserContextualContent, element: }, + { + key: 'discoverWeekly', + shouldRender: showTrackContent && showUserContextualContent, + element: + }, { key: 'undergroundTrendingTracks', shouldRender: isTracksTab, diff --git a/packages/web/src/pages/search-explore-page/components/mobile/SearchExplorePage.tsx b/packages/web/src/pages/search-explore-page/components/mobile/SearchExplorePage.tsx index 2554f68179f..1229ae34c2a 100644 --- a/packages/web/src/pages/search-explore-page/components/mobile/SearchExplorePage.tsx +++ b/packages/web/src/pages/search-explore-page/components/mobile/SearchExplorePage.tsx @@ -36,6 +36,7 @@ import { Category, CategoryKey, CategoryView } from 'pages/search-page/types' import { ArtistSpotlightSection } from '../desktop/ArtistSpotlightSection' import { BestSellingAlbumsSection } from '../desktop/BestSellingAlbumsSection' +import { DiscoverWeeklySection } from '../desktop/DiscoverWeeklySection' import { FanClubsExploreSection } from '../desktop/FanClubsExploreSection' import { FeaturedPlaylistsSection } from '../desktop/FeaturedPlaylistsSection' import { FeaturedRemixContestsSection } from '../desktop/FeaturedRemixContestsSection' @@ -231,6 +232,9 @@ const SearchExplorePage = ({ {showTrackContent && showUserContextualContent ? ( ) : null} + {showTrackContent && showUserContextualContent ? ( + + ) : null} {showPlaylistContent ? : null} {showAlbumContent ? : null} {showAlbumContent ? : null} From a9a5dec99a3e226984311cd9a86cb665f2df30b9 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 24 Aug 2026 13:31:33 -0700 Subject: [PATCH 2/4] feat(mobile): surface Discover Weekly on the native Explore screen Mirrors the web section. The native app composes its own Explore screen from a separate component set, so this is a parallel implementation rather than a shared one. Same shape as web: bundled artwork asset (the mix has no playlist_id to hang cover art on), press plays the mix in place with all 30 queued rather than navigating, and no ExploreSection wrapper since a heading would repeat the card's own title. Co-Authored-By: Claude Opus 5 --- .../src/assets/images/discoverWeekly.jpg | Bin 0 -> 76646 bytes .../components/DiscoverWeekly.tsx | 96 ++++++++++++++++++ .../components/ExploreContent.tsx | 2 + 3 files changed, 98 insertions(+) create mode 100644 packages/mobile/src/assets/images/discoverWeekly.jpg create mode 100644 packages/mobile/src/screens/explore-screen/components/DiscoverWeekly.tsx diff --git a/packages/mobile/src/assets/images/discoverWeekly.jpg b/packages/mobile/src/assets/images/discoverWeekly.jpg new file mode 100644 index 0000000000000000000000000000000000000000..34bb5380ffe0db2b8acf393d704423e85aba2ad6 GIT binary patch literal 76646 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

9^jl_q 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 literal 0 HcmV?d00001 diff --git a/packages/mobile/src/screens/explore-screen/components/DiscoverWeekly.tsx b/packages/mobile/src/screens/explore-screen/components/DiscoverWeekly.tsx new file mode 100644 index 00000000000..d1f515d8951 --- /dev/null +++ b/packages/mobile/src/screens/explore-screen/components/DiscoverWeekly.tsx @@ -0,0 +1,96 @@ +import React, { useMemo } from 'react' + +import { useDiscoverWeekly } from '@audius/common/api' +import { useToggleTrack } from '@audius/common/hooks' +import { exploreMessages as messages } from '@audius/common/messages' +import { QueueSource } from '@audius/common/store' +import { Image } from 'react-native' + +import { Divider, Flex, Paper, Text } from '@audius/harmony-native' +import discoverWeeklyArt from 'app/assets/images/discoverWeekly.jpg' +import { CollectionCardSkeleton } from 'app/components/collection-list/CollectionCardSkeleton' + +import { useExploreSectionTracking } from '../hooks/useExploreSectionTracking' + +const CARD_WIDTH = 200 + +/** + * The mix rendered as a collection card, so it reads like a playlist even + * though it isn't one. Mirrors the web Explore section. + * + * The artwork is a bundled asset rather than entity cover art: the mix has no + * playlist_id to hang an image on. Same reason pressing plays in place rather + * than navigating to a Collection screen -- there's nothing to navigate to. + * + * Deliberately not wrapped in ExploreSection like its siblings: there's one + * card, and a section heading would just repeat the card's own title. + */ +export const DiscoverWeekly = () => { + const { InViewWrapper, inView } = useExploreSectionTracking('Discover Weekly') + const { trackIds, isLoading, isError, isSuccess } = useDiscoverWeekly( + { limit: 30 }, + { enabled: inView } + ) + + // Queue the whole mix, starting at the top, so playback continues through + // all 30 rather than stopping after the first track. + const entries = useMemo( + () => trackIds.map((id) => ({ id, source: QueueSource.EXPLORE })), + [trackIds] + ) + + const { togglePlay } = useToggleTrack({ + id: trackIds[0] ?? null, + source: QueueSource.EXPLORE, + entries + }) + + if (isError || (isSuccess && trackIds.length === 0)) { + return null + } + + return ( + + + {!inView || isLoading || !trackIds.length ? ( + + ) : ( + + + + + {messages.discoverWeekly} + + + {messages.discoverWeeklySubtitle} + + + + + + {messages.discoverWeeklyTrackCount(trackIds.length)} + + + + )} + + + ) +} diff --git a/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx b/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx index 8f5e78cea76..7877745023c 100644 --- a/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx +++ b/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx @@ -8,6 +8,7 @@ import { useSearchCategory } from 'app/screens/search-screen/searchState' import { ArtistSpotlight } from './ArtistSpotlight' import { BestSellingAlbums } from './BestSellingAlbums' +import { DiscoverWeekly } from './DiscoverWeekly' import { FeaturedPlaylists } from './FeaturedPlaylists' import { FeaturedRemixContests } from './FeaturedRemixContests' import { FeelingLucky } from './FeelingLucky' @@ -39,6 +40,7 @@ export const ExploreContent = () => { {showTrackContent && showUserContextualContent && ( )} + {showTrackContent && showUserContextualContent && } {showUserContent && } {showUserContent && } {showTrackContent && showUserContextualContent && } From 12ed1b6a4792214ed48a983f7c74924b6bb35a83 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 24 Aug 2026 14:39:57 -0700 Subject: [PATCH 3/4] feat(client): Discover Weekly page, banners, and analytics Promotes Discover Weekly from a card in the Explore stack to a proper feature with its own destination. - Dedicated page at /explore/discover-weekly (web) and a matching native screen. Structured like a collection page -- artwork, title, play-all, full track list -- but assembled from the History page's pieces, since there's no collection entity to drive the real collection page. - Full-width banner pinned to the top of Explore on both platforms, replacing the card. This is a launch placement for a new feature, not another content row, so it sits above the section stack. - The same banner on the feed. Explore was the only entry point and it takes a deliberate detour to reach; the feed is where people land. - Analytics: banner view, banner click, page view, play-all. Every event carries `surface` ('explore' | 'feed') so we can tell which entry point actually drives listens, and `trackCount` so an impression on an empty mix is distinguishable. Impressions fire once, and only after the mix resolves, so a banner that then hides itself can't inflate the click-through denominator. The banner navigates rather than playing in place -- it's an entry point, and the page it opens has the play-all. Co-Authored-By: Claude Opus 5 --- packages/common/src/messages/explore.ts | 4 + packages/common/src/models/Analytics.ts | 43 ++++ packages/common/src/utils/route.ts | 3 + .../src/screens/app-screen/AppTabScreen.tsx | 6 + .../DiscoverWeeklyScreen.tsx | 80 +++++++ .../screens/discover-weekly-screen/index.ts | 1 + .../components/DiscoverWeekly.tsx | 127 ++++++----- .../components/ExploreContent.tsx | 4 +- .../src/screens/feed-screen/FeedScreen.tsx | 3 + packages/web/src/app/web-player/WebPlayer.tsx | 12 ++ .../discover-weekly/DiscoverWeeklyBanner.tsx | 139 ++++++++++++ .../src/components/discover-weekly/index.ts | 1 + .../DiscoverWeeklyPage.tsx | 203 ++++++++++++++++++ .../components/desktop/FeedPageContent.tsx | 12 +- .../components/desktop/DiscoverWeeklyCard.tsx | 64 ------ .../desktop/DiscoverWeeklySection.tsx | 36 ---- .../components/desktop/SearchExplorePage.tsx | 12 +- .../components/mobile/SearchExplorePage.tsx | 8 +- 18 files changed, 579 insertions(+), 179 deletions(-) create mode 100644 packages/mobile/src/screens/discover-weekly-screen/DiscoverWeeklyScreen.tsx create mode 100644 packages/mobile/src/screens/discover-weekly-screen/index.ts create mode 100644 packages/web/src/components/discover-weekly/DiscoverWeeklyBanner.tsx create mode 100644 packages/web/src/components/discover-weekly/index.ts create mode 100644 packages/web/src/pages/discover-weekly-page/DiscoverWeeklyPage.tsx delete mode 100644 packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklyCard.tsx delete mode 100644 packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklySection.tsx diff --git a/packages/common/src/messages/explore.ts b/packages/common/src/messages/explore.ts index 9248d419649..d0b27be8f22 100644 --- a/packages/common/src/messages/explore.ts +++ b/packages/common/src/messages/explore.ts @@ -29,6 +29,10 @@ export const exploreMessages = { recentlyPlayed: 'Recently Played', discoverWeekly: 'Your Discover Weekly', discoverWeeklySubtitle: 'Updated every Monday', + discoverWeeklyBadge: 'New', + discoverWeeklyPitch: + 'A fresh mix of tracks picked just for you. Updated every Monday.', + discoverWeeklyCta: 'Listen Now', discoverWeeklyTrackCount: (count: number) => `${count} ${count === 1 ? 'track' : 'tracks'}`, undergroundTrending: 'Underground Trending', diff --git a/packages/common/src/models/Analytics.ts b/packages/common/src/models/Analytics.ts index 4aff496a838..b35301ffbf9 100644 --- a/packages/common/src/models/Analytics.ts +++ b/packages/common/src/models/Analytics.ts @@ -263,6 +263,12 @@ export enum Name { EXPLORE_SECTION_VIEW = 'Explore: Section View', EXPLORE_SECTION_CLICK = 'Explore: Section Click', + // Discover Weekly + DISCOVER_WEEKLY_BANNER_VIEW = 'Discover Weekly: Banner View', + DISCOVER_WEEKLY_BANNER_CLICK = 'Discover Weekly: Banner Click', + DISCOVER_WEEKLY_PAGE_VIEW = 'Discover Weekly: Page View', + DISCOVER_WEEKLY_PLAY_ALL = 'Discover Weekly: Play All', + // Errors ERROR_PAGE = 'Error Page', NOT_FOUND_PAGE = 'Not Found Page', @@ -1348,6 +1354,39 @@ type ExploreSectionClick = { link?: string } +/** + * Surface the banner was rendered on. The mix is reachable from more than one + * place, so every Discover Weekly event carries this -- otherwise there's no + * way to tell which entry point is actually driving listens. + */ +export type DiscoverWeeklySurface = 'explore' | 'feed' + +type DiscoverWeeklyBannerView = { + eventName: Name.DISCOVER_WEEKLY_BANNER_VIEW + surface: DiscoverWeeklySurface + source: 'web' | 'mobile' + trackCount: number +} + +type DiscoverWeeklyBannerClick = { + eventName: Name.DISCOVER_WEEKLY_BANNER_CLICK + surface: DiscoverWeeklySurface + source: 'web' | 'mobile' + trackCount: number +} + +type DiscoverWeeklyPageView = { + eventName: Name.DISCOVER_WEEKLY_PAGE_VIEW + source: 'web' | 'mobile' + trackCount: number +} + +type DiscoverWeeklyPlayAll = { + eventName: Name.DISCOVER_WEEKLY_PLAY_ALL + source: 'web' | 'mobile' + trackCount: number +} + type BrowserNotificationSetting = { eventName: Name.BROWSER_NOTIFICATION_SETTINGS provider: 'safari' | 'gcm' @@ -2723,6 +2762,10 @@ export type AllTrackingEvents = | SearchResultSelect | ExploreSectionView | ExploreSectionClick + | DiscoverWeeklyBannerView + | DiscoverWeeklyBannerClick + | DiscoverWeeklyPageView + | DiscoverWeeklyPlayAll | ErrorPage | NotFoundPage | PageView diff --git a/packages/common/src/utils/route.ts b/packages/common/src/utils/route.ts index 994f210f995..16f680e80af 100644 --- a/packages/common/src/utils/route.ts +++ b/packages/common/src/utils/route.ts @@ -31,6 +31,7 @@ export const TRENDING_PLAYLISTS_PAGE_LEGACY = '/trending/playlists' export const EXPLORE_PAGE = '/explore' export const TRENDING_PLAYLISTS_PAGE = '/explore/playlists' export const TRENDING_UNDERGROUND_PAGE = '/explore/underground' +export const DISCOVER_WEEKLY_PAGE = '/explore/discover-weekly' export const CONTESTS_PAGE = '/contests' // DEPRECATED - use /library instead. @@ -301,6 +302,7 @@ export const orderedRoutes = [ TRENDING_GENRES, TRENDING_PAGE, EXPLORE_PAGE, + DISCOVER_WEEKLY_PAGE, CONTESTS_PAGE, EMPTY_PAGE, SEARCH_PAGE, @@ -355,6 +357,7 @@ export const staticRoutes = new Set([ FEED_PAGE, TRENDING_PAGE, EXPLORE_PAGE, + DISCOVER_WEEKLY_PAGE, CONTESTS_PAGE, HOST_REMIX_CONTEST_ROOT_PAGE, TRENDING_PLAYLISTS_PAGE, diff --git a/packages/mobile/src/screens/app-screen/AppTabScreen.tsx b/packages/mobile/src/screens/app-screen/AppTabScreen.tsx index 51ba9ee5c77..a872bc751f5 100644 --- a/packages/mobile/src/screens/app-screen/AppTabScreen.tsx +++ b/packages/mobile/src/screens/app-screen/AppTabScreen.tsx @@ -39,6 +39,7 @@ import { } from 'app/screens/coin-details-screen' import { CoinRedeemScreen } from 'app/screens/coin-redeem-screen' import { CollectionScreen } from 'app/screens/collection-screen/CollectionScreen' +import { DiscoverWeeklyScreen } from 'app/screens/discover-weekly-screen' import { EditProfileScreen } from 'app/screens/edit-profile-screen' import { ProfileScreen } from 'app/screens/profile-screen' import { RewardsScreen } from 'app/screens/rewards-screen' @@ -108,6 +109,7 @@ export type AppTabScreenParamList = { SettingsScreen: undefined AboutScreen: undefined ListeningHistoryScreen: undefined + DiscoverWeeklyScreen: undefined AccountSettingsScreen: undefined ChangeEmail: undefined ChangePassword: undefined @@ -298,6 +300,10 @@ export const AppTabScreen = ({ baseScreen, Stack }: AppTabScreenProps) => { component={EditCoinDetailsScreen} /> + diff --git a/packages/mobile/src/screens/discover-weekly-screen/DiscoverWeeklyScreen.tsx b/packages/mobile/src/screens/discover-weekly-screen/DiscoverWeeklyScreen.tsx new file mode 100644 index 00000000000..e990403a98a --- /dev/null +++ b/packages/mobile/src/screens/discover-weekly-screen/DiscoverWeeklyScreen.tsx @@ -0,0 +1,80 @@ +import React, { useEffect, useRef } from 'react' + +import { useDiscoverWeekly } from '@audius/common/api' +import { useAnalytics } from '@audius/common/hooks' +import { exploreMessages } from '@audius/common/messages' +import { Name } from '@audius/common/models' +import { Image } from 'react-native' + +import { Flex, Paper, Text } from '@audius/harmony-native' +import discoverWeeklyArt from 'app/assets/images/discoverWeekly.jpg' +import { Screen, ScreenContent } from 'app/components/core' +import { TrackLineup } from 'app/components/lineup/TrackLineup' + +const messages = { + title: 'Discover Weekly' +} + +const ART_SIZE = 120 + +/** + * The full Discover Weekly mix. Mirrors the web page: artwork header, then the + * track list. + * + * The endpoint returns a fixed 30, so there is no pagination -- hasNextPage is + * false and loadNextPage is a no-op. + */ +export const DiscoverWeeklyScreen = () => { + const { trackIds, isPending, isFetching } = useDiscoverWeekly({ limit: 30 }) + const { trackEvent } = useAnalytics() + + // Fired once the mix resolves, so trackCount is real and a failed load + // doesn't register as a page view. + const hasTrackedView = useRef(false) + useEffect(() => { + if (hasTrackedView.current || !trackIds.length) return + hasTrackedView.current = true + trackEvent({ + eventName: Name.DISCOVER_WEEKLY_PAGE_VIEW, + source: 'mobile', + trackCount: trackIds.length + }) + }, [trackIds.length, trackEvent]) + + return ( + + + + + + + + {exploreMessages.discoverWeekly} + + + {exploreMessages.discoverWeeklySubtitle} + + {trackIds.length ? ( + + {exploreMessages.discoverWeeklyTrackCount(trackIds.length)} + + ) : null} + + + {}} + pageSize={30} + /> + + + + ) +} diff --git a/packages/mobile/src/screens/discover-weekly-screen/index.ts b/packages/mobile/src/screens/discover-weekly-screen/index.ts new file mode 100644 index 00000000000..4d4cd538596 --- /dev/null +++ b/packages/mobile/src/screens/discover-weekly-screen/index.ts @@ -0,0 +1 @@ +export * from './DiscoverWeeklyScreen' diff --git a/packages/mobile/src/screens/explore-screen/components/DiscoverWeekly.tsx b/packages/mobile/src/screens/explore-screen/components/DiscoverWeekly.tsx index d1f515d8951..b01bb2b2868 100644 --- a/packages/mobile/src/screens/explore-screen/components/DiscoverWeekly.tsx +++ b/packages/mobile/src/screens/explore-screen/components/DiscoverWeekly.tsx @@ -1,49 +1,65 @@ -import React, { useMemo } from 'react' +import React, { useCallback, useEffect, useRef } from 'react' import { useDiscoverWeekly } from '@audius/common/api' -import { useToggleTrack } from '@audius/common/hooks' +import { useAnalytics } from '@audius/common/hooks' import { exploreMessages as messages } from '@audius/common/messages' -import { QueueSource } from '@audius/common/store' +import { Name, type DiscoverWeeklySurface } from '@audius/common/models' import { Image } from 'react-native' -import { Divider, Flex, Paper, Text } from '@audius/harmony-native' +import { Flex, Paper, Text } from '@audius/harmony-native' import discoverWeeklyArt from 'app/assets/images/discoverWeekly.jpg' -import { CollectionCardSkeleton } from 'app/components/collection-list/CollectionCardSkeleton' +import { useNavigation } from 'app/hooks/useNavigation' import { useExploreSectionTracking } from '../hooks/useExploreSectionTracking' -const CARD_WIDTH = 200 +const ART_SIZE = 96 /** - * The mix rendered as a collection card, so it reads like a playlist even - * though it isn't one. Mirrors the web Explore section. + * Promotional banner for Discover Weekly, pinned to the top of Explore. * - * The artwork is a bundled asset rather than entity cover art: the mix has no - * playlist_id to hang an image on. Same reason pressing plays in place rather - * than navigating to a Collection screen -- there's nothing to navigate to. - * - * Deliberately not wrapped in ExploreSection like its siblings: there's one - * card, and a section heading would just repeat the card's own title. + * Mirrors the web banner: an entry point rather than a content row, so it + * navigates to the full mix instead of playing in place. Deliberately not + * wrapped in ExploreSection -- it sits above the section stack. */ -export const DiscoverWeekly = () => { +type DiscoverWeeklyProps = { + /** Which surface this instance renders on -- carried on every event so we + * can tell which entry point actually drives listens. */ + surface?: DiscoverWeeklySurface +} + +export const DiscoverWeekly = ({ + surface = 'explore' +}: DiscoverWeeklyProps) => { const { InViewWrapper, inView } = useExploreSectionTracking('Discover Weekly') - const { trackIds, isLoading, isError, isSuccess } = useDiscoverWeekly( + const navigation = useNavigation() + const { trackEvent } = useAnalytics() + const { trackIds, isError, isSuccess } = useDiscoverWeekly( { limit: 30 }, { enabled: inView } ) - // Queue the whole mix, starting at the top, so playback continues through - // all 30 rather than stopping after the first track. - const entries = useMemo( - () => trackIds.map((id) => ({ id, source: QueueSource.EXPLORE })), - [trackIds] - ) + // Fire the impression once, and only once there's a real mix behind it. + const hasTrackedView = useRef(false) + useEffect(() => { + if (hasTrackedView.current || !inView || !trackIds.length) return + hasTrackedView.current = true + trackEvent({ + eventName: Name.DISCOVER_WEEKLY_BANNER_VIEW, + surface, + source: 'mobile', + trackCount: trackIds.length + }) + }, [inView, trackIds.length, surface, trackEvent]) - const { togglePlay } = useToggleTrack({ - id: trackIds[0] ?? null, - source: QueueSource.EXPLORE, - entries - }) + const handlePress = useCallback(() => { + trackEvent({ + eventName: Name.DISCOVER_WEEKLY_BANNER_CLICK, + surface, + source: 'mobile', + trackCount: trackIds.length + }) + navigation.navigate('DiscoverWeeklyScreen') + }, [navigation, trackEvent, surface, trackIds.length]) if (isError || (isSuccess && trackIds.length === 0)) { return null @@ -51,46 +67,23 @@ export const DiscoverWeekly = () => { return ( - - {!inView || isLoading || !trackIds.length ? ( - - ) : ( - - - - - {messages.discoverWeekly} - - - {messages.discoverWeeklySubtitle} - - - - - - {messages.discoverWeeklyTrackCount(trackIds.length)} - - - - )} - + + + + + {messages.discoverWeeklyBadge} + + + {messages.discoverWeekly} + + + {messages.discoverWeeklyPitch} + + + ) } diff --git a/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx b/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx index 7877745023c..ba5182e75dd 100644 --- a/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx +++ b/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx @@ -31,6 +31,9 @@ export const ExploreContent = () => { return ( + {showTrackContent && showUserContextualContent && ( + + )} {showPlaylistContent && } {showTrackContent && } {showAlbumContent && } @@ -40,7 +43,6 @@ export const ExploreContent = () => { {showTrackContent && showUserContextualContent && ( )} - {showTrackContent && showUserContextualContent && } {showUserContent && } {showUserContent && } {showTrackContent && showUserContextualContent && } diff --git a/packages/mobile/src/screens/feed-screen/FeedScreen.tsx b/packages/mobile/src/screens/feed-screen/FeedScreen.tsx index d2c0e59ea3a..fe377b05a38 100644 --- a/packages/mobile/src/screens/feed-screen/FeedScreen.tsx +++ b/packages/mobile/src/screens/feed-screen/FeedScreen.tsx @@ -28,6 +28,7 @@ import { SuggestedFollows } from 'app/components/suggested-follows' import { useDrawer } from 'app/hooks/useDrawer' import { AppDrawerContext } from 'app/screens/app-drawer-screen' import { MobileRootHeader } from 'app/screens/app-screen/MobileRootHeader' +import { DiscoverWeekly } from 'app/screens/explore-screen/components/DiscoverWeekly' import { make, track } from 'app/services/analytics' import { FeedFilterButton } from './FeedFilterButton' @@ -241,6 +242,7 @@ export const FeedScreen = () => { source='DISCOVER_FEED' pullToRefresh={false} hideHeaderOnEmpty + header={} LineupEmptyComponent={} ListFooterComponent={ @@ -253,6 +255,7 @@ export const FeedScreen = () => { source='DISCOVER_FEED' pullToRefresh hideHeaderOnEmpty + header={} LineupEmptyComponent={} ListFooterComponent={ diff --git a/packages/web/src/app/web-player/WebPlayer.tsx b/packages/web/src/app/web-player/WebPlayer.tsx index e4504fb07ee..4e688a65c6d 100644 --- a/packages/web/src/app/web-player/WebPlayer.tsx +++ b/packages/web/src/app/web-player/WebPlayer.tsx @@ -239,6 +239,7 @@ const { NOTIFICATION_PAGE, NOTIFICATION_USERS_PAGE, EXPLORE_PAGE, + DISCOVER_WEEKLY_PAGE, CONTESTS_PAGE, SAVED_PAGE, LIBRARY_PAGE, @@ -329,6 +330,9 @@ const { // TODO: do we need to lazy load edit? const EditTrackPage = lazy(() => import('pages/edit-page')) +const DiscoverWeeklyPage = lazy( + () => import('pages/discover-weekly-page/DiscoverWeeklyPage') +) const UploadPage = lazy(() => import('pages/upload-page')) const CheckPage = lazy(() => import('pages/check-page/CheckPage')) const Modals = lazy(() => import('pages/modals/Modals')) @@ -924,6 +928,10 @@ const WebPlayer = (props: WebPlayerProps) => { element={} /> } /> + } + /> {!isProduction ? ( } /> ) : null} @@ -1402,6 +1410,10 @@ const WebPlayer = (props: WebPlayerProps) => { element={} /> } /> + } + /> {!isProduction ? ( } /> ) : null} diff --git a/packages/web/src/components/discover-weekly/DiscoverWeeklyBanner.tsx b/packages/web/src/components/discover-weekly/DiscoverWeeklyBanner.tsx new file mode 100644 index 00000000000..1e6c4ede2ad --- /dev/null +++ b/packages/web/src/components/discover-weekly/DiscoverWeeklyBanner.tsx @@ -0,0 +1,139 @@ +import { useCallback, useEffect, useRef } from 'react' + +import { useDiscoverWeekly } from '@audius/common/api' +import { useAnalytics } from '@audius/common/hooks' +import { exploreMessages as messages } from '@audius/common/messages' +import { Name, type DiscoverWeeklySurface } from '@audius/common/models' +import { route } from '@audius/common/utils' +import { + Artwork, + Button, + Flex, + IconArrowRight, + Paper, + Text +} from '@audius/harmony' +import { useInView } from 'react-intersection-observer' +import { useNavigate } from 'react-router' + +import discoverWeeklyArt from 'assets/img/discoverWeekly.jpg' +import { useIsMobile } from 'hooks/useIsMobile' + +const { DISCOVER_WEEKLY_PAGE } = route + +const ART_SIZE_DESKTOP = 140 +const ART_SIZE_MOBILE = 96 + +type DiscoverWeeklyBannerProps = { + /** Which surface this instance is rendered on -- carried on every event so + * we can tell which entry point actually drives listens. */ + surface: DiscoverWeeklySurface +} + +/** + * Promotional banner for Discover Weekly. + * + * Shared across Explore and the feed rather than duplicated, so the two stay + * visually identical and the analytics differ only by `surface`. + * + * Navigates to the full mix rather than playing in place -- the banner is an + * entry point, and the page it opens has the play-all. + */ +export const DiscoverWeeklyBanner = ({ + surface +}: DiscoverWeeklyBannerProps) => { + const navigate = useNavigate() + const isMobile = useIsMobile() + const { trackEvent } = useAnalytics() + + const { ref, inView } = useInView({ + threshold: 0, + rootMargin: '200px', + triggerOnce: true, + fallbackInView: true + }) + + const { trackIds, isError, isSuccess } = useDiscoverWeekly( + { limit: 30 }, + { enabled: inView } + ) + + // Fire the impression once, and only once there's a real mix behind it -- + // an impression for a banner that then hides itself would inflate the + // denominator on click-through. + const hasTrackedView = useRef(false) + useEffect(() => { + if (hasTrackedView.current || !inView || !trackIds.length) return + hasTrackedView.current = true + trackEvent({ + eventName: Name.DISCOVER_WEEKLY_BANNER_VIEW, + surface, + source: isMobile ? 'mobile' : 'web', + trackCount: trackIds.length + }) + }, [inView, trackIds.length, surface, isMobile, trackEvent]) + + const handleClick = useCallback(() => { + trackEvent({ + eventName: Name.DISCOVER_WEEKLY_BANNER_CLICK, + surface, + source: isMobile ? 'mobile' : 'web', + trackCount: trackIds.length + }) + navigate(DISCOVER_WEEKLY_PAGE) + }, [navigate, trackEvent, surface, isMobile, trackIds.length]) + + // Hidden entirely when there's no mix to promote -- a banner advertising an + // empty page is worse than no banner. + if (isError || (isSuccess && trackIds.length === 0)) { + return null + } + + const artSize = isMobile ? ART_SIZE_MOBILE : ART_SIZE_DESKTOP + + return ( + + + + + + {messages.discoverWeeklyBadge} + + + {messages.discoverWeekly} + + + {messages.discoverWeeklyPitch} + + + {isMobile ? null : ( + + )} + + + ) +} diff --git a/packages/web/src/components/discover-weekly/index.ts b/packages/web/src/components/discover-weekly/index.ts new file mode 100644 index 00000000000..42ec029842f --- /dev/null +++ b/packages/web/src/components/discover-weekly/index.ts @@ -0,0 +1 @@ +export * from './DiscoverWeeklyBanner' diff --git a/packages/web/src/pages/discover-weekly-page/DiscoverWeeklyPage.tsx b/packages/web/src/pages/discover-weekly-page/DiscoverWeeklyPage.tsx new file mode 100644 index 00000000000..8ea8b4850b2 --- /dev/null +++ b/packages/web/src/pages/discover-weekly-page/DiscoverWeeklyPage.tsx @@ -0,0 +1,203 @@ +import { useCallback, useEffect, useMemo, useRef } from 'react' + +import { useCurrentUserId, useDiscoverWeekly } from '@audius/common/api' +import { useAnalytics } from '@audius/common/hooks' +import { exploreMessages } from '@audius/common/messages' +import { ID, Name, PlaybackSource } from '@audius/common/models' +import { playbackActions, playbackSelectors } from '@audius/common/store' +import type { PlaybackTrack } from '@audius/common/store' +import { + Artwork, + Button, + Flex, + IconPause, + IconPlay, + Text +} from '@audius/harmony' +import { useDispatch, useSelector } from 'react-redux' + +import discoverWeeklyArt from 'assets/img/discoverWeekly.jpg' +import { make } from 'common/store/analytics/actions' +import Page from 'components/page/Page' +import { TrackTableLineup, TracksTableColumn } from 'components/tracks-table' +import { useIsMobile } from 'hooks/useIsMobile' +import { useMainContentRef } from 'pages/MainContentContext' + +const messages = { + title: 'Discover Weekly', + description: + 'A fresh mix of tracks picked for you, updated every Monday on Audius.' +} + +const DISCOVER_WEEKLY_SOURCE = 'DISCOVER_WEEKLY_TRACKS' +const PAGE_SIZE = 30 +const ARTWORK_SIZE = 200 + +const columns: TracksTableColumn[] = [ + 'trackName', + 'releaseDate', + 'length', + 'plays', + 'reposts', + 'overflowActions' +] + +/** + * The full Discover Weekly mix. + * + * Structured like a collection page -- artwork, title, play-all, track list -- + * but it isn't backed by a collection entity, so it's assembled from the same + * pieces the History page uses rather than reusing the collection page. + * Artwork is the bundled asset for the same reason: there's no playlist_id to + * hang cover art on. + * + * The endpoint returns a fixed 30, so there is no pagination. + */ +export const DiscoverWeeklyPage = () => { + const dispatch = useDispatch() + const isMobile = useIsMobile() + const { trackEvent } = useAnalytics() + const mainContentRef = useMainContentRef() + const { data: currentUserId } = useCurrentUserId() + + const { trackIds, isPending, isFetching, isLoading } = useDiscoverWeekly({ + limit: PAGE_SIZE + }) + + // Fired once the mix resolves rather than on mount, so trackCount is real + // and a failed load doesn't register as a page view. + const hasTrackedView = useRef(false) + useEffect(() => { + if (hasTrackedView.current || !trackIds.length) return + hasTrackedView.current = true + trackEvent({ + eventName: Name.DISCOVER_WEEKLY_PAGE_VIEW, + source: isMobile ? 'mobile' : 'web', + trackCount: trackIds.length + }) + }, [trackIds.length, isMobile, trackEvent]) + + const isPlaying = useSelector(playbackSelectors.getPlaying) + const currentPlaybackTrackId = useSelector( + playbackSelectors.getCurrentTrackId + ) + + const playbackQueue: PlaybackTrack[] = useMemo( + () => + trackIds.map((id) => ({ + trackId: id, + source: DISCOVER_WEEKLY_SOURCE + })), + [trackIds] + ) + + // Mirrors the History page's play-all: toggle when we're already on the + // first track, otherwise start the queue from the top. + const handlePlay = useCallback(() => { + if (playbackQueue.length === 0) return + const firstId = playbackQueue[0].trackId as ID + + if (currentPlaybackTrackId === firstId) { + dispatch( + isPlaying ? playbackActions.togglePlay() : playbackActions.play() + ) + dispatch( + make(isPlaying ? Name.PLAYBACK_PAUSE : Name.PLAYBACK_PLAY, { + id: `${firstId}`, + source: PlaybackSource.PLAYLIST_PAGE + }) + ) + return + } + + trackEvent({ + eventName: Name.DISCOVER_WEEKLY_PLAY_ALL, + source: isMobile ? 'mobile' : 'web', + trackCount: playbackQueue.length + }) + dispatch( + playbackActions.playFrom({ + tracks: playbackQueue, + startIndex: 0, + querySource: null + }) + ) + dispatch( + make(Name.PLAYBACK_PLAY, { + id: `${firstId}`, + source: PlaybackSource.PLAYLIST_PAGE + }) + ) + }, [ + dispatch, + isPlaying, + currentPlaybackTrackId, + playbackQueue, + trackEvent, + isMobile + ]) + + const isEmpty = !isLoading && trackIds.length === 0 + + return ( + + + + + + {exploreMessages.discoverWeekly} + + + {exploreMessages.discoverWeeklySubtitle} + {trackIds.length + ? ` · ${exploreMessages.discoverWeeklyTrackCount(trackIds.length)}` + : ''} + + + + + + {}} + pageSize={PAGE_SIZE} + columns={columns} + userId={currentUserId} + showArtistInTrackNameColumn + scrollRef={mainContentRef} + /> + + ) +} + +export default DiscoverWeeklyPage diff --git a/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx b/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx index 4fd92aebc3a..dcf79782ca6 100644 --- a/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx +++ b/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx @@ -15,6 +15,7 @@ import { Flex, IconFeed } from '@audius/harmony' import { make, useRecord } from 'common/store/analytics/actions' import { MIN_DESKTOP_CONTENT_WIDTH_PX } from 'common/utils/layout' +import { DiscoverWeeklyBanner } from 'components/discover-weekly' import { Header } from 'components/header/desktop/Header' import EndOfLineup from 'components/lineup/EndOfLineup' import { TrackLineup } from 'components/lineup/TrackLineup' @@ -154,7 +155,16 @@ const FeedPageContent = ({ containerRef }: FeedPageContentProps) => { size='large' header={header} > - + + {/* Above the lineup so the mix is reachable without leaving the feed: + Explore is the only other entry point and it takes a deliberate + detour to get to. */} + { - const isMobile = useIsMobile() - - // Queue the whole mix, starting at the top, so playback continues through - // all 30 rather than stopping after the first track. - const entries = useMemo( - () => trackIds.map((id) => ({ id, source: QueueSource.EXPLORE })), - [trackIds] - ) - - const { togglePlay } = useToggleTrack({ - id: trackIds[0] ?? null, - source: QueueSource.EXPLORE, - entries - }) - - return ( - - - - - - {messages.discoverWeekly} - - - {messages.discoverWeeklySubtitle} - - - - - - {messages.discoverWeeklyTrackCount(trackIds.length)} - - - - ) -} diff --git a/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklySection.tsx b/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklySection.tsx deleted file mode 100644 index 8fb1920865e..00000000000 --- a/packages/web/src/pages/search-explore-page/components/desktop/DiscoverWeeklySection.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useDiscoverWeekly } from '@audius/common/api' -import { Flex } from '@audius/harmony' - -import { CollectionCardSkeleton } from 'components/collection' -import { useIsMobile } from 'hooks/useIsMobile' - -import { DiscoverWeeklyCard } from './DiscoverWeeklyCard' -import { useExploreSectionTracking } from './useExploreSectionTracking' - -/** - * Deliberately not wrapped in a Carousel like the sibling sections: there is - * exactly one card, so the scroll affordance is dead weight and a section - * heading would just repeat the card's own title. - */ -export const DiscoverWeeklySection = () => { - const { ref, inView } = useExploreSectionTracking('Discover Weekly') - const isMobile = useIsMobile() - const { trackIds, isLoading, isError, isSuccess } = useDiscoverWeekly( - { limit: 30 }, - { enabled: inView } - ) - - if (isError || (isSuccess && trackIds.length === 0)) { - return null - } - - return ( - - {!inView || isLoading || !trackIds.length ? ( - - ) : ( - - )} - - ) -} diff --git a/packages/web/src/pages/search-explore-page/components/desktop/SearchExplorePage.tsx b/packages/web/src/pages/search-explore-page/components/desktop/SearchExplorePage.tsx index a9ff918d0ce..a780b454828 100644 --- a/packages/web/src/pages/search-explore-page/components/desktop/SearchExplorePage.tsx +++ b/packages/web/src/pages/search-explore-page/components/desktop/SearchExplorePage.tsx @@ -24,6 +24,7 @@ import { useSearchParams } from 'react-router' import { useDebounce, useEffectOnce, usePrevious } from 'react-use' import { MIN_DESKTOP_CONTENT_WIDTH_PX } from 'common/utils/layout' +import { DiscoverWeeklyBanner } from 'components/discover-weekly' import { Header } from 'components/header/desktop/Header' import Page from 'components/page/Page' import { Tab, TabList } from 'components/tabs' @@ -40,7 +41,6 @@ import { CategoryView } from 'pages/search-page/types' import { ArtistSpotlightSection } from './ArtistSpotlightSection' import { BestSellingAlbumsSection } from './BestSellingAlbumsSection' -import { DiscoverWeeklySection } from './DiscoverWeeklySection' import { FanClubsExploreSection } from './FanClubsExploreSection' import { FeaturedPlaylistsSection } from './FeaturedPlaylistsSection' import { FeaturedRemixContestsSection } from './FeaturedRemixContestsSection' @@ -177,6 +177,11 @@ const SearchExplorePage = ({ shouldRender: boolean element: ReactNode }[] = [ + { + key: 'discoverWeekly', + shouldRender: showTrackContent && showUserContextualContent, + element: + }, { key: 'featuredPlaylists', shouldRender: showPlaylistContent, @@ -222,11 +227,6 @@ const SearchExplorePage = ({ shouldRender: showTrackContent && showUserContextualContent, element: }, - { - key: 'discoverWeekly', - shouldRender: showTrackContent && showUserContextualContent, - element: - }, { key: 'undergroundTrendingTracks', shouldRender: isTracksTab, diff --git a/packages/web/src/pages/search-explore-page/components/mobile/SearchExplorePage.tsx b/packages/web/src/pages/search-explore-page/components/mobile/SearchExplorePage.tsx index 1229ae34c2a..1271eda816e 100644 --- a/packages/web/src/pages/search-explore-page/components/mobile/SearchExplorePage.tsx +++ b/packages/web/src/pages/search-explore-page/components/mobile/SearchExplorePage.tsx @@ -22,6 +22,7 @@ import { capitalize } from 'lodash' import { useSearchParams } from 'react-router' import { useDebounce, usePrevious } from 'react-use' +import { DiscoverWeeklyBanner } from 'components/discover-weekly' import Header from 'components/header/mobile/Header' import { HeaderContext } from 'components/header/mobile/HeaderContextProvider' import MobilePageContainer from 'components/mobile-page-container/MobilePageContainer' @@ -36,7 +37,6 @@ import { Category, CategoryKey, CategoryView } from 'pages/search-page/types' import { ArtistSpotlightSection } from '../desktop/ArtistSpotlightSection' import { BestSellingAlbumsSection } from '../desktop/BestSellingAlbumsSection' -import { DiscoverWeeklySection } from '../desktop/DiscoverWeeklySection' import { FanClubsExploreSection } from '../desktop/FanClubsExploreSection' import { FeaturedPlaylistsSection } from '../desktop/FeaturedPlaylistsSection' import { FeaturedRemixContestsSection } from '../desktop/FeaturedRemixContestsSection' @@ -228,12 +228,12 @@ const SearchExplorePage = ({ display: inputValue || showSearchResults ? 'none' : undefined }} > - {isTracksTab ? : null} {showTrackContent && showUserContextualContent ? ( - + ) : null} + {isTracksTab ? : null} {showTrackContent && showUserContextualContent ? ( - + ) : null} {showPlaylistContent ? : null} {showAlbumContent ? : null} From bf8a85da7ed6ef64a12ac5d13d6fcca4803a6f1d Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 24 Aug 2026 15:57:21 -0700 Subject: [PATCH 4/4] feat(mobile): add Discover Weekly play-all, bound the query staleTime Adds a play-all button to the native Discover Weekly screen, mirroring the web page: toggle when already on the first track, otherwise start the queue from the top. Web had one and native didn't. Also bounds the useDiscoverWeekly staleTime. It was Infinity with refetchOnMount: false, which meant a single failed or empty first fetch was permanent for the session -- nothing retried it, and the surfaces that hide themselves on an empty result stayed hidden until restart. The server already caches the mix for hours, so the infinite client staleTime bought nothing and only removed the recovery path. Verified: typecheck and lint clean; web play-all confirmed in the browser (starts playback, queues all 30). The native play-all is NOT verified on device -- the simulator has a Release-scheme build, which per AppDelegate.mm resolves its bundle through CodePush rather than Metro, so it kept executing a stale bundle. Verifying it needs a Dev-scheme build. Co-Authored-By: Claude Opus 5 --- .../tan-query/lineups/useDiscoverWeekly.ts | 15 +++-- .../DiscoverWeeklyScreen.tsx | 67 ++++++++++++++++++- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/packages/common/src/api/tan-query/lineups/useDiscoverWeekly.ts b/packages/common/src/api/tan-query/lineups/useDiscoverWeekly.ts index a7ce2b84d7b..e5bdcbe96ba 100644 --- a/packages/common/src/api/tan-query/lineups/useDiscoverWeekly.ts +++ b/packages/common/src/api/tan-query/lineups/useDiscoverWeekly.ts @@ -12,6 +12,11 @@ import { primeTrackData } from '../utils/primeTrackData' const DEFAULT_LIMIT = 30 +// The server recomputes at the ISO week boundary and caches for hours, so +// anything on this order is cheap. Bounded rather than Infinity so a transient +// failure or an empty response doesn't stick for the whole session. +const STALE_TIME_MS = 30 * 60 * 1000 + export type UseDiscoverWeeklyArgs = { limit?: number } @@ -32,8 +37,11 @@ export const getDiscoverWeeklyQueryKey = ({ * fixed-size artifact, not a lineup you scroll. There is no page 2. * * The server holds the mix constant for the ISO week, so the client cache can - * be long-lived; the staleness that matters is the week boundary, not minutes. - * Refetch-on-mount is left off for the same reason. + * be long-lived -- but NOT infinite. With staleTime: Infinity and + * refetchOnMount: false, a single failed or empty first fetch was permanent for + * the session: nothing retried it, and the surfaces that hide themselves on an + * empty result stayed hidden until the app restarted. A bounded staleTime keeps + * the request count low while still letting a bad result heal. */ export const useDiscoverWeekly = ( { limit = DEFAULT_LIMIT }: UseDiscoverWeeklyArgs = {}, @@ -59,8 +67,7 @@ export const useDiscoverWeekly = ( type: EntityType.TRACK })) }, - staleTime: Infinity, - refetchOnMount: false, + staleTime: STALE_TIME_MS, ...options, enabled: options?.enabled !== false && !!currentUserId }) diff --git a/packages/mobile/src/screens/discover-weekly-screen/DiscoverWeeklyScreen.tsx b/packages/mobile/src/screens/discover-weekly-screen/DiscoverWeeklyScreen.tsx index e990403a98a..8089b005d85 100644 --- a/packages/mobile/src/screens/discover-weekly-screen/DiscoverWeeklyScreen.tsx +++ b/packages/mobile/src/screens/discover-weekly-screen/DiscoverWeeklyScreen.tsx @@ -1,12 +1,23 @@ -import React, { useEffect, useRef } from 'react' +import React, { useCallback, useEffect, useMemo, useRef } from 'react' import { useDiscoverWeekly } from '@audius/common/api' import { useAnalytics } from '@audius/common/hooks' import { exploreMessages } from '@audius/common/messages' +import type { ID } from '@audius/common/models' import { Name } from '@audius/common/models' +import { playbackActions, playbackSelectors } from '@audius/common/store' +import type { PlaybackTrack } from '@audius/common/store' import { Image } from 'react-native' +import { useDispatch, useSelector } from 'react-redux' -import { Flex, Paper, Text } from '@audius/harmony-native' +import { + Button, + Flex, + IconPause, + IconPlay, + Paper, + Text +} from '@audius/harmony-native' import discoverWeeklyArt from 'app/assets/images/discoverWeekly.jpg' import { Screen, ScreenContent } from 'app/components/core' import { TrackLineup } from 'app/components/lineup/TrackLineup' @@ -16,6 +27,7 @@ const messages = { } const ART_SIZE = 120 +const DISCOVER_WEEKLY_SOURCE = 'DISCOVER_WEEKLY_TRACKS' /** * The full Discover Weekly mix. Mirrors the web page: artwork header, then the @@ -27,6 +39,48 @@ const ART_SIZE = 120 export const DiscoverWeeklyScreen = () => { const { trackIds, isPending, isFetching } = useDiscoverWeekly({ limit: 30 }) const { trackEvent } = useAnalytics() + const dispatch = useDispatch() + + const isPlaying = useSelector(playbackSelectors.getPlaying) + const currentPlaybackTrackId = useSelector( + playbackSelectors.getCurrentTrackId + ) + + const playbackQueue: PlaybackTrack[] = useMemo( + () => + trackIds.map((id) => ({ + trackId: id, + source: DISCOVER_WEEKLY_SOURCE + })), + [trackIds] + ) + + // Mirrors the web page's play-all: toggle when we're already on the first + // track, otherwise start the queue from the top. + const handlePlay = useCallback(() => { + if (playbackQueue.length === 0) return + const firstId = playbackQueue[0].trackId as ID + + if (currentPlaybackTrackId === firstId) { + dispatch( + isPlaying ? playbackActions.togglePlay() : playbackActions.play() + ) + return + } + + trackEvent({ + eventName: Name.DISCOVER_WEEKLY_PLAY_ALL, + source: 'mobile', + trackCount: playbackQueue.length + }) + dispatch( + playbackActions.playFrom({ + tracks: playbackQueue, + startIndex: 0, + querySource: null + }) + ) + }, [dispatch, isPlaying, currentPlaybackTrackId, playbackQueue, trackEvent]) // Fired once the mix resolves, so trackCount is real and a failed load // doesn't register as a page view. @@ -62,6 +116,15 @@ export const DiscoverWeeklyScreen = () => { {exploreMessages.discoverWeeklyTrackCount(trackIds.length)} ) : null} +