From 1e9b196bb388a524289305c374fa0c997c25dbb6 Mon Sep 17 00:00:00 2001 From: KJ Shanks Date: Mon, 5 May 2025 12:11:12 -0400 Subject: [PATCH 1/3] Add remix contest section to explore page --- packages/common/src/api/index.ts | 3 + .../tan-query/collection/useExploreContent.ts | 5 ++ .../components/desktop/CollectionArtCard.tsx | 16 +++- .../components/desktop/ExplorePage.tsx | 37 ++++---- .../desktop/FeaturedRemixContests.tsx | 21 +++++ .../components/desktop/TrackArtCard.tsx | 85 +++++++++++++++++++ .../desktop/RemixContestDetailsTab.tsx | 8 +- 7 files changed, 148 insertions(+), 27 deletions(-) create mode 100644 packages/web/src/pages/explore-page/components/desktop/FeaturedRemixContests.tsx create mode 100644 packages/web/src/pages/explore-page/components/desktop/TrackArtCard.tsx diff --git a/packages/common/src/api/index.ts b/packages/common/src/api/index.ts index 45639bd2264..8d909d576da 100644 --- a/packages/common/src/api/index.ts +++ b/packages/common/src/api/index.ts @@ -29,6 +29,9 @@ export * from './tan-query/collection/useFeaturedPlaylists' // Events export * from './tan-query/events' +// Explore +export * from './tan-query/collection/useExploreContent' + // Lineups export * from './tan-query/lineups/useFeed' export * from './tan-query/lineups/useLibraryTracks' diff --git a/packages/common/src/api/tan-query/collection/useExploreContent.ts b/packages/common/src/api/tan-query/collection/useExploreContent.ts index d9663cabce0..40e9ef51970 100644 --- a/packages/common/src/api/tan-query/collection/useExploreContent.ts +++ b/packages/common/src/api/tan-query/collection/useExploreContent.ts @@ -12,11 +12,13 @@ const STATIC_EXPLORE_CONTENT_URL = type ExploreContentResponse = { featuredPlaylists: string[] featuredProfiles: string[] + featuredRemixContests: string[] } export type ExploreContent = { featuredPlaylists: ID[] featuredProfiles: ID[] + featuredRemixContests: ID[] } export const getExploreContentQueryKey = () => { @@ -41,6 +43,9 @@ export const useExploreContent = ( ), featuredProfiles: json.featuredProfiles.map( (id: string) => parseInt(id) as ID + ), + featuredRemixContests: json.featuredRemixContests.map( + (id: string) => parseInt(id) as ID ) } }, diff --git a/packages/web/src/pages/explore-page/components/desktop/CollectionArtCard.tsx b/packages/web/src/pages/explore-page/components/desktop/CollectionArtCard.tsx index e6c7ae86134..48ce081cb2b 100644 --- a/packages/web/src/pages/explore-page/components/desktop/CollectionArtCard.tsx +++ b/packages/web/src/pages/explore-page/components/desktop/CollectionArtCard.tsx @@ -16,6 +16,8 @@ type CollectionArtCardProps = { id: ID } +const ARTWORK_SIZE = 240 + export const CollectionArtCard = ({ id }: CollectionArtCardProps) => { const [isPerspectiveDisabled, setIsPerspectiveDisabled] = useState(false) @@ -36,11 +38,17 @@ export const CollectionArtCard = ({ id }: CollectionArtCardProps) => { - + {playlist_name} @@ -52,7 +60,7 @@ export const CollectionArtCard = ({ id }: CollectionArtCardProps) => { center /> - + { contentClassName={styles.page} header={header} > +
+ {lifestyle.map((i) => ( + navigate(i.link)} + > + + + ))} +
+ + + + +
{ ) })}
- -
- {lifestyle.map((i) => ( - navigate(i.link)} - > - - - ))} -
- - - ) } diff --git a/packages/web/src/pages/explore-page/components/desktop/FeaturedRemixContests.tsx b/packages/web/src/pages/explore-page/components/desktop/FeaturedRemixContests.tsx new file mode 100644 index 00000000000..9a349771a33 --- /dev/null +++ b/packages/web/src/pages/explore-page/components/desktop/FeaturedRemixContests.tsx @@ -0,0 +1,21 @@ +import { useExploreContent } from '@audius/common/api' + +import Section from './Section' +import { TrackArtCard } from './TrackArtCard' + +const messages = { + remixContests: 'Remix Contests' +} + +export const FeaturedRemixContests = () => { + const { data: exploreContent } = useExploreContent() + const contestIds = exploreContent?.featuredRemixContests ?? [] + + return ( +
+ {contestIds.slice(0, 4).map((id) => ( + + ))} +
+ ) +} diff --git a/packages/web/src/pages/explore-page/components/desktop/TrackArtCard.tsx b/packages/web/src/pages/explore-page/components/desktop/TrackArtCard.tsx new file mode 100644 index 00000000000..f4ef8a775a5 --- /dev/null +++ b/packages/web/src/pages/explore-page/components/desktop/TrackArtCard.tsx @@ -0,0 +1,85 @@ +import { useCallback } from 'react' + +import { useRemixContest, useTrack } from '@audius/common/api' +import { ID, SquareSizes } from '@audius/common/models' +import { dayjs } from '@audius/common/utils' +import { Flex, Skeleton, Text } from '@audius/harmony' +import { useNavigate } from 'react-router-dom-v5-compat' + +import { TrackLink } from 'components/link/TrackLink' +import { UserLink } from 'components/link/UserLink' +import PerspectiveCard from 'components/perspective-card/PerspectiveCard' +import { TrackArtwork } from 'components/track/TrackArtwork' + +type TrackArtCardProps = { + id: ID +} + +const messages = { + remixContest: 'Remix Contest', + deadline: 'Deadline', + ended: 'Ended' +} + +const ARTWORK_SIZE = 240 + +export const TrackArtCard = ({ id }: TrackArtCardProps) => { + const navigate = useNavigate() + + const { data: track, isLoading: isTrackLoading } = useTrack(id) + const { data: contest, isLoading: isContestLoading } = useRemixContest(id) + const isLoading = isTrackLoading || isContestLoading + const isRemixContest = !!contest + const isContestEnded = + isRemixContest && dayjs(contest?.endDate).isBefore(dayjs()) + + const goToTrack = useCallback(() => { + if (!track?.permalink) return + navigate(track.permalink) + }, [navigate, track?.permalink]) + + if (!track) return null + + return ( + + + + + + {isLoading ? ( + <> + + + + ) : ( + <> + + + {isRemixContest && ( + + {`${isContestEnded ? messages.ended : messages.deadline}: ${dayjs(contest.endDate).format('MM/DD/YY')}`} + + )} + + )} + + + ) +} diff --git a/packages/web/src/pages/track-page/components/desktop/RemixContestDetailsTab.tsx b/packages/web/src/pages/track-page/components/desktop/RemixContestDetailsTab.tsx index d96f6eee269..4ee308ccc5b 100644 --- a/packages/web/src/pages/track-page/components/desktop/RemixContestDetailsTab.tsx +++ b/packages/web/src/pages/track-page/components/desktop/RemixContestDetailsTab.tsx @@ -40,13 +40,9 @@ export const RemixContestDetailsTab = ({ - {messages.due} - - - {isContestEnded - ? messages.ended - : messages.deadline(remixContest?.endDate)} + {isContestEnded ? messages.ended : messages.due} + {messages.deadline(remixContest?.endDate)} Date: Mon, 5 May 2025 13:12:50 -0400 Subject: [PATCH 2/3] small fixes --- .../harmony/src/components/text-link/TextLink.tsx | 3 ++- .../components/desktop/TrackArtCard.tsx | 14 +++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/harmony/src/components/text-link/TextLink.tsx b/packages/harmony/src/components/text-link/TextLink.tsx index 2fa9bb9fa1a..9c53da8ad75 100644 --- a/packages/harmony/src/components/text-link/TextLink.tsx +++ b/packages/harmony/src/components/text-link/TextLink.tsx @@ -61,7 +61,8 @@ export const TextLink = forwardRef((props: TextLinkProps, ref: Ref<'a'>) => { asChild onClick={onClick} css={{ - display: 'inline-flex', + // MaxLines requires a special webkit display to work, dont override here + display: other.maxLines ? undefined : 'inline-flex', gap: spacing.s, color: variantColors[variant], textDecoration: 'none', diff --git a/packages/web/src/pages/explore-page/components/desktop/TrackArtCard.tsx b/packages/web/src/pages/explore-page/components/desktop/TrackArtCard.tsx index f4ef8a775a5..d2c175bc20b 100644 --- a/packages/web/src/pages/explore-page/components/desktop/TrackArtCard.tsx +++ b/packages/web/src/pages/explore-page/components/desktop/TrackArtCard.tsx @@ -18,7 +18,13 @@ type TrackArtCardProps = { const messages = { remixContest: 'Remix Contest', deadline: 'Deadline', - ended: 'Ended' + ended: 'Ended', + contestDeadline: (endDate: string | undefined) => { + if (!endDate) return null + + const isContestEnded = dayjs(endDate).isBefore(dayjs()) + return `${isContestEnded ? messages.ended : messages.deadline}: ${dayjs(endDate).format('MM/DD/YY')}` + } } const ARTWORK_SIZE = 240 @@ -30,8 +36,6 @@ export const TrackArtCard = ({ id }: TrackArtCardProps) => { const { data: contest, isLoading: isContestLoading } = useRemixContest(id) const isLoading = isTrackLoading || isContestLoading const isRemixContest = !!contest - const isContestEnded = - isRemixContest && dayjs(contest?.endDate).isBefore(dayjs()) const goToTrack = useCallback(() => { if (!track?.permalink) return @@ -64,7 +68,7 @@ export const TrackArtCard = ({ id }: TrackArtCardProps) => { ) : ( <> - + { /> {isRemixContest && ( - {`${isContestEnded ? messages.ended : messages.deadline}: ${dayjs(contest.endDate).format('MM/DD/YY')}`} + {messages.contestDeadline(contest.endDate)} )} From f0695fddefe9d9abd2779d25a825e299caafa6a8 Mon Sep 17 00:00:00 2001 From: KJ Shanks Date: Mon, 5 May 2025 15:20:35 -0400 Subject: [PATCH 3/3] add feature flag --- .../services/remote-config/feature-flags.ts | 6 +- .../components/desktop/ExplorePage.tsx | 62 ++++++++++++++----- .../desktop/FeaturedRemixContests.tsx | 16 +++-- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/packages/common/src/services/remote-config/feature-flags.ts b/packages/common/src/services/remote-config/feature-flags.ts index ab3548cb64f..035c43db05e 100644 --- a/packages/common/src/services/remote-config/feature-flags.ts +++ b/packages/common/src/services/remote-config/feature-flags.ts @@ -30,7 +30,8 @@ export enum FeatureFlags { DOWNLOAD_ALL_TRACK_FILES = 'download_all_track_files', REMIX_CONTEST = 'remix_contest', WALLET_UI_UPDATE = 'wallet_ui_update', - SEARCH_EXPLORE = 'search_explore' + SEARCH_EXPLORE = 'search_explore', + EXPLORE_REMIX_SECTION = 'explore_remix_section' } type FlagDefaults = Record @@ -76,5 +77,6 @@ export const flagDefaults: FlagDefaults = { [FeatureFlags.DOWNLOAD_ALL_TRACK_FILES]: false, [FeatureFlags.REMIX_CONTEST]: false, [FeatureFlags.WALLET_UI_UPDATE]: false, - [FeatureFlags.SEARCH_EXPLORE]: false + [FeatureFlags.SEARCH_EXPLORE]: false, + [FeatureFlags.EXPLORE_REMIX_SECTION]: false } diff --git a/packages/web/src/pages/explore-page/components/desktop/ExplorePage.tsx b/packages/web/src/pages/explore-page/components/desktop/ExplorePage.tsx index 8bd1f264e40..7ca720e1066 100644 --- a/packages/web/src/pages/explore-page/components/desktop/ExplorePage.tsx +++ b/packages/web/src/pages/explore-page/components/desktop/ExplorePage.tsx @@ -1,6 +1,8 @@ import { useCallback } from 'react' +import { useFeatureFlag } from '@audius/common/hooks' import { Variant as CollectionVariant, Variant } from '@audius/common/models' +import { FeatureFlags } from '@audius/common/services' import { ExploreCollectionsVariant } from '@audius/common/store' import { route } from '@audius/common/utils' import { IconExplore } from '@audius/harmony' @@ -83,6 +85,9 @@ export type ExplorePageProps = { const ExplorePage = ({ title, pageTitle, description }: ExplorePageProps) => { const isUSDCPurchasesEnabled = useIsUSDCEnabled() + const { isEnabled: isRemixSectionEnabled } = useFeatureFlag( + FeatureFlags.EXPLORE_REMIX_SECTION + ) const justForYouTiles = justForYou.filter((tile) => { const isPremiumTracksTile = tile.variant === ExploreCollectionsVariant.DIRECT_LINK && @@ -121,22 +126,29 @@ const ExplorePage = ({ title, pageTitle, description }: ExplorePageProps) => { contentClassName={styles.page} header={header} > -
- {lifestyle.map((i) => ( - navigate(i.link)} + {isRemixSectionEnabled ? ( + <> +
- - - ))} -
+ {lifestyle.map((i) => ( + navigate(i.link)} + > + + + ))} +
- - - + + + + + ) : null}
{ ) })}
+ {!isRemixSectionEnabled ? ( + <> +
+ {lifestyle.map((i) => ( + navigate(i.link)} + > + + + ))} +
+ + + + + ) : null} ) } diff --git a/packages/web/src/pages/explore-page/components/desktop/FeaturedRemixContests.tsx b/packages/web/src/pages/explore-page/components/desktop/FeaturedRemixContests.tsx index 9a349771a33..9ff6de2e47a 100644 --- a/packages/web/src/pages/explore-page/components/desktop/FeaturedRemixContests.tsx +++ b/packages/web/src/pages/explore-page/components/desktop/FeaturedRemixContests.tsx @@ -1,5 +1,7 @@ import { useExploreContent } from '@audius/common/api' +import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' + import Section from './Section' import { TrackArtCard } from './TrackArtCard' @@ -8,14 +10,20 @@ const messages = { } export const FeaturedRemixContests = () => { - const { data: exploreContent } = useExploreContent() + const { data: exploreContent, isLoading } = useExploreContent() const contestIds = exploreContent?.featuredRemixContests ?? [] return (
- {contestIds.slice(0, 4).map((id) => ( - - ))} + {isLoading ? ( + + ) : ( + <> + {contestIds.slice(0, 4).map((id) => ( + + ))} + + )}
) }