diff --git a/.changeset/young-dryers-grab.md b/.changeset/young-dryers-grab.md new file mode 100644 index 00000000000..9a81cc703fd --- /dev/null +++ b/.changeset/young-dryers-grab.md @@ -0,0 +1,5 @@ +--- +"@audius/sdk": patch +--- + +Add/update user should use CID for photo/cover art diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml index 5b40cc2f82c..65f1e054c41 100644 --- a/.github/workflows/mobile.yml +++ b/.github/workflows/mobile.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - mobile-app-fix paths: - 'packages/mobile/**' - 'packages/common/**' @@ -93,7 +94,7 @@ jobs: name: iOS Release Candidate Build & Upload runs-on: macos-15 needs: mobile-init - if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/mobile-app-fix') && github.event_name != 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 @@ -261,7 +262,7 @@ jobs: name: Android Release Candidate Build & Upload runs-on: ubuntu-latest needs: mobile-init - if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/mobile-app-fix') && github.event_name != 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 @@ -471,7 +472,7 @@ jobs: name: iOS Production Build & Upload runs-on: macos-15 needs: mobile-init - if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/mobile-app-fix') && github.event_name != 'pull_request' environment: name: mobile-production-ios url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} @@ -632,7 +633,7 @@ jobs: name: Android Production Build & Upload runs-on: ubuntu-latest needs: mobile-init - if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/mobile-app-fix') && github.event_name != 'pull_request' environment: name: mobile-production-android url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/packages/common/src/api/tan-query/users/useUnfollowUser.ts b/packages/common/src/api/tan-query/users/useUnfollowUser.ts index bb7a1f4ab9e..474b3fbaecd 100644 --- a/packages/common/src/api/tan-query/users/useUnfollowUser.ts +++ b/packages/common/src/api/tan-query/users/useUnfollowUser.ts @@ -9,7 +9,6 @@ import { Feature } from '~/models/ErrorReporting' import { ID } from '~/models/Identifiers' import { UserMetadata } from '~/models/User' import { removeFolloweeId } from '~/store/gated-content/slice' -import { revokeFollowGatedAccess } from '~/store/tipping/slice' import { primeUserData } from '../utils/primeUserData' @@ -49,9 +48,6 @@ export const useUnfollowUser = () => { // Handle gated content dispatch(removeFolloweeId({ id: followeeUserId })) - dispatch(revokeFollowGatedAccess({ userId: followeeUserId })) - - // Track the unfollow if (source) { track( make({ diff --git a/packages/common/src/store/pages/trending/actions.ts b/packages/common/src/store/pages/trending/actions.ts index 76a6dcea4b7..d91a0c18cee 100644 --- a/packages/common/src/store/pages/trending/actions.ts +++ b/packages/common/src/store/pages/trending/actions.ts @@ -2,11 +2,8 @@ import { Genre } from '~/utils' import { TimeRange } from '../../../models' -import type { TrendingCategory } from './types' - export const SET_TRENDING_GENRE = 'TRENDING/SET_TRENDING_GENRE' export const SET_TRENDING_TIME_RANGE = 'TRENDING/SET_TRENDING_TIME_RANGE' -export const SET_TRENDING_CATEGORY = 'TRENDING/SET_TRENDING_CATEGORY' export const SET_LAST_FETCHED_TRENDING_GENRE = 'TRENDING/SET_LAST_FETCHED_TRENDING_GENRE' @@ -20,11 +17,6 @@ export type SetTrendingTimeRangeAction = { timeRange: TimeRange } -export type SetTrendingCategoryAction = { - type: typeof SET_TRENDING_CATEGORY - category: TrendingCategory -} - export type SetLastFetchedTrendingGenreAction = { type: typeof SET_LAST_FETCHED_TRENDING_GENRE genre: Genre | null @@ -33,7 +25,6 @@ export type SetLastFetchedTrendingGenreAction = { export type TrendingPageAction = | SetTrendingGenreAction | SetTrendingTimeRangeAction - | SetTrendingCategoryAction | SetLastFetchedTrendingGenreAction export const setTrendingGenre = (genre: Genre | null) => ({ @@ -41,11 +32,6 @@ export const setTrendingGenre = (genre: Genre | null) => ({ genre }) -export const setTrendingCategory = (category: TrendingCategory) => ({ - type: SET_TRENDING_CATEGORY, - category -}) - export const setTrendingTimeRange = (timeRange: TimeRange) => ({ type: SET_TRENDING_TIME_RANGE, timeRange diff --git a/packages/common/src/store/pages/trending/reducer.ts b/packages/common/src/store/pages/trending/reducer.ts index 2a2b6e831c7..55d4efb9b12 100644 --- a/packages/common/src/store/pages/trending/reducer.ts +++ b/packages/common/src/store/pages/trending/reducer.ts @@ -4,11 +4,9 @@ import { LineupActions, asLineup } from '~/store/lineup/reducer' import { SET_TRENDING_GENRE, SET_TRENDING_TIME_RANGE, - SET_TRENDING_CATEGORY, SET_LAST_FETCHED_TRENDING_GENRE, SetTrendingGenreAction, SetTrendingTimeRangeAction, - SetTrendingCategoryAction, SetLastFetchedTrendingGenreAction, TrendingPageAction } from '~/store/pages/trending/actions' @@ -39,15 +37,6 @@ const actionsMap = { trendingTimeRange: action.timeRange } }, - [SET_TRENDING_CATEGORY]( - state: TrendingPageState, - action: SetTrendingCategoryAction - ) { - return { - ...state, - trendingCategory: action.category - } - }, [SET_TRENDING_GENRE]( state: TrendingPageState, action: SetTrendingGenreAction @@ -88,8 +77,7 @@ const reducer = trendingMonth: makeInitialState(TRENDING_MONTH_PREFIX), trendingAllTime: makeInitialState(TRENDING_ALL_TIME_PREFIX), trendingGenre: null, - trendingTimeRange: TimeRange.WEEK, - trendingCategory: 'tracks' + trendingTimeRange: TimeRange.WEEK } if (history) { @@ -142,11 +130,6 @@ const reducer = state, action as SetTrendingTimeRangeAction ) - case SET_TRENDING_CATEGORY: - return actionsMap[SET_TRENDING_CATEGORY]( - state, - action as SetTrendingCategoryAction - ) case SET_LAST_FETCHED_TRENDING_GENRE: return actionsMap[SET_LAST_FETCHED_TRENDING_GENRE]( state, diff --git a/packages/common/src/store/pages/trending/selectors.ts b/packages/common/src/store/pages/trending/selectors.ts index 68a208a3ad0..aca88d81827 100644 --- a/packages/common/src/store/pages/trending/selectors.ts +++ b/packages/common/src/store/pages/trending/selectors.ts @@ -31,8 +31,5 @@ export const getTrendingTimeRange = (state: CommonState) => export const getTrendingGenre = (state: CommonState) => state.pages.trending.trendingGenre -export const getTrendingCategory = (state: CommonState) => - state.pages.trending.trendingCategory - export const getLastFetchedTrendingGenre = (state: CommonState) => state.pages.trending.lastFetchedTrendingGenre diff --git a/packages/common/src/store/pages/trending/types.ts b/packages/common/src/store/pages/trending/types.ts index c6aa7b9f934..0de1a4121c5 100644 --- a/packages/common/src/store/pages/trending/types.ts +++ b/packages/common/src/store/pages/trending/types.ts @@ -2,8 +2,6 @@ import { Genre } from '~/utils' import { LineupState, TimeRange, Track } from '../../../models' -export type TrendingCategory = 'tracks' | 'underground' - export type TrendingPageState = { trendingWeek: LineupState trendingMonth: LineupState @@ -11,6 +9,4 @@ export type TrendingPageState = { trendingTimeRange: TimeRange trendingGenre: Genre | null lastFetchedTrendingGenre: Genre | null - /** Mobile: selected tab for trending (Tracks vs Underground). */ - trendingCategory: TrendingCategory } diff --git a/packages/common/src/store/ui/modals/parentSlice.ts b/packages/common/src/store/ui/modals/parentSlice.ts index 068c787155d..2bf8ac9daf2 100644 --- a/packages/common/src/store/ui/modals/parentSlice.ts +++ b/packages/common/src/store/ui/modals/parentSlice.ts @@ -24,8 +24,6 @@ export const initialState: BasicModalsState = { FeedFilter: { isOpen: false }, PurchaseVendor: { isOpen: false }, TrendingGenreSelection: { isOpen: false }, - TrendingCategory: { isOpen: false }, - TrendingTimeRange: { isOpen: false }, TrendingRewardsExplainer: { isOpen: false }, SocialProof: { isOpen: false }, EditFolder: { isOpen: false }, diff --git a/packages/common/src/store/ui/modals/types.ts b/packages/common/src/store/ui/modals/types.ts index 1231fb3dda7..04a4dfb5814 100644 --- a/packages/common/src/store/ui/modals/types.ts +++ b/packages/common/src/store/ui/modals/types.ts @@ -59,8 +59,6 @@ export type Modals = | 'FeedFilter' | 'PurchaseVendor' | 'TrendingGenreSelection' - | 'TrendingCategory' - | 'TrendingTimeRange' | 'TrendingRewardsExplainer' | 'SocialProof' | 'EditFolder' diff --git a/packages/discovery-provider/integration_tests/queries/test_get_sitemap.py b/packages/discovery-provider/integration_tests/queries/test_get_sitemap.py index 8a5d64b1741..23a85f3812c 100644 --- a/packages/discovery-provider/integration_tests/queries/test_get_sitemap.py +++ b/packages/discovery-provider/integration_tests/queries/test_get_sitemap.py @@ -72,7 +72,7 @@ def test_get_sitemaps(mock_get_base_url, app): default_sitemap = build_default() assert ( default_sitemap - == b'\n \n https://audius.co/legal/privacy-policy\n \n \n https://audius.co/legal/terms-of-use\n \n \n https://audius.co/download\n \n \n https://audius.co/feed\n \n \n https://audius.co/trending\n \n \n https://audius.co/explore\n \n \n https://audius.co/upload\n \n \n https://audius.co/favorites\n \n \n https://audius.co/history\n \n \n https://audius.co/messages\n \n \n https://audius.co/dashboard\n \n \n https://audius.co/explore/playlists\n \n \n https://audius.co/explore/top-albums\n \n \n https://audius.co/explore/remixables\n \n \n https://audius.co/explore/feeling-lucky\n \n \n https://audius.co/explore/chill\n \n \n https://audius.co/explore/upbeat\n \n \n https://audius.co/explore/intense\n \n \n https://audius.co/explore/provoking\n \n \n https://audius.co/explore/intimate\n \n \n https://audius.co/signup\n \n \n https://audius.co/signin\n \n \n https://audius.co/audio\n \n \n https://audius.co/settings\n \n\n' + == b'\n \n https://audius.co/legal/privacy-policy\n \n \n https://audius.co/legal/terms-of-use\n \n \n https://audius.co/download\n \n \n https://audius.co/feed\n \n \n https://audius.co/trending\n \n \n https://audius.co/explore\n \n \n https://audius.co/upload\n \n \n https://audius.co/favorites\n \n \n https://audius.co/history\n \n \n https://audius.co/messages\n \n \n https://audius.co/dashboard\n \n \n https://audius.co/explore/playlists\n \n \n https://audius.co/explore/underground\n \n \n https://audius.co/explore/top-albums\n \n \n https://audius.co/explore/remixables\n \n \n https://audius.co/explore/feeling-lucky\n \n \n https://audius.co/explore/chill\n \n \n https://audius.co/explore/upbeat\n \n \n https://audius.co/explore/intense\n \n \n https://audius.co/explore/provoking\n \n \n https://audius.co/explore/intimate\n \n \n https://audius.co/signup\n \n \n https://audius.co/signin\n \n \n https://audius.co/audio\n \n \n https://audius.co/settings\n \n\n' ) # Validate that there are 7 track sitemaps - 10 total track / 3 user per sitemap = 4 diff --git a/packages/discovery-provider/src/queries/get_sitemap.py b/packages/discovery-provider/src/queries/get_sitemap.py index 4c4b8a5fc08..c57b439de47 100644 --- a/packages/discovery-provider/src/queries/get_sitemap.py +++ b/packages/discovery-provider/src/queries/get_sitemap.py @@ -63,6 +63,7 @@ def create_xml_url(route): "messages", "dashboard", "explore/playlists", + "explore/underground", "explore/top-albums", "explore/remixables", "explore/feeling-lucky", diff --git a/packages/harmony/src/assets/icons/Leading.svg b/packages/harmony/src/assets/icons/Leading.svg deleted file mode 100644 index 038cb12bada..00000000000 --- a/packages/harmony/src/assets/icons/Leading.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/mobile/src/app/Drawers.tsx b/packages/mobile/src/app/Drawers.tsx index 11d837ce028..e4f580f306b 100644 --- a/packages/mobile/src/app/Drawers.tsx +++ b/packages/mobile/src/app/Drawers.tsx @@ -54,11 +54,7 @@ import { PublishConfirmationDrawer } from 'app/screens/edit-track-screen/compone import { ConnectNewWalletDrawer } from 'app/screens/external-wallets/components/ConnectNewWalletDrawer' import { WelcomeDrawer } from 'app/screens/sign-on-screen/components/WelcomeDrawer' import { PickWinnersDrawer } from 'app/screens/track-screen/PickWinnersDrawer' -import { - TrendingCategoryDrawer, - TrendingFilterDrawer, - TrendingTimeRangeDrawer -} from 'app/screens/trending-screen' +import { TrendingFilterDrawer } from 'app/screens/trending-screen' import { WalletRowOverflowMenu } from 'app/screens/wallet-screen/components/LinkedWallets' import { useDrawerState } from '../components/drawer' @@ -117,8 +113,6 @@ const commonDrawersMap: { [Modal in Modals]?: ComponentType } = { DeactivateAccountConfirmation: DeactivateAccountConfirmationDrawer, FeedFilter: FeedFilterDrawer, TrendingGenreSelection: TrendingFilterDrawer, - TrendingCategory: TrendingCategoryDrawer, - TrendingTimeRange: TrendingTimeRangeDrawer, Overflow: OverflowMenuDrawer, SignOutConfirmation: SignOutConfirmationDrawer, AddToCollection: AddToCollectionDrawer, diff --git a/packages/mobile/src/components/navigation-container/NavigationContainer.tsx b/packages/mobile/src/components/navigation-container/NavigationContainer.tsx index 40910d7b6e2..03b61d577e0 100644 --- a/packages/mobile/src/components/navigation-container/NavigationContainer.tsx +++ b/packages/mobile/src/components/navigation-container/NavigationContainer.tsx @@ -203,6 +203,7 @@ const NavigationContainer = (props: NavigationContainerProps) => { screens: { Explore: 'explore', PremiumTracks: 'explore/premium-tracks', + TrendingUnderground: 'explore/underground', LetThemDJ: 'explore/let-them-dj', TopAlbums: 'explore/top-albums', UnderTheRadar: 'explore/under-the-radar', diff --git a/packages/mobile/src/components/trending-dropdown-button/TrendingDropdownButton.tsx b/packages/mobile/src/components/trending-dropdown-button/TrendingDropdownButton.tsx deleted file mode 100644 index 3544223f6c4..00000000000 --- a/packages/mobile/src/components/trending-dropdown-button/TrendingDropdownButton.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import type { GestureResponderEvent } from 'react-native' -import { Pressable } from 'react-native' - -import { IconCaretDown, Text } from '@audius/harmony-native' -import { makeStyles } from 'app/styles' - -type TrendingDropdownButtonProps = { - label: string - onPress: (e: GestureResponderEvent) => void -} - -const useStyles = makeStyles(({ palette, spacing, typography }) => ({ - button: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - gap: spacing(2), - height: spacing(8), - paddingHorizontal: spacing(4), - backgroundColor: palette.white, - borderWidth: 1, - borderColor: palette.neutralLight8, - borderRadius: spacing(4) - }, - label: { - fontSize: typography.fontSize.small, - fontWeight: '600' - } -})) - -export const TrendingDropdownButton = (props: TrendingDropdownButtonProps) => { - const { label, onPress } = props - const styles = useStyles() - - return ( - - - {label} - - - - ) -} diff --git a/packages/mobile/src/components/trending-dropdown-button/index.ts b/packages/mobile/src/components/trending-dropdown-button/index.ts deleted file mode 100644 index 571d9139bd4..00000000000 --- a/packages/mobile/src/components/trending-dropdown-button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { TrendingDropdownButton } from './TrendingDropdownButton' diff --git a/packages/mobile/src/components/trending-rewards-drawer/TrendingRewardsDrawer.tsx b/packages/mobile/src/components/trending-rewards-drawer/TrendingRewardsDrawer.tsx index e3dbeb9828f..ff5287b14b6 100644 --- a/packages/mobile/src/components/trending-rewards-drawer/TrendingRewardsDrawer.tsx +++ b/packages/mobile/src/components/trending-rewards-drawer/TrendingRewardsDrawer.tsx @@ -180,7 +180,7 @@ export const TrendingRewardsDrawer = (titleIcon) => { break } case 'underground': { - navigation.navigate('trending', { screen: 'Trending' }) + navigation.navigate('explore', { screen: 'TrendingUnderground' }) break } } diff --git a/packages/mobile/src/screens/app-screen/ExploreTabScreen.tsx b/packages/mobile/src/screens/app-screen/ExploreTabScreen.tsx index 1b30c7a67ce..7e1ca1dfd22 100644 --- a/packages/mobile/src/screens/app-screen/ExploreTabScreen.tsx +++ b/packages/mobile/src/screens/app-screen/ExploreTabScreen.tsx @@ -1,6 +1,7 @@ import type { SearchCategory, SearchFilters } from '@audius/common/api' import { SearchExploreScreen } from '../explore-screen/SearchExploreScreen' +import { TrendingUndergroundScreen } from '../explore-screen/tabs/ForYouTab/TrendingUndergroundScreen' import type { AppTabScreenParamList } from './AppTabScreen' import { createAppTabScreenStack } from './createAppTabScreenStack' @@ -12,6 +13,7 @@ export type ExploreTabScreenParamList = AppTabScreenParamList & { category?: SearchCategory filters?: SearchFilters } + TrendingUnderground: undefined } export const ExploreTabScreen = @@ -19,6 +21,10 @@ export const ExploreTabScreen = return ( <> + ) }) diff --git a/packages/mobile/src/screens/explore-screen/collections.ts b/packages/mobile/src/screens/explore-screen/collections.ts index 22ed98d5d1a..d8d2d9a08aa 100644 --- a/packages/mobile/src/screens/explore-screen/collections.ts +++ b/packages/mobile/src/screens/explore-screen/collections.ts @@ -4,6 +4,7 @@ import type { ImageSourcePropType } from 'react-native' import type { SvgProps } from 'react-native-svg' import { IconCart } from '@audius/harmony-native' +import IconCassette from 'app/assets/images/iconCassette.svg' export type ExploreCollection = { title: string @@ -31,3 +32,15 @@ export const PREMIUM_TRACKS: ExploreCollection = { shadowOpacity: 0.25, icon: IconCart } + +export const TRENDING_UNDERGROUND: ExploreCollection = { + title: 'Underground Trending', + description: + 'Some of the best up-and-coming music on Audius all in one place', + gradientColors: ['#BA27FF', '#EF8CD9'], + gradientAngle: 315, + shadowColor: 'rgb(242,87,255)', + shadowOpacity: 0.25, + icon: IconCassette, + incentivized: true +} diff --git a/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx b/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx index eeea2bdf428..8217d6c6a99 100644 --- a/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx +++ b/packages/mobile/src/screens/explore-screen/components/ExploreContent.tsx @@ -14,6 +14,7 @@ import { FeelingLucky } from './FeelingLucky' import { ForYouTracks } from './ForYouTracks' import { LabelSpotlight } from './LabelSpotlight' import { RecentlyPlayedTracks } from './RecentlyPlayed' +import { UndergroundTrendingTracks } from './UndergroundTrendingTracks' export const ExploreContent = () => { const [category] = useSearchCategory() @@ -34,6 +35,7 @@ export const ExploreContent = () => { )} {showPlaylistContent && } {showTrackContent && } + {showTrackContent && } {showUserContent && } {showUserContent && } {showTrackContent && showUserContextualContent && } diff --git a/packages/mobile/src/screens/explore-screen/components/UndergroundTrendingTracks.tsx b/packages/mobile/src/screens/explore-screen/components/UndergroundTrendingTracks.tsx new file mode 100644 index 00000000000..60976bc9e1b --- /dev/null +++ b/packages/mobile/src/screens/explore-screen/components/UndergroundTrendingTracks.tsx @@ -0,0 +1,37 @@ +import React, { useMemo } from 'react' + +import { useTrendingUnderground } from '@audius/common/api' +import { exploreMessages as messages } from '@audius/common/messages' +import { QueueSource } from '@audius/common/store' + +import { useDeferredElement } from '../../../hooks/useDeferredElement' + +import { ExploreSection } from './ExploreSection' +import { TrackTileCarousel } from './TrackTileCarousel' + +export const UndergroundTrendingTracks = () => { + const { inView, InViewWrapper } = useDeferredElement() + const { data: undergroundTrendingTracks, isPending } = useTrendingUnderground( + { pageSize: 10 }, + { enabled: inView } + ) + + const trackIds = useMemo(() => { + return undergroundTrendingTracks?.map(({ id }) => id) ?? [] + }, [undergroundTrendingTracks]) + + return ( + + + + + + ) +} diff --git a/packages/mobile/src/screens/explore-screen/tabs/ForYouTab/TrendingUndergroundScreen.tsx b/packages/mobile/src/screens/explore-screen/tabs/ForYouTab/TrendingUndergroundScreen.tsx new file mode 100644 index 00000000000..ebca746c107 --- /dev/null +++ b/packages/mobile/src/screens/explore-screen/tabs/ForYouTab/TrendingUndergroundScreen.tsx @@ -0,0 +1,36 @@ +import { + lineupSelectors, + trendingUndergroundPageLineupSelectors, + trendingUndergroundPageLineupActions +} from '@audius/common/store' +import { useSelector } from 'react-redux' + +import { Screen, ScreenContent, ScreenHeader } from 'app/components/core' +import { Lineup } from 'app/components/lineup' +const { makeGetLineupMetadatas } = lineupSelectors +const { getLineup } = trendingUndergroundPageLineupSelectors + +const getTrendingUndergroundLineup = makeGetLineupMetadatas(getLineup) + +const messages = { + header: 'Underground Trending' +} + +export const TrendingUndergroundScreen = () => { + const lineup = useSelector(getTrendingUndergroundLineup) + + return ( + + + + + + + ) +} diff --git a/packages/mobile/src/screens/trending-screen/TrendingCategoryDrawer.tsx b/packages/mobile/src/screens/trending-screen/TrendingCategoryDrawer.tsx deleted file mode 100644 index 5182b68f37e..00000000000 --- a/packages/mobile/src/screens/trending-screen/TrendingCategoryDrawer.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { useCallback } from 'react' - -import { modalsActions, trendingPageActions } from '@audius/common/store' -import { useDispatch } from 'react-redux' - -import ActionDrawer from 'app/components/action-drawer/ActionDrawer' - -export const TRENDING_CATEGORY_MODAL = 'TrendingCategory' as const - -const messages = { - tracks: 'Tracks', - underground: 'Underground' -} - -export const TrendingCategoryDrawer = () => { - const dispatch = useDispatch() - - const handleSelect = useCallback( - (category: 'tracks' | 'underground') => () => { - dispatch( - modalsActions.setVisibility({ - modal: TRENDING_CATEGORY_MODAL, - visible: false - }) - ) - dispatch(trendingPageActions.setTrendingCategory(category)) - }, - [dispatch] - ) - - const rows = [ - { text: messages.tracks, callback: handleSelect('tracks') }, - { text: messages.underground, callback: handleSelect('underground') } - ] - - return -} diff --git a/packages/mobile/src/screens/trending-screen/TrendingFilterButton.tsx b/packages/mobile/src/screens/trending-screen/TrendingFilterButton.tsx index 367127f680b..a859d279458 100644 --- a/packages/mobile/src/screens/trending-screen/TrendingFilterButton.tsx +++ b/packages/mobile/src/screens/trending-screen/TrendingFilterButton.tsx @@ -1,30 +1,22 @@ import { useCallback } from 'react' -import { modalsActions, trendingPageSelectors } from '@audius/common/store' +import { trendingPageSelectors, modalsActions } from '@audius/common/store' import { Genre } from '@audius/common/utils' import { useDispatch, useSelector } from 'react-redux' -import { FilterButton } from '@audius/harmony-native' +import { ScreenHeaderButton } from 'app/components/core' import { MODAL_NAME } from './TrendingFilterDrawer' - const { getTrendingGenre } = trendingPageSelectors const { setVisibility } = modalsActions export const TrendingFilterButton = () => { - const dispatch = useDispatch() + const dispatchWeb = useDispatch() const trendingGenre = useSelector(getTrendingGenre) ?? Genre.ALL const handlePress = useCallback(() => { - dispatch(setVisibility({ modal: MODAL_NAME, visible: true })) - }, [dispatch]) + dispatchWeb(setVisibility({ modal: MODAL_NAME, visible: true })) + }, [dispatchWeb]) - return ( - - ) + return } diff --git a/packages/mobile/src/screens/trending-screen/TrendingFilterRow.tsx b/packages/mobile/src/screens/trending-screen/TrendingFilterRow.tsx deleted file mode 100644 index 001428e66aa..00000000000 --- a/packages/mobile/src/screens/trending-screen/TrendingFilterRow.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useCallback } from 'react' - -import { TimeRange } from '@audius/common/models' -import { modalsActions, trendingPageSelectors } from '@audius/common/store' -import { View } from 'react-native' -import { useDispatch, useSelector } from 'react-redux' - -import { Flex } from '@audius/harmony-native' -import { TrendingDropdownButton } from 'app/components/trending-dropdown-button' -import { makeStyles } from 'app/styles' - -import { TrendingGenrePill } from './TrendingGenrePill' -import { TRENDING_TIME_RANGE_MODAL } from './TrendingTimeRangeDrawer' - -const { getTrendingTimeRange } = trendingPageSelectors -const { setVisibility } = modalsActions - -const timeRangeLabels: Record = { - [TimeRange.WEEK]: 'This Week', - [TimeRange.MONTH]: 'This Month', - [TimeRange.ALL_TIME]: 'All Time' -} - -const useStyles = makeStyles(({ palette, spacing }) => ({ - row: { - flexDirection: 'row', - alignItems: 'center', - paddingHorizontal: spacing(4), - paddingVertical: spacing(3), - gap: spacing(2), - borderBottomWidth: 1, - borderBottomColor: palette.neutralLight8, - backgroundColor: palette.white - } -})) - -export const TrendingFilterRow = () => { - const styles = useStyles() - const dispatch = useDispatch() - const timeRange = useSelector(getTrendingTimeRange) ?? TimeRange.WEEK - - const handleOpenTimeRangeDrawer = useCallback(() => { - dispatch(setVisibility({ modal: TRENDING_TIME_RANGE_MODAL, visible: true })) - }, [dispatch]) - - return ( - - - - - - - ) -} diff --git a/packages/mobile/src/screens/trending-screen/TrendingGenrePill.tsx b/packages/mobile/src/screens/trending-screen/TrendingGenrePill.tsx deleted file mode 100644 index 424c455ebd1..00000000000 --- a/packages/mobile/src/screens/trending-screen/TrendingGenrePill.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { useCallback } from 'react' - -import { - modalsActions, - trendingPageActions, - trendingPageLineupActions, - trendingPageSelectors -} from '@audius/common/store' -import { Genre } from '@audius/common/utils' -import { useDispatch, useSelector } from 'react-redux' - -import { IconCloseAlt, SelectablePill } from '@audius/harmony-native' - -import { MODAL_NAME } from './TrendingFilterDrawer' - -const { getTrendingGenre } = trendingPageSelectors -const { setTrendingGenre } = trendingPageActions -const { setVisibility } = modalsActions -const { trendingWeekActions, trendingMonthActions, trendingAllTimeActions } = - trendingPageLineupActions - -export const TrendingGenrePill = () => { - const dispatch = useDispatch() - const genre = useSelector(getTrendingGenre) ?? Genre.ALL - - const isSelected = genre !== Genre.ALL - - const handlePress = useCallback(() => { - if (genre === Genre.ALL) { - dispatch(setVisibility({ modal: MODAL_NAME, visible: true })) - } - }, [dispatch, genre]) - - const handleChange = useCallback( - (_value: string, selected: boolean) => { - if (!selected) { - dispatch(setTrendingGenre(null)) - dispatch(trendingWeekActions.reset()) - dispatch(trendingMonthActions.reset()) - dispatch(trendingAllTimeActions.reset()) - } - }, - [dispatch] - ) - - return ( - - ) -} diff --git a/packages/mobile/src/screens/trending-screen/TrendingScreen.tsx b/packages/mobile/src/screens/trending-screen/TrendingScreen.tsx index dd9f330cf5e..def624de7c7 100644 --- a/packages/mobile/src/screens/trending-screen/TrendingScreen.tsx +++ b/packages/mobile/src/screens/trending-screen/TrendingScreen.tsx @@ -1,60 +1,66 @@ -import { useCallback } from 'react' +import { TimeRange } from '@audius/common/models' -import { modalsActions, trendingPageSelectors } from '@audius/common/store' -import { useDispatch, useSelector } from 'react-redux' - -import { IconTrending } from '@audius/harmony-native' +import { + IconAllTime, + IconCalendarDay, + IconCalendarMonth, + IconTrending +} from '@audius/harmony-native' import { Screen, ScreenContent, ScreenHeader } from 'app/components/core' import { ScreenPrimaryContent } from 'app/components/core/Screen/ScreenPrimaryContent' import { ScreenSecondaryContent } from 'app/components/core/Screen/ScreenSecondaryContent' -import { TrendingDropdownButton } from 'app/components/trending-dropdown-button' +import { TopTabNavigator } from 'app/components/top-tab-bar' import { useAppTabScreen } from 'app/hooks/useAppTabScreen' -import { TRENDING_CATEGORY_MODAL } from './TrendingCategoryDrawer' -import { TrendingFilterRow } from './TrendingFilterRow' -import { TrendingTracksLineup } from './TrendingTracksLineup' -import { TrendingUndergroundLineup } from './TrendingUndergroundLineup' +import { TrendingFilterButton } from './TrendingFilterButton' +import { TrendingLineup } from './TrendingLineup' + +const ThisWeekTab = () => { + return +} +const ThisMonthTab = () => { + return +} -const { getTrendingCategory } = trendingPageSelectors -const { setVisibility } = modalsActions +const AllTimeTab = () => { + return +} -const categoryLabels = { - tracks: 'Tracks', - underground: 'Underground' -} as const +const trendingScreens = [ + { + name: 'This Week', + Icon: IconCalendarDay, + component: ThisWeekTab + }, + { + name: 'This Month', + Icon: IconCalendarMonth, + component: ThisMonthTab + }, + { + name: 'All Time', + Icon: IconAllTime, + component: AllTimeTab + } +] export const TrendingScreen = () => { useAppTabScreen() - const dispatch = useDispatch() - const category = useSelector(getTrendingCategory) ?? 'tracks' - - const handleOpenCategoryDrawer = useCallback(() => { - dispatch(setVisibility({ modal: TRENDING_CATEGORY_MODAL, visible: true })) - }, [dispatch]) return ( - + - {category === 'tracks' ? ( - <> - - - - - - ) : ( - - - - )} + + + ) diff --git a/packages/mobile/src/screens/trending-screen/TrendingTimeRangeDrawer.tsx b/packages/mobile/src/screens/trending-screen/TrendingTimeRangeDrawer.tsx deleted file mode 100644 index 4478b55caf6..00000000000 --- a/packages/mobile/src/screens/trending-screen/TrendingTimeRangeDrawer.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { useCallback } from 'react' - -import { TimeRange } from '@audius/common/models' -import { modalsActions, trendingPageActions } from '@audius/common/store' -import { useDispatch } from 'react-redux' - -import ActionDrawer from 'app/components/action-drawer/ActionDrawer' - -export const TRENDING_TIME_RANGE_MODAL = 'TrendingTimeRange' as const - -const messages = { - thisWeek: 'This Week', - thisMonth: 'This Month', - allTime: 'All Time' -} - -export const TrendingTimeRangeDrawer = () => { - const dispatch = useDispatch() - - const handleSelect = useCallback( - (timeRange: TimeRange) => () => { - dispatch( - modalsActions.setVisibility({ - modal: TRENDING_TIME_RANGE_MODAL, - visible: false - }) - ) - dispatch(trendingPageActions.setTrendingTimeRange(timeRange)) - }, - [dispatch] - ) - - const rows = [ - { text: messages.thisWeek, callback: handleSelect(TimeRange.WEEK) }, - { text: messages.thisMonth, callback: handleSelect(TimeRange.MONTH) }, - { text: messages.allTime, callback: handleSelect(TimeRange.ALL_TIME) } - ] - - return -} diff --git a/packages/mobile/src/screens/trending-screen/TrendingTracksLineup.tsx b/packages/mobile/src/screens/trending-screen/TrendingTracksLineup.tsx deleted file mode 100644 index 3945b4e6e8c..00000000000 --- a/packages/mobile/src/screens/trending-screen/TrendingTracksLineup.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { TimeRange } from '@audius/common/models' -import { trendingPageSelectors } from '@audius/common/store' -import { useSelector } from 'react-redux' - -import { TrendingLineup } from './TrendingLineup' - -const { getTrendingTimeRange } = trendingPageSelectors - -export const TrendingTracksLineup = () => { - const timeRange = useSelector(getTrendingTimeRange) ?? TimeRange.WEEK - - return -} diff --git a/packages/mobile/src/screens/trending-screen/TrendingUndergroundLineup.tsx b/packages/mobile/src/screens/trending-screen/TrendingUndergroundLineup.tsx deleted file mode 100644 index 7ab61aae06d..00000000000 --- a/packages/mobile/src/screens/trending-screen/TrendingUndergroundLineup.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { useCallback, useEffect } from 'react' - -import { - lineupSelectors, - trendingUndergroundPageLineupActions, - trendingUndergroundPageLineupSelectors -} from '@audius/common/store' -import { useDispatch } from 'react-redux' - -import { Lineup } from 'app/components/lineup' - -const { getLineup } = trendingUndergroundPageLineupSelectors -const { makeGetLineupMetadatas } = lineupSelectors - -const getTrendingUndergroundLineup = makeGetLineupMetadatas(getLineup) - -export const TrendingUndergroundLineup = () => { - const dispatch = useDispatch() - - useEffect(() => { - return () => { - dispatch(trendingUndergroundPageLineupActions.reset()) - } - }, [dispatch]) - - const handleLoadMore = useCallback( - (offset: number, limit: number, overwrite: boolean) => { - dispatch( - trendingUndergroundPageLineupActions.fetchLineupMetadatas( - offset, - limit, - overwrite - ) - ) - }, - [dispatch] - ) - - return ( - - ) -} diff --git a/packages/mobile/src/screens/trending-screen/index.ts b/packages/mobile/src/screens/trending-screen/index.ts index d3933a1f883..8301b7ea704 100644 --- a/packages/mobile/src/screens/trending-screen/index.ts +++ b/packages/mobile/src/screens/trending-screen/index.ts @@ -1,4 +1,2 @@ export { TrendingScreen } from './TrendingScreen' export { TrendingFilterDrawer } from './TrendingFilterDrawer' -export { TrendingCategoryDrawer } from './TrendingCategoryDrawer' -export { TrendingTimeRangeDrawer } from './TrendingTimeRangeDrawer' diff --git a/packages/sdk/src/sdk/api/users/UsersApi.ts b/packages/sdk/src/sdk/api/users/UsersApi.ts index cee604a1af1..01e7231e162 100644 --- a/packages/sdk/src/sdk/api/users/UsersApi.ts +++ b/packages/sdk/src/sdk/api/users/UsersApi.ts @@ -140,12 +140,15 @@ export class UsersApi extends GeneratedUsersApi { userId, ...(profilePictureResp ? { - profilePicture: profilePictureResp?.id, - profilePictureSizes: profilePictureResp?.id + profilePicture: profilePictureResp?.orig_file_cid, + profilePictureSizes: profilePictureResp?.orig_file_cid } : {}), ...(coverArtResp - ? { coverPhoto: coverArtResp?.id, coverPhotoSizes: coverArtResp?.id } + ? { + coverPhoto: coverArtResp?.orig_file_cid, + coverPhotoSizes: coverArtResp?.orig_file_cid + } : {}) } @@ -249,12 +252,15 @@ export class UsersApi extends GeneratedUsersApi { ...metadata, ...(profilePictureResp ? { - profilePicture: profilePictureResp?.id, - profilePictureSizes: profilePictureResp?.id + profilePicture: profilePictureResp?.orig_file_cid, + profilePictureSizes: profilePictureResp?.orig_file_cid } : {}), ...(coverArtResp - ? { coverPhoto: coverArtResp?.id, coverPhotoSizes: coverArtResp?.id } + ? { + coverPhoto: coverArtResp?.orig_file_cid, + coverPhotoSizes: coverArtResp?.orig_file_cid + } : {}) }) diff --git a/packages/web/src/app/web-player/WebPlayer.tsx b/packages/web/src/app/web-player/WebPlayer.tsx index e2ab971f82c..9646a3188d8 100644 --- a/packages/web/src/app/web-player/WebPlayer.tsx +++ b/packages/web/src/app/web-player/WebPlayer.tsx @@ -216,6 +216,9 @@ const TrackCommentsPage = lazy(() => ) const TrackPage = lazy(() => import('pages/track-page/TrackPage')) const TrendingPage = lazy(() => import('pages/trending-page/TrendingPage')) +const TrendingUndergroundPage = lazy( + () => import('pages/trending-underground/TrendingUndergroundPage') +) const Visualizer = lazy(() => import('pages/visualizer/Visualizer')) const WalletPage = lazy(() => import('pages/wallet-page').then((m) => ({ default: m.WalletPage })) @@ -819,7 +822,11 @@ const WebPlayer = (props: WebPlayerProps) => { /> } + element={ + + } /> } /> { /> } + element={ + + } /> } /> } {showTrackContent && } + {showTrackContent && } {showUserContent && } {showUserContent && } {showTrackContent && showUserContextualContent && ( diff --git a/packages/web/src/pages/search-explore-page/components/desktop/UndergroundTrendingTracksSection.tsx b/packages/web/src/pages/search-explore-page/components/desktop/UndergroundTrendingTracksSection.tsx new file mode 100644 index 00000000000..ad03c21d18e --- /dev/null +++ b/packages/web/src/pages/search-explore-page/components/desktop/UndergroundTrendingTracksSection.tsx @@ -0,0 +1,53 @@ +import { useMemo } from 'react' + +import { useTrendingUnderground } from '@audius/common/api' +import { exploreMessages as messages } from '@audius/common/messages' +import { Status } from '@audius/common/models' + +import { Carousel } from './Carousel' +import { TilePairs, TileSkeletons } from './TileHelpers' +import { useExploreSectionTracking } from './useExploreSectionTracking' + +export const UndergroundTrendingTracksSection = () => { + const { ref, inView } = useExploreSectionTracking( + 'Underground Trending Tracks' + ) + const { + data: undergroundTrendingTracks, + isLoading, + isError, + isSuccess, + lineup + } = useTrendingUnderground({ pageSize: 10 }, { enabled: inView }) + + const trackIds = useMemo(() => { + return undergroundTrendingTracks.map(({ id }) => id) + }, [undergroundTrendingTracks]) + + if ( + isError || + lineup.status === Status.ERROR || + (isSuccess && + lineup.status === Status.SUCCESS && + lineup.entries.length === 0) + ) { + return null + } + + return ( + + {!inView || + isLoading || + lineup.status === Status.LOADING || + !trackIds.length ? ( + + ) : ( + + )} + + ) +} 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 9901a4b2703..88cd824e0ff 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 @@ -46,6 +46,7 @@ import { LabelSpotlightSection } from '../desktop/LabelSpotlightSection' import { RecentSearchesSection } from '../desktop/RecentSearchesSection' import { RecentlyPlayedSection } from '../desktop/RecentlyPlayedSection' import { RecommendedTracksSection } from '../desktop/RecommendedTracksSection' +import { UndergroundTrendingTracksSection } from '../desktop/UndergroundTrendingTracksSection' export type SearchExplorePageProps = { title: string @@ -244,6 +245,7 @@ const SearchExplorePage = ({ )} {showPlaylistContent && } {showTrackContent && } + {showTrackContent && } {showUserContent && } {showUserContent && } {showTrackContent && showUserContextualContent && ( diff --git a/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.module.css b/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.module.css index 8700a07846a..693449425d7 100644 --- a/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.module.css +++ b/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.module.css @@ -4,6 +4,21 @@ overflow: hidden; } +.tabBody { + /* Should be 1080px, but account for extra room for hover to grow */ + min-width: 400px; + width: calc(100% + 20px); + + /* Compensate for padding of .lineupContainer */ + left: -10px; + top: -10px; +} + +.tabElement { + max-width: 1100px; + overflow: visible; +} + .bannerContainer { margin-bottom: 14px; } 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 b1e42625e16..3de76a6fb77 100644 --- a/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx +++ b/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx @@ -1,31 +1,17 @@ -import { useCallback, useEffect, useRef, useState } from 'react' +import { useCallback, useRef, useState } from 'react' import { Name, Status, TimeRange } from '@audius/common/models' -import { - trendingPageLineupActions, - trendingUndergroundPageLineupActions, - trendingUndergroundPageLineupSelectors -} from '@audius/common/store' -import { - ELECTRONIC_PREFIX, - getCanonicalName, - TRENDING_GENRES -} from '@audius/common/utils' -import { - FilterButton, - Flex, - IconTrending, - SelectablePill -} from '@audius/harmony' -import { useDispatch } from 'react-redux' +import { trendingPageLineupActions } from '@audius/common/store' +import { ELECTRONIC_PREFIX, TRENDING_GENRES } from '@audius/common/utils' +import { IconTrending } from '@audius/harmony' import { make, useRecord } from 'common/store/analytics/actions' import { Header } from 'components/header/desktop/Header' import EndOfLineup from 'components/lineup/EndOfLineup' import Lineup from 'components/lineup/Lineup' -import { useLineupProps } from 'components/lineup/hooks' import { LineupVariant } from 'components/lineup/types' import Page from 'components/page/Page' +import useTabs from 'hooks/useTabs/useTabs' import { TRENDING_MESSAGES } from 'pages/trending-page/constants' import { useTrendingActions } from 'pages/trending-page/hooks/useTrendingActions' import { useTrendingLineups } from 'pages/trending-page/hooks/useTrendingLineups' @@ -33,25 +19,21 @@ import { useTrendingPageCleanup } from 'pages/trending-page/hooks/useTrendingPag import { useTrendingPageState } from 'pages/trending-page/hooks/useTrendingPageState' import { useTrendingUrlParams } from 'pages/trending-page/hooks/useTrendingUrlParams' +import GenreSelectionModal from './GenreSelectionModal' +import { TrendingGenreFilters } from './TrendingGenreFilters' import styles from './TrendingPageContent.module.css' const { trendingAllTimeActions, trendingMonthActions, trendingWeekActions } = trendingPageLineupActions -const { getLineup } = trendingUndergroundPageLineupSelectors const messages = { - tracks: 'Tracks', - underground: 'Underground', thisWeek: 'This Week', thisMonth: 'This Month', allTime: 'All Time', allGenres: 'All Genres', - genres: 'Genres', endOfLineupDescription: "Looks like you've reached the end of this list...", disabledTabTooltip: 'Nothing available' } -type TrendingCategory = 'tracks' | 'underground' - type TrendingPageContentProps = { containerRef?: React.RefObject } @@ -77,31 +59,13 @@ const getRangesToDisable = (timeRange: TimeRange) => { } } -const useTrendingUndergroundLineup = ( - scrollParent: HTMLElement | undefined -) => { - return useLineupProps({ - actions: trendingUndergroundPageLineupActions, - getLineupSelector: getLineup, - variant: LineupVariant.MAIN, - scrollParent: scrollParent ?? undefined, - isTrending: true, - isOrdered: true - }) -} - const TrendingPageContent = ({ containerRef }: TrendingPageContentProps) => { - const dispatch = useDispatch() - const [category, setCategory] = useState('tracks') const trendingPageState = useTrendingPageState() const actions = useTrendingActions() const lineups = useTrendingLineups({ trendingPageState, containerRef: containerRef || undefined }) - const undergroundLineupProps = useTrendingUndergroundLineup( - containerRef?.current ?? undefined - ) useTrendingUrlParams({ trendingPageState, @@ -112,12 +76,6 @@ const TrendingPageContent = ({ containerRef }: TrendingPageContentProps) => { useTrendingPageCleanup({ trendingPageState, actions }) - useEffect(() => { - return () => { - dispatch(trendingUndergroundPageLineupActions.reset()) - } - }, [dispatch]) - const { trendingTitle, pageTitle, trendingDescription } = TRENDING_MESSAGES const { trendingWeek, @@ -254,195 +212,148 @@ const TrendingPageContent = ({ containerRef }: TrendingPageContentProps) => { variant: LineupVariant.MAIN } + const trendingLineups = [ +
+ + } + {...mainLineupProps} + /> +
, +
+ + } + actions={trendingMonthActions} + {...mainLineupProps} + /> +
, +
+ + } + {...mainLineupProps} + /> +
+ ] const record = useRecord() + // Setup tabs + const didChangeTabs = (from: string, to: string) => { + setTrendingTimeRange(to as TimeRange) + scrollToTop(to as TimeRange) + record( + make(Name.TRENDING_CHANGE_VIEW, { + timeframe: to as TimeRange, + genre: trendingGenre || '' + }) + ) + } + + const tabIsDisabled = (timeRange: TimeRange) => + emptyTimeGenreSet.current.has( + getTimeGenreCacheKey(timeRange, trendingGenre) + ) + const { tabs, body } = useTabs({ + isMobile: false, + tabs: [ + { + text: messages.thisWeek, + label: TimeRange.WEEK, + disabled: tabIsDisabled(TimeRange.WEEK) + }, + { + text: messages.thisMonth, + label: TimeRange.MONTH, + disabled: tabIsDisabled(TimeRange.MONTH) + }, + { + text: messages.allTime, + label: TimeRange.ALL_TIME, + disabled: tabIsDisabled(TimeRange.ALL_TIME) + } + ], + selectedTabLabel: trendingTimeRange, + elements: trendingLineups, + didChangeTabsFrom: didChangeTabs, + bodyClassName: styles.tabBody, + elementClassName: styles.tabElement, + interElementSpacing: 100, + disabledTabTooltipText: messages.disabledTabTooltip + }) + const setGenre = useCallback( (genre: string | null) => { setGenreAndRefresh(genre) record( make(Name.TRENDING_CHANGE_VIEW, { timeframe: trendingTimeRange, - genre: genre ?? '' + genre: genre || '' }) ) }, [setGenreAndRefresh, record, trendingTimeRange] ) - const handleTimeRangeChange = useCallback( - (value: string) => { - const timeRange = value as TimeRange - setTrendingTimeRange(timeRange) - scrollToTop(timeRange) - record( - make(Name.TRENDING_CHANGE_VIEW, { - timeframe: timeRange, - genre: trendingGenre ?? '' - }) - ) - }, - [setTrendingTimeRange, scrollToTop, record, trendingGenre] - ) - - const handleGenreChange = useCallback( - (value: string) => { - setGenre(value === 'all' ? null : value) - }, - [setGenre] - ) - - const timeRangeOptions = [ - { label: messages.thisWeek, value: TimeRange.WEEK }, - { label: messages.thisMonth, value: TimeRange.MONTH }, - { label: messages.allTime, value: TimeRange.ALL_TIME } - ] - - const genreOptions = [ - { label: messages.allGenres, value: 'all' }, - ...TRENDING_GENRES.map((g) => ({ - label: getCanonicalName(g), - value: g - })) - ] - - // Bottom bar: category tabs (Tracks | Underground) on left; - // when Tracks, dropdown buttons for time range + genres on right (per design) - const bottomBar = ( - - - setCategory('tracks')} - /> - setCategory('underground')} - /> - - {category === 'tracks' ? ( - - - - - ) : null} - - ) + // Setup Modal + const [modalIsOpen, setModalIsOpen] = useState(false) + const didSelectModalGenre = (genre: string | null) => { + const trimmedGenre = + genre !== null ? genre.replace(ELECTRONIC_PREFIX, '') : genre + setGenre(trimmedGenre) + setModalIsOpen(false) + } // Setup Header const header = ( -
- ) - - const getTracksLineupForRange = (timeRange: TimeRange) => { - const lineupMap = { - [TimeRange.WEEK]: ( -
- - } - {...mainLineupProps} - /> -
- ), - [TimeRange.MONTH]: ( -
- - } - actions={trendingMonthActions} - {...mainLineupProps} - /> -
- ), - [TimeRange.ALL_TIME]: ( -
- - } - {...mainLineupProps} - /> -
- ) - } - return lineupMap[timeRange] - } - - const pageContent = - category === 'tracks' ? ( - getTracksLineupForRange(trendingTimeRange) - ) : ( -
- - } - variant={LineupVariant.MAIN} +
setModalIsOpen(true)} /> -
- ) + } + /> + ) return ( <> @@ -452,8 +363,17 @@ const TrendingPageContent = ({ containerRef }: TrendingPageContentProps) => { size='large' header={header} > - {pageContent} + {body} + { + setModalIsOpen(false) + }} + didSelectGenre={didSelectModalGenre} + isOpen={modalIsOpen} + /> ) } diff --git a/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.module.css b/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.module.css index 40f124e73e6..da57f00b8f4 100644 --- a/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.module.css +++ b/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.module.css @@ -30,50 +30,8 @@ z-index: 10; } -.filterRow { - position: fixed; - top: 92px; - top: calc(92px + env(safe-area-inset-top, 0px)); - left: 0; - right: 0; - z-index: 10; - display: flex; - align-items: center; - gap: 8px; - padding: 12px 16px; - background: var(--harmony-white); - border-bottom: 1px solid var(--harmony-n-100); -} - -.filterButton { - display: flex; - align-items: center; - justify-content: center; - padding: 8px 12px; - margin: 0; - border: none; - border-radius: 20px; - background: var(--harmony-n-100); - cursor: pointer; - font: inherit; - color: inherit; -} - -.filterButton:active { - opacity: 0.8; -} - -.filterButtonLabel { - white-space: nowrap; -} - .tabBodyHolder { - margin-top: 0; -} - -.tabBodyHolder.hasFilterRow { - /* Clear the fixed filter row (header 92px + filter row ~56px) */ - margin-top: 56px; + margin-top: 60px; } .rewardsContainer { 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 70466487458..e0932b538ee 100644 --- a/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.tsx +++ b/packages/web/src/pages/trending-page/components/mobile/TrendingPageContent.tsx @@ -1,27 +1,20 @@ -import { useCallback, useContext, useEffect, useMemo, useState } from 'react' +import { useCallback, useContext, useEffect, useMemo } from 'react' import { Name, TimeRange } from '@audius/common/models' +import { trendingPageLineupActions } from '@audius/common/store' +import { route } from '@audius/common/utils' import { - trendingPageLineupActions, - trendingUndergroundPageLineupActions, - trendingUndergroundPageLineupSelectors -} from '@audius/common/store' -import { getCanonicalName, route } from '@audius/common/utils' -import { - FilterButton, - Flex, - IconCloseAlt, - SelectablePill + IconAllTime, + IconCalendarDay as IconDay, + IconCalendarMonth as IconMonth } from '@audius/harmony' import cn from 'classnames' -import { useDispatch } 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' import Lineup from 'components/lineup/Lineup' -import { useLineupProps } from 'components/lineup/hooks' import { LineupVariant } from 'components/lineup/types' import MobilePageContainer from 'components/mobile-page-container/MobilePageContainer' import NavContext, { @@ -29,6 +22,7 @@ import NavContext, { LeftPreset, RightPreset } from 'components/nav/mobile/NavContext' +import useTabs from 'hooks/useTabs/useTabs' import { TRENDING_MESSAGES } from 'pages/trending-page/constants' import { useTrendingActions } from 'pages/trending-page/hooks/useTrendingActions' import { useTrendingLineups } from 'pages/trending-page/hooks/useTrendingLineups' @@ -38,58 +32,39 @@ import { useTrendingUrlParams } from 'pages/trending-page/hooks/useTrendingUrlPa import { BASE_URL } from 'utils/route' import { scrollWindowToTop } from 'utils/scroll' +import TrendingFilterButton from './TrendingFilterButton' import styles from './TrendingPageContent.module.css' const { TRENDING_PAGE } = route const { trendingAllTimeActions, trendingMonthActions, trendingWeekActions } = trendingPageLineupActions -const { getLineup } = trendingUndergroundPageLineupSelectors const messages = { - trending: 'Trending', - underground: 'Underground', - tracks: 'Tracks', + title: 'Trending', thisWeek: 'This Week', thisMonth: 'This Month', allTime: 'All Time', - genre: 'Genre', - allGenres: 'All Genres', endOfLineupDescription: "Looks like you've reached the end of this list..." } -type TrendingCategory = 'tracks' | 'underground' +const tabHeaders = [ + { icon: , text: messages.thisWeek, label: TimeRange.WEEK }, + { icon: , text: messages.thisMonth, label: TimeRange.MONTH }, + { icon: , text: messages.allTime, label: TimeRange.ALL_TIME } +] type TrendingPageMobileContentProps = { containerRef?: React.RefObject } -const useTrendingUndergroundLineup = ( - scrollParent: HTMLElement | undefined -) => { - return useLineupProps({ - actions: trendingUndergroundPageLineupActions, - getLineupSelector: getLineup, - variant: LineupVariant.MAIN, - scrollParent: scrollParent ?? undefined, - isTrending: true, - isOrdered: true - }) -} - const TrendingPageMobileContent = ({ containerRef }: TrendingPageMobileContentProps) => { - const dispatch = useDispatch() - const [category, setCategory] = useState('tracks') - const trendingPageState = useTrendingPageState() const actions = useTrendingActions() const lineups = useTrendingLineups({ trendingPageState, - containerRef: containerRef ?? undefined + containerRef: containerRef || undefined }) - const undergroundLineupProps = useTrendingUndergroundLineup( - containerRef?.current ?? undefined - ) useTrendingUrlParams({ trendingPageState, @@ -100,12 +75,6 @@ const TrendingPageMobileContent = ({ useTrendingPageCleanup({ trendingPageState, actions }) - useEffect(() => { - return () => { - dispatch(trendingUndergroundPageLineupActions.reset()) - } - }, [dispatch]) - const { trendingWeek, trendingMonth, trendingAllTime, getLineupProps } = lineups const { trendingGenre, trendingTimeRange } = trendingPageState @@ -115,10 +84,9 @@ const TrendingPageMobileContent = ({ makePauseTrack, makeSetInView, setTrendingTimeRange, - setTrendingGenre, goToGenreSelection } = actions - + // Set Nav-Bar Menu const { setLeft, setCenter, setRight } = useContext(NavContext)! useEffect(() => { setLeft(LeftPreset.NOTIFICATION) @@ -126,6 +94,7 @@ const TrendingPageMobileContent = ({ setCenter(CenterPreset.LOGO) }, [setLeft, setCenter, setRight]) + // Setup lineups const weekProps = useMemo( () => getLineupProps(trendingWeek), [getLineupProps, trendingWeek] @@ -139,204 +108,128 @@ const TrendingPageMobileContent = ({ [getLineupProps, trendingAllTime] ) + const lineupElements = useMemo(() => { + return [ + <> + + } + /> + , + + } + />, + + } + /> + ] + }, [ + makeLoadMore, + makePauseTrack, + makePlayTrack, + makeSetInView, + monthProps, + weekProps, + allTimeProps, + trendingGenre + ]) const record = useRecord() - const handleTimeRangeChange = useCallback( - (timeRange: TimeRange) => { - setTrendingTimeRange(timeRange) + const didChangeTabs = useCallback( + (from: string, to: string) => { + if (from === to) return + setTrendingTimeRange(to as TimeRange) + + // Fo the mobile layout scroll the document element, not the lineup container scrollWindowToTop() - makeSetInView(timeRange)(true) - ;[TimeRange.WEEK, TimeRange.MONTH, TimeRange.ALL_TIME].forEach((tr) => { - if (tr !== timeRange) makeSetInView(tr)(false) - }) - record( - make(Name.TRENDING_CHANGE_VIEW, { - timeframe: timeRange, - genre: trendingGenre ?? '' - }) - ) - }, - [setTrendingTimeRange, makeSetInView, record, trendingGenre] - ) - const getTracksLineupForRange = useCallback( - (timeRange: TimeRange) => { - const lineupMap = { - [TimeRange.WEEK]: ( - - } - /> - ), - [TimeRange.MONTH]: ( - - } - /> - ), - [TimeRange.ALL_TIME]: ( - - } - /> + // Manually setInView + makeSetInView(to as TimeRange)(true) + makeSetInView(from as TimeRange)(false) + if (from !== to) + record( + make(Name.TRENDING_CHANGE_VIEW, { + timeframe: to as TimeRange, + genre: trendingGenre || '' + }) ) - } - return lineupMap[timeRange] }, - [ - weekProps, - monthProps, - allTimeProps, - trendingGenre, - makeSetInView, - makeLoadMore, - makePlayTrack, - makePauseTrack - ] - ) - - const timeRangeOptions = useMemo( - () => [ - { value: TimeRange.WEEK, label: messages.thisWeek }, - { value: TimeRange.MONTH, label: messages.thisMonth }, - { value: TimeRange.ALL_TIME, label: messages.allTime } - ], - [] - ) - - const categoryOptions = useMemo( - () => [ - { value: 'tracks' as const, label: messages.tracks }, - { value: 'underground' as const, label: messages.underground } - ], - [] + [setTrendingTimeRange, makeSetInView, record, trendingGenre] ) - const handleCategoryChange = useCallback((value: string) => { - setCategory(value as TrendingCategory) - }, []) - - const genreLabel = - trendingGenre !== null && trendingGenre !== undefined - ? getCanonicalName(trendingGenre) - : messages.allGenres - - const isGenreSelected = trendingGenre !== null && trendingGenre !== undefined - - const handleGenrePillClick = useCallback(() => { - if (isGenreSelected) { - setTrendingGenre(null) - } else { - goToGenreSelection() - } - }, [isGenreSelected, setTrendingGenre, goToGenreSelection]) + const memoizedElements = useMemo(() => { + return lineupElements.map((lineup, i) => ( +
+ {lineup} +
+ )) + }, [lineupElements]) + + const { tabs, body } = useTabs({ + tabs: tabHeaders, + elements: memoizedElements, + initialTab: trendingTimeRange, + selectedTabLabel: trendingTimeRange, + didChangeTabsFrom: didChangeTabs + }) const { setHeader } = useContext(HeaderContext) useEffect(() => { setHeader( -
- - +
+ - -
- ) - }, [setHeader, category, handleCategoryChange, categoryOptions]) - - const content = - category === 'tracks' ? ( -
- {getTracksLineupForRange(trendingTimeRange)} -
- ) : ( -
- - } - variant={LineupVariant.MAIN} - /> -
+
+
{tabs}
+ ) + }, [setHeader, trendingGenre, goToGenreSelection, tabs]) return ( - <> - {category === 'tracks' ? ( -
- handleTimeRangeChange(value as TimeRange)} - options={timeRangeOptions} - size='small' - /> - -
- ) : null} - -
-
- {content} -
-
-
- + +
+
{body}
+
+
) } diff --git a/packages/web/src/pages/trending-underground/TrendingUndergroundPage.module.css b/packages/web/src/pages/trending-underground/TrendingUndergroundPage.module.css new file mode 100644 index 00000000000..186028d1e8e --- /dev/null +++ b/packages/web/src/pages/trending-underground/TrendingUndergroundPage.module.css @@ -0,0 +1,14 @@ +.mobileLineupContainer { + margin-top: 12px; + padding: 0px 12px; + min-width: 0; + flex: 1; +} + +.bannerContainer { + margin-bottom: 14px; +} + +.mobileBannerContainer { + margin: 12px 0px 8px; +} diff --git a/packages/web/src/pages/trending-underground/TrendingUndergroundPage.tsx b/packages/web/src/pages/trending-underground/TrendingUndergroundPage.tsx new file mode 100644 index 00000000000..e49672745fe --- /dev/null +++ b/packages/web/src/pages/trending-underground/TrendingUndergroundPage.tsx @@ -0,0 +1,109 @@ +import { useEffect } from 'react' + +import { + trendingUndergroundPageLineupSelectors, + trendingUndergroundPageLineupActions +} from '@audius/common/store' +import { route } from '@audius/common/utils' +import { useDispatch } from 'react-redux' + +import { Header as DesktopHeader } from 'components/header/desktop/Header' +import { useMobileHeader } from 'components/header/mobile/hooks' +import Lineup from 'components/lineup/Lineup' +import { useLineupProps } from 'components/lineup/hooks' +import { LineupVariant } from 'components/lineup/types' +import MobilePageContainer from 'components/mobile-page-container/MobilePageContainer' +import Page from 'components/page/Page' +import { useIsMobile } from 'hooks/useIsMobile' +import { getExploreInfo } from 'ssr/metaTags' +import { BASE_URL } from 'utils/route' + +import styles from './TrendingUndergroundPage.module.css' +const { TRENDING_UNDERGROUND_PAGE } = route +const { getLineup } = trendingUndergroundPageLineupSelectors + +const useTrendingUndergroundLineup = (containerRef: HTMLElement) => { + return useLineupProps({ + actions: trendingUndergroundPageLineupActions, + getLineupSelector: getLineup, + variant: LineupVariant.MAIN, + scrollParent: containerRef, + isTrending: true, + isOrdered: true + }) +} + +const exploreInfo = getExploreInfo('underground') +const messages = { + trendingUndergroundTitle: exploreInfo.title, + description: exploreInfo.description +} + +type TrendingUndergroundPageProps = { + containerRef: HTMLElement +} + +const MobileTrendingUndergroundPage = ({ + containerRef +}: TrendingUndergroundPageProps) => { + const lineupProps = useTrendingUndergroundLineup(containerRef) + useMobileHeader({ title: messages.trendingUndergroundTitle }) + return ( + +
+ +
+
+ ) +} + +const DesktopTrendingUndergroundPage = ({ + containerRef +}: TrendingUndergroundPageProps) => { + const lineupProps = useTrendingUndergroundLineup(containerRef) + + const header = + + return ( + + + + ) +} + +const useLineupReset = () => { + const dispatch = useDispatch() + useEffect(() => { + return () => { + dispatch(trendingUndergroundPageLineupActions.reset()) + } + }, [dispatch]) +} + +const TrendingUndergroundPage = (props: TrendingUndergroundPageProps) => { + const isMobile = useIsMobile() + + useLineupReset() + + return ( + <> + {isMobile ? ( + + ) : ( + + )} + + ) +} + +export default TrendingUndergroundPage diff --git a/packages/web/src/ssr/metaTags.ts b/packages/web/src/ssr/metaTags.ts index 7a593ff1617..6510d7e8266 100644 --- a/packages/web/src/ssr/metaTags.ts +++ b/packages/web/src/ssr/metaTags.ts @@ -13,6 +13,10 @@ export const AUDIO_REWARDS_IMAGE_URL = export const SIGNUP_REF_IMAGE_URL = 'https://download.audius.co/static-resources/signup_referral.png' +// Explore page image URLs +const UNDERGROUND_TRENDING_URL = + 'https://download.audius.co/static-resources/underground-trending.png' + // Regex to detect Twitter/Discord bots that can embed players const CAN_EMBED_USER_AGENT_REGEX = /(twitter|discord)/i @@ -79,7 +83,15 @@ export const getWebUrl = (path: string): string => { /** * Explore type to metadata mapping */ -export const exploreMap: Record = {} +export const exploreMap: Record = { + underground: { + title: 'Underground Trending', + description: createSeoDescription( + "Listen to what's trending on the Audius platform" + ), + image: UNDERGROUND_TRENDING_URL + } +} /** * Get explore info for a given type