From 9dabd1bdea2be8712dd0dcccac4adbbfea4c87b0 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Thu, 7 Nov 2024 19:52:18 +0100 Subject: [PATCH] [C-5364] Track and Collection Tile Stat updates (#10379) --- .../src/components/text-link/TextLink.tsx | 12 +- .../harmony/src/components/text-link/types.ts | 5 + .../src/components/lineup-tile/LineupTile.tsx | 2 - .../mobile/src/components/lineup/Lineup.tsx | 1 - packages/web/src/components/avatar/Avatar.tsx | 2 +- .../web/src/components/avatar/AvatarList.tsx | 26 +++ packages/web/src/components/avatar/index.ts | 1 + .../collection/CollectionLockedStatusPill.tsx | 57 +++++ .../collection/CollectionTileMetrics.tsx | 151 +++++++++++++ .../collection/CollectionTileStats.tsx | 64 ++++++ .../src/components/entity/VanityMetrics.tsx | 48 ++++ .../web/src/components/lineup/EntityRank.tsx | 7 +- .../src/components/lineup/LineupProvider.tsx | 6 - packages/web/src/components/lineup/hooks.ts | 3 - packages/web/src/components/link/TextLink.tsx | 4 +- packages/web/src/components/link/UserLink.tsx | 14 +- .../track/TrackLockedStatusPill.tsx | 61 +++++ .../src/components/track/TrackTileMetrics.tsx | 212 ++++++++++++++++++ .../src/components/track/TrackTileStats.tsx | 70 ++++++ .../track/desktop/ConnectedPlaylistTile.tsx | 79 +------ .../desktop/ConnectedTrackTile.module.css | 7 - .../track/desktop/ConnectedTrackTile.tsx | 157 +------------ .../components/track/desktop/PlaylistTile.tsx | 6 +- .../components/track/desktop/TrackTile.tsx | 96 ++------ .../track/desktop/stats/Stats.module.css | 57 ----- .../components/track/desktop/stats/Stats.tsx | 118 ---------- .../track/desktop/stats/StatsText.module.css | 16 -- .../track/desktop/stats/StatsText.tsx | 125 ----------- .../track/mobile/ConnectedPlaylistTile.tsx | 5 +- .../track/mobile/ConnectedTrackTile.tsx | 61 +---- .../track/mobile/PlaylistTile.module.css | 34 --- .../components/track/mobile/PlaylistTile.tsx | 176 ++------------- .../src/components/track/mobile/TrackTile.tsx | 212 ++---------------- packages/web/src/components/track/types.ts | 34 +-- .../components/ChatMessagePlaylist.tsx | 1 - .../chat-page/components/ChatMessageTrack.tsx | 1 - .../desktop/TrendingPageContent.tsx | 3 - .../components/mobile/TrendingPageContent.tsx | 3 - .../TrendingPlaylistPage.tsx | 1 - .../TrendingUndergroundPage.tsx | 1 - 40 files changed, 780 insertions(+), 1159 deletions(-) create mode 100644 packages/web/src/components/avatar/AvatarList.tsx create mode 100644 packages/web/src/components/collection/CollectionLockedStatusPill.tsx create mode 100644 packages/web/src/components/collection/CollectionTileMetrics.tsx create mode 100644 packages/web/src/components/collection/CollectionTileStats.tsx create mode 100644 packages/web/src/components/entity/VanityMetrics.tsx create mode 100644 packages/web/src/components/track/TrackLockedStatusPill.tsx create mode 100644 packages/web/src/components/track/TrackTileMetrics.tsx create mode 100644 packages/web/src/components/track/TrackTileStats.tsx delete mode 100644 packages/web/src/components/track/desktop/stats/Stats.module.css delete mode 100644 packages/web/src/components/track/desktop/stats/Stats.tsx delete mode 100644 packages/web/src/components/track/desktop/stats/StatsText.module.css delete mode 100644 packages/web/src/components/track/desktop/stats/StatsText.tsx diff --git a/packages/harmony/src/components/text-link/TextLink.tsx b/packages/harmony/src/components/text-link/TextLink.tsx index 20fa3df2c99..7037a527db4 100644 --- a/packages/harmony/src/components/text-link/TextLink.tsx +++ b/packages/harmony/src/components/text-link/TextLink.tsx @@ -20,6 +20,7 @@ export const TextLink = forwardRef((props: TextLinkProps, ref: Ref<'a'>) => { onClick, textVariant, showUnderline, + noUnderlineOnHover, applyHoverStylesToInnerSvg, disabled, ...other @@ -46,14 +47,10 @@ export const TextLink = forwardRef((props: TextLinkProps, ref: Ref<'a'>) => { } const hoverStyles = { - textDecoration: 'underline', + textDecoration: noUnderlineOnHover ? 'none' : 'underline', color: variantHoverColors[variant], ...(applyHoverStylesToInnerSvg - ? { - path: { - fill: variantHoverColors[variant] - } - } + ? { path: { fill: variantHoverColors[variant] } } : {}) } @@ -70,6 +67,9 @@ export const TextLink = forwardRef((props: TextLinkProps, ref: Ref<'a'>) => { transition: `color ${motion.hover}`, cursor: 'pointer', pointerEvents: disabled ? 'none' : undefined, + ...(applyHoverStylesToInnerSvg && { + path: { transition: `fill ${motion.hover}` } + }), ':hover': hoverStyles, ...(isActive && { ...hoverStyles, textDecoration: 'none' }), ...(showUnderline && hoverStyles) diff --git a/packages/harmony/src/components/text-link/types.ts b/packages/harmony/src/components/text-link/types.ts index 817bdfaa088..1423044897a 100644 --- a/packages/harmony/src/components/text-link/types.ts +++ b/packages/harmony/src/components/text-link/types.ts @@ -36,6 +36,11 @@ export type TextLinkProps = Omit & */ showUnderline?: boolean + /** + * When true, hide the underline when the link is active. + */ + noUnderlineOnHover?: boolean + /** * When `true`, render link in active style (e.g. hover color) */ diff --git a/packages/mobile/src/components/lineup-tile/LineupTile.tsx b/packages/mobile/src/components/lineup-tile/LineupTile.tsx index 57664306efc..eb781090ad1 100644 --- a/packages/mobile/src/components/lineup-tile/LineupTile.tsx +++ b/packages/mobile/src/components/lineup-tile/LineupTile.tsx @@ -51,7 +51,6 @@ export const LineupTile = ({ commentCount, renderImage, repostType, - showRankIcon, title, item, user, @@ -138,7 +137,6 @@ export const LineupTile = ({ repostCount={repost_count} saveCount={save_count} commentCount={commentCount} - showRankIcon={showRankIcon} hasStreamAccess={hasStreamAccess} streamConditions={streamConditions} isOwner={isOwner} diff --git a/packages/mobile/src/components/lineup/Lineup.tsx b/packages/mobile/src/components/lineup/Lineup.tsx index 64e277747ab..11ed16fa0b3 100644 --- a/packages/mobile/src/components/lineup/Lineup.tsx +++ b/packages/mobile/src/components/lineup/Lineup.tsx @@ -160,7 +160,6 @@ const LineupTileView = memo(function LineupTileView({ {...item} index={index} isTrending={isTrending} - showRankIcon={index < rankIconCount} togglePlay={togglePlay} onPress={onPress} uid={item.uid} diff --git a/packages/web/src/components/avatar/Avatar.tsx b/packages/web/src/components/avatar/Avatar.tsx index bb59868803c..0788dc432a6 100644 --- a/packages/web/src/components/avatar/Avatar.tsx +++ b/packages/web/src/components/avatar/Avatar.tsx @@ -22,7 +22,7 @@ const messages = { profile: 'profile' } -type AvatarProps = Omit & { +export type AvatarProps = Omit & { 'aria-hidden'?: true userId: Maybe onClick?: () => void diff --git a/packages/web/src/components/avatar/AvatarList.tsx b/packages/web/src/components/avatar/AvatarList.tsx new file mode 100644 index 00000000000..74396f11e82 --- /dev/null +++ b/packages/web/src/components/avatar/AvatarList.tsx @@ -0,0 +1,26 @@ +import { ID } from '@audius/common/models' +import { Flex } from '@audius/harmony' + +import { Avatar, AvatarProps } from './Avatar' + +type AvatarListProps = { + users: ID[] + avatarProps?: Partial +} + +export const AvatarList = (props: AvatarListProps) => { + const { users, avatarProps } = props + return ( + + {users.slice(0, 3).map((user, index) => ( + + ))} + + ) +} diff --git a/packages/web/src/components/avatar/index.ts b/packages/web/src/components/avatar/index.ts index bb0725fdf40..5458581d7be 100644 --- a/packages/web/src/components/avatar/index.ts +++ b/packages/web/src/components/avatar/index.ts @@ -1,2 +1,3 @@ export * from './Avatar' export * from './AvatarLegacy' +export * from './AvatarList' diff --git a/packages/web/src/components/collection/CollectionLockedStatusPill.tsx b/packages/web/src/components/collection/CollectionLockedStatusPill.tsx new file mode 100644 index 00000000000..4cc17afe50f --- /dev/null +++ b/packages/web/src/components/collection/CollectionLockedStatusPill.tsx @@ -0,0 +1,57 @@ +import { useGetPlaylistById } from '@audius/common/api' +import { useGatedContentAccess } from '@audius/common/hooks' +import { + Collection, + ID, + isContentUSDCPurchaseGated +} from '@audius/common/models' +import { Nullable } from '@audius/common/utils' + +import { + LockedStatusPill, + LockedStatusPillProps +} from 'components/locked-status-pill' + +type CollectionLockedStatusPillProps = { + collectionId: ID +} + +export const CollectionLockedStatusPill = ( + props: CollectionLockedStatusPillProps +) => { + const { collectionId } = props + const { data: collection } = useGetPlaylistById( + { playlistId: collectionId }, + { disabled: !collectionId } + ) + + const { hasStreamAccess } = useGatedContentAccess( + collection as Nullable + ) + + if (!collection) return null + const { stream_conditions } = collection + + const isPurchaseable = isContentUSDCPurchaseGated(stream_conditions) + + let variant: Nullable = null + if (isPurchaseable) { + variant = 'premium' + } + + if (!variant) return null + + return +} + +export const useIsCollectionUnlockable = (collectionId: ID) => { + const { data: collection } = useGetPlaylistById({ + playlistId: collectionId + }) + + if (!collection) return false + const { stream_conditions } = collection + const isPurchaseable = isContentUSDCPurchaseGated(stream_conditions) + + return isPurchaseable +} diff --git a/packages/web/src/components/collection/CollectionTileMetrics.tsx b/packages/web/src/components/collection/CollectionTileMetrics.tsx new file mode 100644 index 00000000000..f1ea624f251 --- /dev/null +++ b/packages/web/src/components/collection/CollectionTileMetrics.tsx @@ -0,0 +1,151 @@ +import { useCallback } from 'react' + +import { useGetPlaylistById } from '@audius/common/api' +import { ID } from '@audius/common/models' +import { repostsUserListActions, RepostType } from '@audius/common/store' +import { formatCount, route } from '@audius/common/utils' +import { Text, Flex, IconRepost, IconHeart } from '@audius/harmony' +import { push } from 'connected-react-router' +import { useDispatch } from 'react-redux' + +import { AvatarList } from 'components/avatar' +import { UserName, VanityMetric } from 'components/entity/VanityMetrics' +import { TrackTileSize } from 'components/track/types' +import { useIsMobile } from 'hooks/useIsMobile' +import { + setUsers, + setVisibility +} from 'store/application/ui/userListModal/slice' +import { + UserListEntityType, + UserListType +} from 'store/application/ui/userListModal/types' +import { pluralize } from 'utils/stringUtils' + +const { REPOSTING_USERS_ROUTE, FAVORITING_USERS_ROUTE } = route +const { setRepost } = repostsUserListActions + +type RepostsMetricProps = { + collectionId: ID + size?: TrackTileSize +} + +export const RepostsMetric = (props: RepostsMetricProps) => { + const { collectionId, size } = props + const { data: playlist } = useGetPlaylistById( + { playlistId: collectionId }, + { disabled: !collectionId } + ) + const isMobile = useIsMobile() + const dispatch = useDispatch() + + const handleClick = useCallback(() => { + if (isMobile) { + dispatch(setRepost(collectionId, RepostType.COLLECTION)) + dispatch(push(REPOSTING_USERS_ROUTE)) + } else { + dispatch( + setUsers({ + userListType: UserListType.REPOST, + entityType: UserListEntityType.COLLECTION, + id: collectionId + }) + ) + dispatch(setVisibility(true)) + } + }, [dispatch, isMobile, collectionId]) + + if (!playlist) return null + const { repost_count = 0, followee_reposts = [], is_album } = playlist + + if (repost_count === 0) + return ( + + + + Be the first to repost this {is_album ? 'album' : 'playlist'} + + + ) + + const renderName = () => { + const [{ user_id }] = followee_reposts + + const remainingCount = repost_count - 1 + const remainingText = + remainingCount > 0 + ? ` + ${formatCount(remainingCount)} ${pluralize( + 'Repost', + remainingCount + )}` + : ' Reposted' + + return ( + + + {remainingText} + + ) + } + + const isLargeSize = size === TrackTileSize.LARGE && !isMobile + + return ( + ({ gap: theme.spacing.l })} + onClick={handleClick} + > + {isLargeSize && followee_reposts.length >= 3 ? ( + user_id)} /> + ) : null} + + + {isLargeSize && followee_reposts.length > 0 + ? renderName() + : formatCount(repost_count)} + + + ) +} + +type SavesMetricProps = { + collectionId: ID +} + +export const SavesMetric = (props: SavesMetricProps) => { + const { collectionId } = props + const { data: playlist } = useGetPlaylistById( + { playlistId: collectionId }, + { disabled: !collectionId } + ) + const isMobile = useIsMobile() + const dispatch = useDispatch() + + const handleClick = useCallback(() => { + if (isMobile) { + dispatch(setRepost(collectionId, RepostType.COLLECTION)) + dispatch(push(FAVORITING_USERS_ROUTE)) + } else { + dispatch( + setUsers({ + userListType: UserListType.FAVORITE, + entityType: UserListEntityType.COLLECTION, + id: collectionId + }) + ) + dispatch(setVisibility(true)) + } + }, [dispatch, isMobile, collectionId]) + + if (!playlist) return null + const { save_count = 0 } = playlist + + if (save_count === 0) return null + + return ( + + + {formatCount(save_count)} + + ) +} diff --git a/packages/web/src/components/collection/CollectionTileStats.tsx b/packages/web/src/components/collection/CollectionTileStats.tsx new file mode 100644 index 00000000000..8cf504f59cc --- /dev/null +++ b/packages/web/src/components/collection/CollectionTileStats.tsx @@ -0,0 +1,64 @@ +import { useGetPlaylistById } from '@audius/common/api' +import { ID } from '@audius/common/models' +import { Flex, Skeleton } from '@audius/harmony' + +import { EntityRank } from 'components/lineup/EntityRank' +import { TrackTileSize } from 'components/track/types' +import { useIsMobile } from 'hooks/useIsMobile' + +import { CollectionAccessTypeLabel } from './CollectionAccessTypeLabel' +import { + CollectionLockedStatusPill, + useIsCollectionUnlockable +} from './CollectionLockedStatusPill' +import { RepostsMetric, SavesMetric } from './CollectionTileMetrics' + +type CollectionTileStatsProps = { + collectionId: ID + isTrending?: boolean + rankIndex?: number + size: TrackTileSize + isLoading?: boolean +} + +export const CollectionTileStats = (props: CollectionTileStatsProps) => { + const { collectionId, isTrending, rankIndex, size, isLoading } = props + + const isMobile = useIsMobile() + const isUnlockable = useIsCollectionUnlockable(collectionId) + + const { data: collection } = useGetPlaylistById( + { playlistId: collectionId }, + { disabled: !!collectionId } + ) + + if (isLoading || !collection) { + return + } + + const { is_private } = collection + + return ( + + + {isTrending && rankIndex !== undefined ? ( + + ) : null} + + {is_private ? null : ( + <> + + + + )} + + {isUnlockable ? ( + + ) : null} + + ) +} diff --git a/packages/web/src/components/entity/VanityMetrics.tsx b/packages/web/src/components/entity/VanityMetrics.tsx new file mode 100644 index 00000000000..caa8ff91fbb --- /dev/null +++ b/packages/web/src/components/entity/VanityMetrics.tsx @@ -0,0 +1,48 @@ +import { useCallback, MouseEvent } from 'react' + +import { ID } from '@audius/common/models' +import { cacheUsersSelectors } from '@audius/common/store' +import { Text } from '@audius/harmony' + +import { TextLink, TextLinkProps } from 'components/link' +import { useSelector } from 'utils/reducer' + +const { getUser } = cacheUsersSelectors + +type VanityMetricProps = TextLinkProps + +export const VanityMetric = (props: VanityMetricProps) => { + const { children, onClick, ...other } = props + const handleClick = useCallback( + (e: MouseEvent) => { + e.stopPropagation() + onClick?.(e) + }, + [onClick] + ) + return ( + ({ + gap: theme.spacing.xs, + alignItems: 'center', + flexWrap: 'nowrap', + whiteSpace: 'nowrap' + })} + onClick={handleClick} + {...other} + > + {children} + + ) +} + +export const UserName = (props: { userId: ID }) => { + const { userId } = props + const userName = useSelector((state) => getUser(state, { id: userId })?.name) + + return {userName} +} diff --git a/packages/web/src/components/lineup/EntityRank.tsx b/packages/web/src/components/lineup/EntityRank.tsx index 6667072bb1b..2b40c7413b6 100644 --- a/packages/web/src/components/lineup/EntityRank.tsx +++ b/packages/web/src/components/lineup/EntityRank.tsx @@ -1,13 +1,14 @@ import { Flex, Text, IconCrown, IconTrending } from '@audius/harmony' +const RANK_ICON_COUNT = 5 + type EntityRankType = { - type: 'crown' | 'trending' index: number } export const EntityRank = (props: EntityRankType) => { - const { type, index } = props - const Icon = type === 'crown' ? IconCrown : IconTrending + const { index } = props + const Icon = RANK_ICON_COUNT <= 5 ? IconCrown : IconTrending return ( diff --git a/packages/web/src/components/lineup/LineupProvider.tsx b/packages/web/src/components/lineup/LineupProvider.tsx index 5bc8733988f..03a12c950ce 100644 --- a/packages/web/src/components/lineup/LineupProvider.tsx +++ b/packages/web/src/components/lineup/LineupProvider.tsx @@ -206,9 +206,6 @@ export interface LineupProviderProps { /** Whether we are in the feed lineup */ showFeedTipTile?: boolean - /** How many icons to show for top ranked entries in the lineup. Defaults to 0, showing none */ - rankIconCount?: number - /** Function triggered on click of tile */ onClickTile?: (trackId: ID) => void } @@ -489,7 +486,6 @@ class LineupProvider extends PureComponent { numPlaylistSkeletonRows, isTrending = false, showFeedTipTile = false, - rankIconCount = 0, onClickTile } = this.props const isMobile = this.context.isMobile @@ -541,7 +537,6 @@ class LineupProvider extends PureComponent { isLoading: !this.canLoad(index), hasLoaded: this.hasLoaded, isTrending, - showRankIcon: index < rankIconCount, showFeedTipTile, onClick: onClickTile, source: ModalSource.LineUpTrackTile @@ -568,7 +563,6 @@ class LineupProvider extends PureComponent { hasLoaded: this.hasLoaded, numLoadingSkeletonRows: numPlaylistSkeletonRows, isTrending, - showRankIcon: index < rankIconCount, showFeedTipTile, source: ModalSource.LineUpCollectionTile } diff --git a/packages/web/src/components/lineup/hooks.ts b/packages/web/src/components/lineup/hooks.ts index cfc4ba8b8fb..47d1d0f66b4 100644 --- a/packages/web/src/components/lineup/hooks.ts +++ b/packages/web/src/components/lineup/hooks.ts @@ -25,7 +25,6 @@ type useLineupPropsProps = { variant?: LineupVariant numPlaylistSkeletonRows?: number scrollParent?: HTMLElement - rankIconCount?: number isTrending?: boolean isOrdered?: boolean } @@ -41,7 +40,6 @@ export const useLineupProps = ({ variant, numPlaylistSkeletonRows, scrollParent, - rankIconCount, isTrending, isOrdered }: useLineupPropsProps) => { @@ -85,7 +83,6 @@ export const useLineupProps = ({ numPlaylistSkeletonRows, scrollParent, isMobile, - rankIconCount, isTrending, ordered: isOrdered } diff --git a/packages/web/src/components/link/TextLink.tsx b/packages/web/src/components/link/TextLink.tsx index 2f9f6da05a7..61e4d1cb90d 100644 --- a/packages/web/src/components/link/TextLink.tsx +++ b/packages/web/src/components/link/TextLink.tsx @@ -10,7 +10,7 @@ import { Link, LinkProps } from 'react-router-dom' export type LinkKind = 'track' | 'collection' | 'user' | 'mention' | 'other' export type TextLinkProps = HarmonyTextLinkProps & - Omit & { + Partial> & { stopPropagation?: boolean onClick?: ( e: MouseEvent, @@ -34,7 +34,7 @@ export const TextLink = forwardRef((props: TextLinkProps, ref: Ref<'a'>) => { return ( - {children} + {to ? {children} : {children}} ) }) diff --git a/packages/web/src/components/link/UserLink.tsx b/packages/web/src/components/link/UserLink.tsx index 46e57e55f9e..2ddbfcb7696 100644 --- a/packages/web/src/components/link/UserLink.tsx +++ b/packages/web/src/components/link/UserLink.tsx @@ -20,6 +20,7 @@ type UserLinkProps = Omit & { popover?: boolean popoverMount?: MountPlacement noText?: boolean // Should be used if you're intending for the children to be the link element (i.e. Avatar) + noBadges?: boolean } export const UserLink = (props: UserLinkProps) => { @@ -30,6 +31,7 @@ export const UserLink = (props: UserLinkProps) => { popoverMount, children, noText, + noBadges, ...other } = props const { iconSizes, spacing } = useTheme() @@ -54,11 +56,13 @@ export const UserLink = (props: UserLinkProps) => { {...other} > {userName} - + {noBadges ? null : ( + + )} {children} ) diff --git a/packages/web/src/components/track/TrackLockedStatusPill.tsx b/packages/web/src/components/track/TrackLockedStatusPill.tsx new file mode 100644 index 00000000000..0aa9ebbcbfd --- /dev/null +++ b/packages/web/src/components/track/TrackLockedStatusPill.tsx @@ -0,0 +1,61 @@ +import { useGetTrackById } from '@audius/common/api' +import { useGatedContentAccess } from '@audius/common/hooks' +import { + ID, + isContentCollectibleGated, + isContentSpecialAccess, + isContentUSDCPurchaseGated, + Track +} from '@audius/common/models' +import { Nullable } from '@audius/common/utils' + +import { + LockedStatusPill, + LockedStatusPillProps +} from 'components/locked-status-pill' + +type TrackLockedStatusPillProps = { + trackId: ID +} + +export const TrackLockedStatusPill = (props: TrackLockedStatusPillProps) => { + const { trackId } = props + const { data: track } = useGetTrackById( + { id: trackId }, + { disabled: !trackId } + ) + + const { hasStreamAccess } = useGatedContentAccess(track as Nullable) + + if (!track) return null + const { stream_conditions } = track + + const isPurchaseable = isContentUSDCPurchaseGated(stream_conditions) + const isCollectibleGated = isContentCollectibleGated(stream_conditions) + const isSpecialAccess = isContentSpecialAccess(stream_conditions) + + let variant: Nullable = null + if (isPurchaseable) { + variant = 'premium' + } else if (isCollectibleGated) { + variant = 'gated' + } else if (isSpecialAccess) { + variant = 'gated' + } + + if (!variant) return null + + return +} + +export const useIsTrackUnlockable = (trackId: ID) => { + const { data: track } = useGetTrackById({ id: trackId }) + + if (!track) return false + const { stream_conditions } = track + const isPurchaseable = isContentUSDCPurchaseGated(stream_conditions) + const isCollectibleGated = isContentCollectibleGated(stream_conditions) + const isSpecialAccess = isContentSpecialAccess(stream_conditions) + + return isPurchaseable || isCollectibleGated || isSpecialAccess +} diff --git a/packages/web/src/components/track/TrackTileMetrics.tsx b/packages/web/src/components/track/TrackTileMetrics.tsx new file mode 100644 index 00000000000..0902476be57 --- /dev/null +++ b/packages/web/src/components/track/TrackTileMetrics.tsx @@ -0,0 +1,212 @@ +import { useCallback } from 'react' + +import { useGetTrackById } from '@audius/common/api' +import { ID, Name } from '@audius/common/models' +import { + cacheUsersSelectors, + repostsUserListActions, + RepostType +} from '@audius/common/store' +import { formatCount, route } from '@audius/common/utils' +import { IconMessage, Text, Flex, IconRepost, IconHeart } from '@audius/harmony' +import { push } from 'connected-react-router' +import { useDispatch } from 'react-redux' + +import { AvatarList } from 'components/avatar' +import { VanityMetric } from 'components/entity/VanityMetrics' +import { TrackTileSize } from 'components/track/types' +import { useIsMobile } from 'hooks/useIsMobile' +import { make, track as trackEvent } from 'services/analytics' +import { + setUsers, + setVisibility +} from 'store/application/ui/userListModal/slice' +import { + UserListEntityType, + UserListType +} from 'store/application/ui/userListModal/types' +import { useSelector } from 'utils/reducer' +import { pluralize } from 'utils/stringUtils' + +const { REPOSTING_USERS_ROUTE, FAVORITING_USERS_ROUTE } = route +const { getUser } = cacheUsersSelectors +const { setRepost } = repostsUserListActions + +const UserName = (props: { userId: ID }) => { + const { userId } = props + const userName = useSelector((state) => getUser(state, { id: userId })?.name) + + return {userName} +} + +type RepostsMetricProps = { + trackId: ID + size?: TrackTileSize +} + +export const RepostsMetric = (props: RepostsMetricProps) => { + const { trackId, size } = props + const { data: track } = useGetTrackById( + { id: trackId }, + { disabled: !trackId } + ) + const isMobile = useIsMobile() + const dispatch = useDispatch() + + const handleClick = useCallback(() => { + if (isMobile) { + dispatch(setRepost(trackId, RepostType.TRACK)) + dispatch(push(REPOSTING_USERS_ROUTE)) + } else { + dispatch( + setUsers({ + userListType: UserListType.REPOST, + entityType: UserListEntityType.TRACK, + id: trackId + }) + ) + dispatch(setVisibility(true)) + } + }, [dispatch, isMobile, trackId]) + + if (!track) return null + const { repost_count = 0, followee_reposts = [] } = track + + if (repost_count === 0) return null + + const renderName = () => { + const [{ user_id }] = followee_reposts + + const remainingCount = repost_count - 1 + const remainingText = + remainingCount > 0 + ? ` + ${formatCount(remainingCount)} ${pluralize( + 'Repost', + remainingCount + )}` + : ' Reposted' + + return ( + + + {remainingText} + + ) + } + + const isLargeSize = size === TrackTileSize.LARGE && !isMobile + + return ( + ({ gap: theme.spacing.l })} + onClick={handleClick} + > + {isLargeSize && followee_reposts.length >= 3 ? ( + user_id)} /> + ) : null} + + + {isLargeSize && followee_reposts.length > 0 + ? renderName() + : formatCount(repost_count)} + + + ) +} + +type SavesMetricProps = { + trackId: ID +} + +export const SavesMetric = (props: SavesMetricProps) => { + const { trackId } = props + const { data: track } = useGetTrackById( + { id: trackId }, + { disabled: !trackId } + ) + const isMobile = useIsMobile() + const dispatch = useDispatch() + + const handleClick = useCallback(() => { + if (isMobile) { + dispatch(setRepost(trackId, RepostType.TRACK)) + dispatch(push(FAVORITING_USERS_ROUTE)) + } else { + dispatch( + setUsers({ + userListType: UserListType.FAVORITE, + entityType: UserListEntityType.TRACK, + id: trackId + }) + ) + dispatch(setVisibility(true)) + } + }, [dispatch, isMobile, trackId]) + + if (!track) return null + const { save_count = 0 } = track + + if (save_count === 0) return null + + return ( + + + {formatCount(save_count)} + + ) +} + +type CommentMetricProps = { + trackId: ID +} + +export const CommentMetric = (props: CommentMetricProps) => { + const { trackId } = props + const isMobile = useIsMobile() + const { data: track } = useGetTrackById( + { id: trackId }, + { disabled: !trackId } + ) + + const handleClick = useCallback(() => { + trackEvent( + make({ + eventName: Name.COMMENTS_CLICK_COMMENT_STAT, + trackId, + source: 'lineup' + }) + ) + }, [trackId]) + + if (!track) return null + const { comment_count = 0, permalink, comments_disabled } = track + if (comments_disabled) return null + + const url = isMobile + ? `${permalink}/comments` + : `${permalink}?showComments=true` + + return ( + + + {comment_count > 0 ? formatCount(comment_count) : 'Leave a comment'} + + ) +} + +type PlayMetricProps = { + trackId: ID +} + +export const PlayMetric = (props: PlayMetricProps) => { + const { trackId } = props + const { data: track } = useGetTrackById( + { id: trackId }, + { disabled: !trackId } + ) + if (!track) return null + const { play_count } = track + if (play_count === 0) return null + + return {formatCount(play_count)} Plays +} diff --git a/packages/web/src/components/track/TrackTileStats.tsx b/packages/web/src/components/track/TrackTileStats.tsx new file mode 100644 index 00000000000..d0dc222db35 --- /dev/null +++ b/packages/web/src/components/track/TrackTileStats.tsx @@ -0,0 +1,70 @@ +import { useGetTrackById } from '@audius/common/api' +import { ID } from '@audius/common/models' +import { Flex, Skeleton } from '@audius/harmony' + +import { EntityRank } from 'components/lineup/EntityRank' +import { useIsMobile } from 'hooks/useIsMobile' + +import { TrackAccessTypeLabel } from './TrackAccessTypeLabel' +import { + TrackLockedStatusPill, + useIsTrackUnlockable +} from './TrackLockedStatusPill' +import { + CommentMetric, + PlayMetric, + RepostsMetric, + SavesMetric +} from './TrackTileMetrics' +import { TrackTileSize } from './types' + +type TrackTileStatsProps = { + trackId: ID + isTrending?: boolean + rankIndex?: number + size: TrackTileSize + isLoading?: boolean +} + +export const TrackTileStats = (props: TrackTileStatsProps) => { + const { trackId, isTrending, rankIndex, size, isLoading } = props + + const isUnlockable = useIsTrackUnlockable(trackId) + const isMobile = useIsMobile() + + const { data: track } = useGetTrackById( + { id: trackId }, + { disabled: !!trackId } + ) + + if (isLoading || !track) { + return + } + + const { is_unlisted } = track + + return ( + + + {isTrending ? : null} + + {is_unlisted ? null : ( + <> + + + + + )} + + {isUnlockable ? ( + + ) : is_unlisted ? null : ( + + )} + + ) +} diff --git a/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx b/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx index 9e38448203f..1834d50ae64 100644 --- a/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx +++ b/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx @@ -47,14 +47,6 @@ import Menu from 'components/menu/Menu' import { CollectionArtwork } from 'components/track/Artwork' import { TrackTileSize } from 'components/track/types' import { useRequiresAccountOnClick } from 'hooks/useRequiresAccount' -import { - setUsers, - setVisibility -} from 'store/application/ui/userListModal/slice' -import { - UserListType, - UserListEntityType -} from 'store/application/ui/userListModal/types' import { AppState } from 'store/types' import { isDescendantElementOf } from 'utils/domUtils' import { fullCollectionPage, fullTrackPage } from 'utils/route' @@ -65,8 +57,6 @@ import { getCollectionWithFallback, getUserWithFallback } from '../helpers' import styles from './ConnectedPlaylistTile.module.css' import PlaylistTile from './PlaylistTile' import TrackListItem from './TrackListItem' -import Stats from './stats/Stats' -import { Flavor } from './stats/StatsText' const { getUid, getBuffering, getPlaying } = playerSelectors const { requestOpen: requestOpenShareModal } = shareModalUIActions const { getUserFromCollection } = cacheUsersSelectors @@ -95,7 +85,6 @@ type OwnProps = { hasLoaded: (index: number) => void numLoadingSkeletonRows?: number isTrending: boolean - showRankIcon: boolean isFeed: boolean source?: ModalSource } @@ -126,16 +115,12 @@ const ConnectedPlaylistTile = ({ numLoadingSkeletonRows, isUploading, hasLoaded, - setRepostUsers, - setFavoriteUsers, - setModalVisibility, shareCollection, repostCollection, undoRepostCollection, saveCollection, unsaveCollection, isTrending, - showRankIcon, isFeed = false, source }: ConnectedPlaylistTileProps) => { @@ -145,10 +130,6 @@ const ConnectedPlaylistTile = ({ playlist_id: id, is_private: isUnlisted, _cover_art_sizes: coverArtSizes, - repost_count: repostCount, - save_count: saveCount, - followee_reposts: followeeReposts, - followee_saves: followeeSaves, has_current_user_reposted: isReposted, has_current_user_saved: isFavorited, track_count: trackCount, @@ -326,42 +307,6 @@ const ConnectedPlaylistTile = ({ ) - const onClickStatFavorite = useCallback(() => { - setFavoriteUsers(id!) - setModalVisibility() - }, [setFavoriteUsers, id, setModalVisibility]) - - const onClickStatRepost = useCallback(() => { - setRepostUsers(id!) - setModalVisibility() - }, [setRepostUsers, id, setModalVisibility]) - - const renderStats = () => { - const contentTitle = isAlbum ? 'album' : 'playlist' - const sz = 'large' - return ( -
- - -
- ) - } - const onClickFavorite = useCallback(() => { if (isFavorited) { unsaveCollection(id) @@ -479,7 +424,6 @@ const ConnectedPlaylistTile = ({ ]) const artwork = renderImage() - const stats = renderStats() const rightActions = renderOverflowMenu() const trackList = renderTrackList() @@ -504,13 +448,11 @@ const ConnectedPlaylistTile = ({ isDarkMode={isDarkMode()} isMatrixMode={isMatrix()} isActive={isActive} - isUnlisted={isUnlisted} isPlaying={isPlaylistPlaying} artwork={artwork} rightActions={rightActions} title={title} userName={userName} - stats={stats} header={header} onClickTitle={onClickTitle} onClickRepost={onClickRepost} @@ -536,7 +478,6 @@ const ConnectedPlaylistTile = ({ trackList={trackList} trackCount={trackCount} isTrending={isTrending} - showRankIcon={showRankIcon} href={href} hasStreamAccess={hasStreamAccess} streamConditions={isStreamGated ? streamConditions : null} @@ -578,25 +519,7 @@ function mapDispatchToProps(dispatch: Dispatch) { saveCollection: (id: ID, isFeed: boolean) => dispatch(saveCollection(id, FavoriteSource.TILE, isFeed)), unsaveCollection: (id: ID) => - dispatch(unsaveCollection(id, FavoriteSource.TILE)), - - setRepostUsers: (trackID: ID) => - dispatch( - setUsers({ - userListType: UserListType.REPOST, - entityType: UserListEntityType.COLLECTION, - id: trackID - }) - ), - setFavoriteUsers: (trackID: ID) => - dispatch( - setUsers({ - userListType: UserListType.FAVORITE, - entityType: UserListEntityType.COLLECTION, - id: trackID - }) - ), - setModalVisibility: () => dispatch(setVisibility(true)) + dispatch(unsaveCollection(id, FavoriteSource.TILE)) } } diff --git a/packages/web/src/components/track/desktop/ConnectedTrackTile.module.css b/packages/web/src/components/track/desktop/ConnectedTrackTile.module.css index e81dbd004cd..739600b8e9a 100644 --- a/packages/web/src/components/track/desktop/ConnectedTrackTile.module.css +++ b/packages/web/src/components/track/desktop/ConnectedTrackTile.module.css @@ -52,13 +52,6 @@ color: var(--harmony-primary); } -.socialInfo { - display: inline-flex; - flex: 1 1 100%; - min-width: 0; - justify-content: flex-start; -} - .iconKebabHorizontal path { fill: var(--harmony-n-400); } diff --git a/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx b/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx index cc06d7649fe..6c888416d98 100644 --- a/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx +++ b/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx @@ -1,22 +1,13 @@ -import { - memo, - useCallback, - useEffect, - MouseEvent, - useRef, - useMemo -} from 'react' - -import { useFeatureFlag, useGatedContentAccess } from '@audius/common/hooks' +import { memo, useCallback, useEffect, MouseEvent, useRef } from 'react' + +import { useGatedContentAccess } from '@audius/common/hooks' import { ShareSource, RepostSource, FavoriteSource, ID, - UID, - Name + UID } from '@audius/common/models' -import { FeatureFlags } from '@audius/common/services' import { accountSelectors, cacheTracksSelectors, @@ -29,7 +20,6 @@ import { import { Genre } from '@audius/common/utils' import { IconKebabHorizontal } from '@audius/harmony' import cn from 'classnames' -import { push } from 'connected-react-router' import { connect, useDispatch } from 'react-redux' import { Dispatch } from 'redux' @@ -39,15 +29,6 @@ import { UserLink } from 'components/link' import Menu from 'components/menu/Menu' import { OwnProps as TrackMenuProps } from 'components/menu/TrackMenu' import { TrackArtwork } from 'components/track/Artwork' -import { make, track as trackEvent } from 'services/analytics' -import { - setUsers, - setVisibility -} from 'store/application/ui/userListModal/slice' -import { - UserListType, - UserListEntityType -} from 'store/application/ui/userListModal/types' import { AppState } from 'store/types' import { isDescendantElementOf } from 'utils/domUtils' import { fullTrackPage } from 'utils/route' @@ -58,8 +39,6 @@ import { TrackTileSize } from '../types' import styles from './ConnectedTrackTile.module.css' import TrackTile from './TrackTile' -import Stats from './stats/Stats' -import { Flavor } from './stats/StatsText' const { getUid, getPlaying, getBuffering } = playerSelectors const { requestOpen: requestOpenShareModal } = shareModalUIActions const { getTrack } = cacheTracksSelectors @@ -81,7 +60,6 @@ type OwnProps = { isLoading: boolean hasLoaded: (index: number) => void isTrending: boolean - showRankIcon: boolean isFeed: boolean onClick?: (trackId: ID) => void } @@ -104,9 +82,6 @@ const ConnectedTrackTile = ({ isLoading, hasLoaded, containerClassName, - setRepostUsers, - setFavoriteUsers, - setModalVisibility, userHandle, saveTrack, unsaveTrack, @@ -115,10 +90,7 @@ const ConnectedTrackTile = ({ shareTrack, isTrending, isFeed = false, - showRankIcon, - onClick, - statSize = 'large', - goToRoute + onClick }: ConnectedTrackTileProps) => { const trackWithFallback = getTrackWithFallback(track) const { @@ -130,18 +102,10 @@ const ConnectedTrackTile = ({ title, genre, permalink, - repost_count, - save_count, - comment_count, - comments_disabled, - field_visibility: fieldVisibility, - followee_reposts, - followee_saves, _co_sign: coSign, has_current_user_reposted: isReposted, has_current_user_saved: isFavorited, _cover_art_sizes, - play_count, duration, ddex_app: ddexApp } = trackWithFallback @@ -154,10 +118,6 @@ const ConnectedTrackTile = ({ artist_pick_track_id } = getUserWithFallback(user) - const { isEnabled: isCommentsEnabled } = useFeatureFlag( - FeatureFlags.COMMENTS_ENABLED - ) - const isActive = uid === playingUid const isTrackBuffering = isActive && isBuffering const isTrackPlaying = isActive && isPlaying @@ -173,28 +133,6 @@ const ConnectedTrackTile = ({ const [, setLockedContentVisibility] = useModalState('LockedContent') const menuRef = useRef(null) - const onClickStatRepost = () => { - setRepostUsers(trackId) - setModalVisibility() - } - - const onClickStatFavorite = () => { - setFavoriteUsers(trackId) - setModalVisibility() - } - - const onClickStatComment = () => { - goToRoute(permalink + '?showComments=true') - - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_COMMENT_STAT, - trackId, - source: 'lineup' - }) - ) - } - useEffect(() => { if (!loading && hasLoaded) { hasLoaded(index) @@ -272,63 +210,6 @@ const ConnectedTrackTile = ({ ) - const followeeRepostsTruncated = useMemo( - () => (followee_reposts ?? []).slice(0, 1), - [followee_reposts] - ) - - const followeeSavesTruncated = useMemo(() => { - const [firstSave, secondSave] = followee_saves ?? [] - const [firstRepost] = followee_reposts ?? [] - - // If the first followee save is not the same as the first followee repost, - // then we should show the first followee save. Otherwise, we should show - // the second followee save. - if (firstSave && firstSave.user_id !== firstRepost?.user_id) { - return [firstSave] - } else if (secondSave) { - return [secondSave] - } - return [] - }, [followee_saves, followee_reposts]) - - const renderStats = () => { - const contentTitle = 'track' // undefined, playlist or album - undefined is track - return ( -
- - - {!isCommentsEnabled || comments_disabled ? null : ( - - )} -
- ) - } - const onClickFavorite = useCallback(() => { if (isFavorited) { unsaveTrack(trackId) @@ -399,7 +280,6 @@ const ConnectedTrackTile = ({ const order = ordered && index !== undefined ? index + 1 : undefined const artwork = renderImage() - const stats = renderStats() const rightActions = renderOverflowMenu() const disableActions = false @@ -413,14 +293,11 @@ const ConnectedTrackTile = ({ isFavorited={isFavorited} isReposted={isReposted} isOwner={isOwner} - isUnlisted={isUnlisted} - isStreamGated={isStreamGated} streamConditions={streamConditions} hasStreamAccess={hasStreamAccess} isLoading={loading} isDarkMode={isDarkMode()} isMatrixMode={isMatrix()} - listenCount={play_count} isActive={isActive} isPlaying={isTrackPlaying} artwork={artwork} @@ -429,8 +306,6 @@ const ConnectedTrackTile = ({ genre={genre as Genre} userName={userName} duration={duration} - stats={stats} - fieldVisibility={fieldVisibility} containerClassName={cn(styles.container, { [containerClassName!]: !!containerClassName, [styles.loading]: loading, @@ -443,7 +318,6 @@ const ConnectedTrackTile = ({ onTogglePlay={onTogglePlay} onClickTitle={onClickTitle} isTrending={isTrending} - showRankIcon={showRankIcon} permalink={permalink} trackId={trackId} isTrack @@ -496,26 +370,7 @@ function mapDispatchToProps(dispatch: Dispatch) { saveTrack: (trackId: ID, isFeed: boolean) => dispatch(saveTrack(trackId, FavoriteSource.TILE, isFeed)), unsaveTrack: (trackId: ID) => - dispatch(unsaveTrack(trackId, FavoriteSource.TILE)), - - setRepostUsers: (trackID: ID) => - dispatch( - setUsers({ - userListType: UserListType.REPOST, - entityType: UserListEntityType.TRACK, - id: trackID - }) - ), - setFavoriteUsers: (trackID: ID) => - dispatch( - setUsers({ - userListType: UserListType.FAVORITE, - entityType: UserListEntityType.TRACK, - id: trackID - }) - ), - setModalVisibility: () => dispatch(setVisibility(true)), - goToRoute: (route: string) => dispatch(push(route)) + dispatch(unsaveTrack(trackId, FavoriteSource.TILE)) } } diff --git a/packages/web/src/components/track/desktop/PlaylistTile.tsx b/packages/web/src/components/track/desktop/PlaylistTile.tsx index 166309ef965..f98a1b63945 100644 --- a/packages/web/src/components/track/desktop/PlaylistTile.tsx +++ b/packages/web/src/components/track/desktop/PlaylistTile.tsx @@ -45,7 +45,6 @@ const PlaylistTile = ({ title, userName, duration, - stats, bottomBar, showIconButtons = true, containerClassName, @@ -60,7 +59,6 @@ const PlaylistTile = ({ trackList, trackCount, isTrending, - showRankIcon, href, hasStreamAccess, streamConditions, @@ -128,7 +126,6 @@ const PlaylistTile = ({ title={title} userName={userName} duration={duration} - stats={stats} bottomBar={bottomBar} showIconButtons={showIconButtons} containerClassName={tileClassName} @@ -136,13 +133,12 @@ const PlaylistTile = ({ onClickFavorite={onClickFavorite} onClickShare={onClickShare} onTogglePlay={onTogglePlay} - showRankIcon={showRankIcon} isTrending={isTrending} permalink={href} - isStreamGated={!!streamConditions} streamConditions={streamConditions} hasStreamAccess={hasStreamAccess} source={source} + collectionId={playlistId} /> diff --git a/packages/web/src/components/track/desktop/TrackTile.tsx b/packages/web/src/components/track/desktop/TrackTile.tsx index 92ed2574da9..108b1cbd2da 100644 --- a/packages/web/src/components/track/desktop/TrackTile.tsx +++ b/packages/web/src/components/track/desktop/TrackTile.tsx @@ -8,11 +8,7 @@ import { CommonState, PurchaseableContentType } from '@audius/common/store' -import { - formatCount, - Genre, - formatLineupTileDuration -} from '@audius/common/utils' +import { Genre, formatLineupTileDuration } from '@audius/common/utils' import { IconVolumeLevel2 as IconVolume, IconCheck, @@ -26,18 +22,14 @@ import cn from 'classnames' import { useSelector } from 'react-redux' import { CollectionDogEar } from 'components/collection' -import { CollectionAccessTypeLabel } from 'components/collection/CollectionAccessTypeLabel' +import { CollectionTileStats } from 'components/collection/CollectionTileStats' import { TextLink } from 'components/link' import Skeleton from 'components/skeleton/Skeleton' import { useRequiresAccountOnClick } from 'hooks/useRequiresAccount' -import { - LockedStatusPill, - LockedStatusPillProps -} from '../../locked-status-pill' import { OwnerActionButtons } from '../OwnerActionButtons' -import { TrackAccessTypeLabel } from '../TrackAccessTypeLabel' import { TrackDogEar } from '../TrackDogEar' +import { TrackTileStats } from '../TrackTileStats' import { ViewerActionButtons } from '../ViewerActionButtons' import { messages } from '../trackTileMessages' import { @@ -52,12 +44,10 @@ const { getTrackPosition } = playbackPositionSelectors const RankAndIndexIndicator = ({ hasOrdering, - showCrownIcon, isLoading, index }: { hasOrdering: boolean - showCrownIcon: boolean isLoading: boolean index: number }) => { @@ -65,7 +55,7 @@ const RankAndIndexIndicator = ({ <> {hasOrdering && (
- {showCrownIcon && ( + {index <= 5 && (
@@ -77,46 +67,13 @@ const RankAndIndexIndicator = ({ ) } -const renderLockedContentOrPlayCount = ({ - hasStreamAccess, - isOwner, - isStreamGated, - listenCount, - variant -}: Pick< - TrackTileProps, - | 'hasStreamAccess' - | 'fieldVisibility' - | 'isOwner' - | 'isStreamGated' - | 'listenCount' -> & - Pick) => { - if (isStreamGated && !isOwner) { - return - } - - return ( - listenCount !== undefined && - listenCount > 0 && ( -
- {formatCount(listenCount)} - {messages.getPlays(listenCount)} -
- ) - ) -} - const TrackTile = ({ size, order, standalone, isOwner, - isUnlisted, - isStreamGated, streamConditions, hasStreamAccess, - listenCount, isActive, isDisabled, isLoading, @@ -128,8 +85,6 @@ const TrackTile = ({ genre, userName, duration, - stats, - fieldVisibility, bottomBar, isDarkMode, isMatrixMode, @@ -141,7 +96,6 @@ const TrackTile = ({ onClickShare, onClickLocked, onTogglePlay, - showRankIcon, permalink, isTrack, collectionId, @@ -231,7 +185,6 @@ const TrackTile = ({ {/* prefix ordering */} @@ -280,37 +233,26 @@ const TrackTile = ({ )} {isLoading ? : userName} - - - {isLoading ? ( - - ) : ( - <> - {trackId ? : null} - {collectionId ? ( - - ) : null} - {isUnlisted ? null : stats} - - )} - + {trackId ? ( + + ) : null} + {collectionId ? ( + + ) : null} {!isLoading && duration !== null && duration !== undefined ? (
{getDurationText()}
) : null}
- - {!isLoading - ? renderLockedContentOrPlayCount({ - hasStreamAccess, - fieldVisibility, - isOwner, - isStreamGated, - listenCount, - variant: isPurchase ? 'premium' : 'gated' - }) - : null} - {isTrack && trackId ? ( <> diff --git a/packages/web/src/components/track/desktop/stats/Stats.module.css b/packages/web/src/components/track/desktop/stats/Stats.module.css deleted file mode 100644 index 6dc2831ead4..00000000000 --- a/packages/web/src/components/track/desktop/stats/Stats.module.css +++ /dev/null @@ -1,57 +0,0 @@ -.root { - max-width: calc(50% - var(--harmony-unit-4)); - margin-right: var(--harmony-unit-4); - display: flex; - align-items: center; -} - -.large { - font-size: var(--harmony-font-xs); - font-weight: var(--harmony-font-demi-bold); -} - -.medium, -.small { - font-size: var(--harmony-font-xs); - font-weight: var(--harmony-font-demi-bold); - letter-spacing: 0.25px; -} - -.profileImages { - display: flex; - margin-right: 4px; -} - -.hide { - opacity: 0; -} - -.show { - opacity: 1; - transition: opacity ease-in-out 0.5s; - display: inline-flex; -} - -.showNonEmpty:hover * { - color: var(--harmony-primary); -} - -.showNonEmpty:hover path { - fill: var(--harmony-primary); -} - -.text { - color: var(--harmony-n-400); - min-width: 0; - display: inline-flex; - align-items: center; -} - -.text span { - margin-left: 4px; - margin-top: 1px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - line-height: normal; -} diff --git a/packages/web/src/components/track/desktop/stats/Stats.tsx b/packages/web/src/components/track/desktop/stats/Stats.tsx deleted file mode 100644 index 0ee5ded7d5d..00000000000 --- a/packages/web/src/components/track/desktop/stats/Stats.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { memo, useMemo, MouseEvent, useCallback } from 'react' - -import { Favorite, ID, Repost } from '@audius/common/models' -import { cacheUsersSelectors, CommonState } from '@audius/common/store' -import { createShallowSelector } from '@audius/common/utils' -import { - IconHeart as IconFavorite, - IconMessage, - IconRepost -} from '@audius/harmony' -import cn from 'classnames' -import { useSelector } from 'react-redux' - -import ProfileImage from './ProfileImage' -import styles from './Stats.module.css' -import { StatsText, Flavor } from './StatsText' -const { getUsers } = cacheUsersSelectors - -const MAX_IMAGES = 3 - -const makeFolloweeActionsUsers = () => - createShallowSelector( - [getUsers, (_state: CommonState, userIds: ID[]) => userIds], - (users, userIds) => - userIds - ? userIds.map((id) => users[id]).filter((u) => !!u && !u.is_deactivated) - : [] - ) - -type StatsProps = { - count: number - followeeActions?: Repost[] | Favorite[] - size: 'small' | 'medium' | 'large' - showSkeleton?: boolean - contentTitle: string - onClick?: () => void - flavor: Flavor - hideImage?: boolean - isOwner?: boolean -} - -const Stats = memo((props: StatsProps) => { - const { - count, - followeeActions = [], - size, - showSkeleton, - contentTitle, - onClick, - flavor, - hideImage, - isOwner - } = props - - const handleClick = useCallback( - (e: MouseEvent) => { - if (!onClick || !count) return - e.stopPropagation() - onClick() - }, - [count, onClick] - ) - - const getFolloweeActionsUsers = useMemo(makeFolloweeActionsUsers, []) - const followeeActionUsers = useSelector((state: CommonState) => - getFolloweeActionsUsers( - state, - (followeeActions as Array).map( - (a: Repost | Favorite) => a.user_id - ) - ) - ) - - const profileImages = followeeActionUsers - .slice(0, MAX_IMAGES) - .map((item) => ) - - const Icon = - flavor === Flavor.REPOST - ? IconRepost - : flavor === Flavor.FAVORITE - ? IconFavorite - : IconMessage - - return ( -
- {size === 'large' && - flavor === Flavor.REPOST && - !hideImage && - profileImages.length > 0 ? ( -
{profileImages}
- ) : null} - - {/* TODO: css hack to align the text. We need to fix the icon so we can use flex alignment */} - - - -
- ) -}) - -export default Stats diff --git a/packages/web/src/components/track/desktop/stats/StatsText.module.css b/packages/web/src/components/track/desktop/stats/StatsText.module.css deleted file mode 100644 index b7b679f4c7e..00000000000 --- a/packages/web/src/components/track/desktop/stats/StatsText.module.css +++ /dev/null @@ -1,16 +0,0 @@ -.long { - margin-left: 4px; - margin-top: 1px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.first { - margin-left: 4px; - text-decoration: none !important; -} - -.end { - flex: 1 0 auto; -} diff --git a/packages/web/src/components/track/desktop/stats/StatsText.tsx b/packages/web/src/components/track/desktop/stats/StatsText.tsx deleted file mode 100644 index 53428790fc7..00000000000 --- a/packages/web/src/components/track/desktop/stats/StatsText.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { User } from '@audius/common/models' -import { formatCount, pluralize } from '@audius/common/utils' - -import styles from './StatsText.module.css' - -export enum Flavor { - REPOST = 'REPOST', - FAVORITE = 'FAVORITE', - COMMENT = 'COMMENT' -} - -const flavorize = ( - favoriteText: string, - repostText: string, - commentText: string, - flavor: Flavor -) => - flavor === Flavor.FAVORITE - ? favoriteText - : flavor === Flavor.REPOST - ? repostText - : commentText - -const formatEmptyState = ( - flavor: Flavor, - contentTitle?: string, - isOwner?: boolean -) => { - if (flavor === Flavor.FAVORITE) { - return '0 Favorites' - } - if (flavor === Flavor.REPOST) { - if (isOwner) { - return '0 Reposts' - } - return `Be the first to repost this ${ - contentTitle ? contentTitle.toLowerCase() : 'track' - }!` - } - if (flavor === Flavor.COMMENT) { - return '0 Comments' - } -} - -export const formatLongString = ( - flavor: Flavor, - count: number, - users: User[] -) => { - if (count <= 0) { - return { longString: '', endString: '0' } - } - if (users.length < 1) { - return { - longString: '', - endString: - formatCount(count) + - ` ${pluralize( - flavorize('Favorite', 'Repost', 'Comment', flavor), - count - )}` - } - } - - let longString = '' - let endString = '' - users.forEach((user, i) => { - if (i !== 0) { - longString += ', ' - } - longString += user.name - }) - - // Add count if there's remaining users - const remainingCount = count - users.length - if (remainingCount > 0) { - endString += ` + ${formatCount(remainingCount)} ` - } - - // If *just* followees of yours interacted, we need to say 'Favorited' (e.g. 'MyFollowee Favorited'), - // otherwise, it should be 'Favorite' or 'Favorites'. (e.g. '1 favorite', '5 favorites', 'MyFollowee + 6 Favorites') - if (remainingCount === 0) { - endString += ` ${flavorize('Favorited', 'Reposted', 'Commented', flavor)}` - } else { - endString += pluralize( - flavorize('Favorite', 'Repost', 'Comment', flavor), - remainingCount - ) - } - - return { longString, endString } -} - -type RepostTextProps = { - users: User[] - count: number - contentTitle: string - flavor: Flavor - size: 'small' | 'medium' | 'large' - isOwner?: boolean -} - -export const StatsText = (props: RepostTextProps) => { - const { users, count, contentTitle, flavor, size, isOwner } = props - if (size === 'small') { - return {formatCount(count)} - } - - if (count === 0) { - return ( - - {formatEmptyState(flavor, contentTitle, isOwner)} - - ) - } - - const { longString, endString } = formatLongString(flavor, count, users) - - return ( - <> - {longString ? {longString} : null} - {endString ? {endString} : null} - - ) -} diff --git a/packages/web/src/components/track/mobile/ConnectedPlaylistTile.tsx b/packages/web/src/components/track/mobile/ConnectedPlaylistTile.tsx index f66093ed1b6..80e66b962cc 100644 --- a/packages/web/src/components/track/mobile/ConnectedPlaylistTile.tsx +++ b/packages/web/src/components/track/mobile/ConnectedPlaylistTile.tsx @@ -115,7 +115,6 @@ const ConnectedPlaylistTile = ({ clickOverflow, currentUserId, darkMode, - showRankIcon, isTrending, variant, containerClassName, @@ -310,7 +309,7 @@ const ConnectedPlaylistTile = ({ isPlaying={isActive && isPlaying} isLoading={isActive && isBuffering} activeTrackUid={playingUid || null} - goToRoute={goToRoute} + isOwner={isOwner} goToCollectionPage={goToCollectionPage} toggleSave={toggleSave} toggleRepost={toggleRepost} @@ -318,11 +317,9 @@ const ConnectedPlaylistTile = ({ onClickOverflow={onClickOverflow} makeGoToRepostsPage={makeGoToRepostsPage} makeGoToFavoritesPage={makeGoToFavoritesPage} - isOwner={isOwner} darkMode={darkMode} isMatrix={isMatrix()} isTrending={isTrending} - showRankIcon={showRankIcon} variant={variant} isUnlisted={collection.is_private} isStreamGated={collection.is_stream_gated} diff --git a/packages/web/src/components/track/mobile/ConnectedTrackTile.tsx b/packages/web/src/components/track/mobile/ConnectedTrackTile.tsx index 2949e1f06ce..41899b0252d 100644 --- a/packages/web/src/components/track/mobile/ConnectedTrackTile.tsx +++ b/packages/web/src/components/track/mobile/ConnectedTrackTile.tsx @@ -1,13 +1,11 @@ -import { memo, MouseEvent } from 'react' +import { memo } from 'react' import { useGatedContentAccess } from '@audius/common/hooks' import { ShareSource, RepostSource, FavoriteSource, - FavoriteType, - ID, - Name + ID } from '@audius/common/models' import { FeatureFlags, trpc } from '@audius/common/services' import { @@ -20,14 +18,10 @@ import { themeSelectors, OverflowAction, OverflowSource, - repostsUserListActions, - favoritesUserListActions, - RepostType, playerSelectors } from '@audius/common/store' -import { Genre, route } from '@audius/common/utils' +import { Genre } from '@audius/common/utils' import { Box, IconButton, IconKebabHorizontal } from '@audius/harmony' -import { push as pushRoute } from 'connected-react-router' import { connect } from 'react-redux' import { Dispatch } from 'redux' @@ -35,17 +29,13 @@ import Menu from 'components/menu/Menu' import { OwnProps as TrackMenuProps } from 'components/menu/TrackMenu' import { TrackTileProps } from 'components/track/types' import { useFlag } from 'hooks/useRemoteConfig' -import { make, track as trackEvent } from 'services/analytics' import { AppState } from 'store/types' import { isMatrix, shouldShowDark } from 'utils/theme/theme' import { getTrackWithFallback, getUserWithFallback } from '../helpers' import TrackTile from './TrackTile' -const { REPOSTING_USERS_ROUTE, FAVORITING_USERS_ROUTE } = route const { getUid, getPlaying, getBuffering } = playerSelectors -const { setFavorite } = favoritesUserListActions -const { setRepost } = repostsUserListActions const { getTheme } = themeSelectors const { requestOpen: requestOpenShareModal } = shareModalUIActions const { open } = mobileOverflowMenuUIActions @@ -74,7 +64,6 @@ type OwnProps = Omit< | 'hasCurrentUserSaved' | 'artistIsVerified' | 'isPlaying' - | 'goToRoute' > type ConnectedTrackTileProps = OwnProps & @@ -89,7 +78,6 @@ const ConnectedTrackTile = ({ user, ordered, trackTileStyles, - goToRoute, togglePlay, isBuffering, isPlaying, @@ -102,12 +90,9 @@ const ConnectedTrackTile = ({ repostTrack, unrepostTrack, shareTrack, - setRepostTrackId, - setFavoriteTrackId, clickOverflow, darkMode, isTrending, - showRankIcon, isActive, variant, containerClassName, @@ -135,7 +120,6 @@ const ConnectedTrackTile = ({ has_current_user_saved, _cover_art_sizes, activity_timestamp, - play_count, _co_sign, is_scheduled_release: isScheduledRelease, release_date: releaseDate, @@ -180,32 +164,6 @@ const ConnectedTrackTile = ({ shareTrack(id) } - const makeGoToRepostsPage = (trackId: ID) => (e: MouseEvent) => { - e.stopPropagation() - setRepostTrackId(trackId) - goToRoute(REPOSTING_USERS_ROUTE) - } - - const makeGoToFavoritesPage = - (trackId: ID) => (e: MouseEvent) => { - e.stopPropagation() - setFavoriteTrackId(trackId) - goToRoute(FAVORITING_USERS_ROUTE) - } - - const makeGoToCommentsPage = (_: ID) => (e: MouseEvent) => { - e.stopPropagation() - goToRoute(track?.permalink + '?showComments=true') - - trackEvent( - make({ - eventName: Name.COMMENTS_CLICK_COMMENT_STAT, - trackId: track_id, - source: 'lineup' - }) - ) - } - // We wanted to use mobile track tile on desktop, which means shimming in the desktop overflow // menu whenever isMobile is false. const renderOverflowMenu = () => { @@ -315,7 +273,6 @@ const ConnectedTrackTile = ({ activityTimestamp={activity_timestamp} trackTileStyles={trackTileStyles} size={size} - listenCount={play_count} fieldVisibility={field_visibility} coSign={_co_sign} // Artist @@ -335,10 +292,6 @@ const ConnectedTrackTile = ({ onClickOverflow={onClickOverflow} renderOverflow={renderOverflowMenu} toggleRepost={toggleRepost} - makeGoToRepostsPage={makeGoToRepostsPage} - makeGoToFavoritesPage={makeGoToFavoritesPage} - makeGoToCommentsPage={makeGoToCommentsPage} - goToRoute={goToRoute} isOwner={isOwner} darkMode={darkMode} isMatrix={isMatrix()} @@ -347,7 +300,6 @@ const ConnectedTrackTile = ({ isStreamGated={isStreamGated} streamConditions={streamConditions} hasStreamAccess={hasStreamAccess} - showRankIcon={showRankIcon} variant={variant} isScheduledRelease={isScheduledRelease} releaseDate={releaseDate} @@ -390,12 +342,7 @@ function mapDispatchToProps(dispatch: Dispatch) { clickOverflow: (trackId: ID, overflowActions: OverflowAction[]) => dispatch( open({ source: OverflowSource.TRACKS, id: trackId, overflowActions }) - ), - setRepostTrackId: (trackId: ID) => - dispatch(setRepost(trackId, RepostType.TRACK)), - setFavoriteTrackId: (trackId: ID) => - dispatch(setFavorite(trackId, FavoriteType.TRACK)), - goToRoute: (route: string) => dispatch(pushRoute(route)) + ) } } diff --git a/packages/web/src/components/track/mobile/PlaylistTile.module.css b/packages/web/src/components/track/mobile/PlaylistTile.module.css index 7ed5b69fa94..36be4dbe49a 100644 --- a/packages/web/src/components/track/mobile/PlaylistTile.module.css +++ b/packages/web/src/components/track/mobile/PlaylistTile.module.css @@ -70,20 +70,6 @@ top: 10px; } -.statItem { - transform: scale(1); - transition: transform 0.07s ease-in-out; -} - -.statItem:active { - transform: scale(0.93); - color: var(--harmony-primary); -} - -.statItem:active svg path { - fill: var(--harmony-primary); -} - .readonly .statItem:active { color: unset; transform: scale(1); @@ -167,26 +153,6 @@ color: var(--harmony-n-400); } -.readonly .favoriteButtonWrapper:hover { - transform: scale3d(1, 1, 1); -} - -.favoriteButton { - height: 14px; - width: 14px; - margin-left: 4px; -} - -.readonly .repostButtonWrapper:hover { - transform: scale3d(1, 1, 1); -} - -.repostButton { - height: 16px; - width: 16px; - margin-left: 4px; -} - .hide { opacity: 0 !important; } diff --git a/packages/web/src/components/track/mobile/PlaylistTile.tsx b/packages/web/src/components/track/mobile/PlaylistTile.tsx index 1cf0481a1ef..cfbb20e9108 100644 --- a/packages/web/src/components/track/mobile/PlaylistTile.tsx +++ b/packages/web/src/components/track/mobile/PlaylistTile.tsx @@ -1,26 +1,19 @@ import { useEffect, MouseEvent, useCallback } from 'react' -import { useGetCurrentUserId, useGetPlaylistById } from '@audius/common/api' import { ID, UID, LineupTrack, AccessConditions, ModalSource, - isContentUSDCPurchaseGated, - GatedContentStatus + isContentUSDCPurchaseGated } from '@audius/common/models' import { gatedContentActions, - gatedContentSelectors, PurchaseableContentType, usePremiumContentPurchaseModal } from '@audius/common/store' -import { - Nullable, - formatCount, - formatLineupTileDuration -} from '@audius/common/utils' +import { Nullable, formatLineupTileDuration } from '@audius/common/utils' import { Box, Flex, @@ -29,27 +22,20 @@ import { } from '@audius/harmony' import cn from 'classnames' import { range } from 'lodash' -import { useDispatch, useSelector } from 'react-redux' +import { useDispatch } from 'react-redux' import { useModalState } from 'common/hooks/useModalState' -import FavoriteButton from 'components/alt-button/FavoriteButton' -import RepostButton from 'components/alt-button/RepostButton' import { CollectionDogEar } from 'components/collection' -import { CollectionAccessTypeLabel } from 'components/collection/CollectionAccessTypeLabel' -import { EntityRank } from 'components/lineup/EntityRank' +import { CollectionTileStats } from 'components/collection/CollectionTileStats' import { TextLink, UserLink } from 'components/link' -import { LockedStatusPill } from 'components/locked-status-pill' import Skeleton from 'components/skeleton/Skeleton' -import { PlaylistTileProps } from 'components/track/types' +import { PlaylistTileProps, TrackTileSize } from 'components/track/types' import { useRequiresAccountOnClick } from 'hooks/useRequiresAccount' -import { GatedConditionsPill } from '../GatedConditionsPill' - import BottomButtons from './BottomButtons' import styles from './PlaylistTile.module.css' import TrackTileArt from './TrackTileArt' const { setLockedContentId } = gatedContentActions -const { getGatedContentStatusMap } = gatedContentSelectors type TrackItemProps = { index: number @@ -183,56 +169,6 @@ type ExtraProps = { streamConditions: Nullable } -type CombinedProps = PlaylistTileProps & ExtraProps - -type LockedOrPlaysContentProps = Pick< - CombinedProps, - | 'hasStreamAccess' - | 'isOwner' - | 'isStreamGated' - | 'streamConditions' - | 'variant' - | 'id' -> & { - lockedContentType: 'premium' | 'gated' - gatedTrackStatus?: GatedContentStatus - onClickGatedUnlockPill: (e: MouseEvent) => void -} - -const renderLockedContent = ({ - id, - hasStreamAccess, - isOwner, - isStreamGated, - streamConditions, - gatedTrackStatus, - onClickGatedUnlockPill, - lockedContentType, - variant -}: LockedOrPlaysContentProps) => { - if (isStreamGated && streamConditions && !isOwner) { - if ( - !hasStreamAccess && - lockedContentType === 'premium' && - variant === 'readonly' - ) { - return ( - - ) - } - return ( - - ) - } -} - const PlaylistTile = (props: PlaylistTileProps & ExtraProps) => { const { id, @@ -240,8 +176,6 @@ const PlaylistTile = (props: PlaylistTileProps & ExtraProps) => { index, showSkeleton, numLoadingSkeletonRows, - isOwner, - showRankIcon, trackCount, variant, containerClassName, @@ -252,24 +186,12 @@ const PlaylistTile = (props: PlaylistTileProps & ExtraProps) => { isPlaying, isAlbum, ownerId, - isStreamGated, hasStreamAccess, streamConditions, - source + source, + isTrending } = props - const { data: currentUserId } = useGetCurrentUserId({}) - const { data: collection } = useGetPlaylistById({ - playlistId: id, - currentUserId - }) - - const { - is_private: isPrivate, - repost_count: repostCount, - save_count: saveCount - } = collection ?? {} - useEffect(() => { if (!showSkeleton) { hasLoaded(index) @@ -282,9 +204,6 @@ const PlaylistTile = (props: PlaylistTileProps & ExtraProps) => { [styles.show]: shouldShow, [styles.hide]: !shouldShow } - const gatedContentStatusMap = useSelector(getGatedContentStatusMap) - const gatedContentStatus = id ? gatedContentStatusMap[id] : undefined - const shouldShowStats = !isPrivate && !!(repostCount || saveCount) const [, setModalVisibility] = useModalState('LockedContent') const dispatch = useDispatch() @@ -385,81 +304,12 @@ const PlaylistTile = (props: PlaylistTileProps & ExtraProps) => {
- - - - - - {shouldShowStats ? ( - <> - - - {formatCount(props.saveCount)} - - - - {formatCount(props.repostCount)} - - - ) : null} - - - {renderLockedContent({ - id, - hasStreamAccess, - isOwner, - isStreamGated, - streamConditions, - gatedTrackStatus: gatedContentStatus, - lockedContentType: isPurchase ? 'premium' : 'gated', - variant, - onClickGatedUnlockPill - })} - - - + void toggleRepost: (trackId: ID) => void onShare: (trackId: ID) => void - makeGoToRepostsPage: (trackId: ID) => (e: MouseEvent) => void - makeGoToFavoritesPage: (trackId: ID) => (e: MouseEvent) => void - makeGoToCommentsPage: (trackId: ID) => (e: MouseEvent) => void isOwner: boolean darkMode: boolean isMatrix: boolean @@ -74,67 +53,6 @@ type ExtraProps = { type CombinedProps = TrackTileProps & ExtraProps -type LockedOrPlaysContentProps = Pick< - CombinedProps, - | 'trackId' - | 'hasStreamAccess' - | 'isOwner' - | 'isStreamGated' - | 'streamConditions' - | 'listenCount' - | 'variant' -> & { - lockedContentType: 'gated' | 'premium' - gatedTrackStatus?: GatedContentStatus - onClickGatedUnlockPill: (e: MouseEvent) => void -} - -const renderLockedContentOrPlayCount = ({ - trackId, - hasStreamAccess, - isOwner, - isStreamGated, - streamConditions, - gatedTrackStatus, - listenCount, - onClickGatedUnlockPill, - variant, - lockedContentType -}: LockedOrPlaysContentProps) => { - if (isStreamGated && streamConditions && !isOwner) { - if ( - !hasStreamAccess && - lockedContentType === 'premium' && - variant === 'readonly' && - trackId - ) { - return ( - - ) - } - return ( - - ) - } - - return ( - listenCount !== undefined && - listenCount > 0 && ( -
- {formatCount(listenCount)} - {messages.getPlays(listenCount)} -
- ) - ) -} - const formatCoSign = ({ hasReposted, hasFavorited @@ -171,10 +89,8 @@ const TrackTile = (props: CombinedProps) => { isUnlisted, isLoading, isStreamGated, - listenCount, streamConditions, hasStreamAccess, - showRankIcon, permalink, duration, genre, @@ -185,13 +101,12 @@ const TrackTile = (props: CombinedProps) => { hasPreview = false, title, source, - renderOverflow + renderOverflow, + isTrending, + fieldVisibility } = props - const hideShare: boolean = props.fieldVisibility - ? props.fieldVisibility.share === false - : false - + const hideShare = fieldVisibility?.share const dispatch = useDispatch() const [, setModalVisibility] = useModalState('LockedContent') const { onOpen: openPremiumContentPurchaseModal } = @@ -266,10 +181,6 @@ const TrackTile = (props: CombinedProps) => { openLockedContentModal ]) - const { isEnabled: isCommentsEnabled } = useFeatureFlag( - FeatureFlags.COMMENTS_ENABLED - ) - const isReadonly = variant === 'readonly' return ( @@ -361,103 +272,12 @@ const TrackTile = (props: CombinedProps) => { })} ) : null} - -
- - {id ? : null} - {!( - props.repostCount || - props.saveCount || - props.commentCount - ) ? null : ( - <> -
- - {formatCount(props.repostCount)} -
-
- - {formatCount(props.saveCount)} -
-
- - {formatCount(props.commentCount)} -
- - )} -
- - {!isLoading - ? renderLockedContentOrPlayCount({ - trackId: id, - hasStreamAccess, - isOwner, - isStreamGated, - streamConditions, - listenCount, - gatedTrackStatus, - variant, - lockedContentType: isPurchase ? 'premium' : 'gated', - onClickGatedUnlockPill: onClickPill - }) - : null} - -
+ {isReadonly ? null : ( void - goToRoute: (route: string) => void isTrending: boolean - showRankIcon: boolean variant?: 'readonly' } @@ -56,7 +54,6 @@ export type TrackTileProps = TileProps & { showArtworkIcon?: boolean showSkeleton?: boolean userSignedIn?: boolean - listenCount?: number saveCount: number commentCount: number commentsDisabled?: boolean @@ -123,9 +120,6 @@ export type DesktopTrackTileProps = { /** Prefix order number displayed on the left side of the tile */ order?: number - /** The number of plays for the track */ - listenCount?: number - /** If there is nothing underneath, it's standalone */ standalone?: boolean @@ -138,12 +132,6 @@ export type DesktopTrackTileProps = { /** If the track is playing */ isPlaying?: boolean - /** If the track is gated */ - isStreamGated?: boolean - - /** If the track is unlisted/hidden */ - isUnlisted?: boolean - /** If the track is a scheduled release */ isScheduledRelease?: boolean @@ -186,12 +174,6 @@ export type DesktopTrackTileProps = { /** The beneath the title is the username, for the track's creator */ userName: ReactNode - /** The beneath the username is the state, displays the favorite and repost counts */ - stats: ReactNode - - /** The fields which are visible on the track */ - fieldVisibility?: FieldVisibility - /** Displayed on the bottom right is the kebab icon for menu options */ rightActions?: ReactNode @@ -237,9 +219,6 @@ export type DesktopTrackTileProps = { /** Are we in a trending lineup? Allows tiles to specialize their rendering */ isTrending?: boolean - /** Whether to show an icon indicating rank in lineup */ - showRankIcon: boolean - /** The relative link of the track */ permalink: string @@ -275,9 +254,6 @@ export type DesktopPlaylistTileProps = { /** If the button actions should be clickable */ isDisabled?: boolean - /** If the track is unlisted */ - isUnlisted?: boolean - /** If track metadata is loading in */ isLoading?: boolean @@ -305,9 +281,6 @@ export type DesktopPlaylistTileProps = { /** The beneath the title is the username, for the track's creator */ userName: ReactNode - /** The beneath the username is the state, displays the favorite and repost counts */ - stats: ReactNode - /** Displayed on the bottom right is the kebab icon for menu options */ rightActions?: ReactNode @@ -368,9 +341,6 @@ export type DesktopPlaylistTileProps = { /** Are we in a trending lineup? Allows tiles to specialize their rendering */ isTrending?: boolean - /** Whether to show an icon indicating rank in lineup */ - showRankIcon: boolean - /** Relative link to playlist page */ href: string diff --git a/packages/web/src/pages/chat-page/components/ChatMessagePlaylist.tsx b/packages/web/src/pages/chat-page/components/ChatMessagePlaylist.tsx index 55cd6bc8518..0ff4bbaf92b 100644 --- a/packages/web/src/pages/chat-page/components/ChatMessagePlaylist.tsx +++ b/packages/web/src/pages/chat-page/components/ChatMessagePlaylist.tsx @@ -145,7 +145,6 @@ export const ChatMessagePlaylist = ({ hasLoaded={() => {}} isLoading={status === Status.LOADING || status === Status.IDLE} isTrending={false} - showRankIcon={false} numLoadingSkeletonRows={tracksWithUids.length} togglePlay={() => {}} playingTrackId={playingTrackId} diff --git a/packages/web/src/pages/chat-page/components/ChatMessageTrack.tsx b/packages/web/src/pages/chat-page/components/ChatMessageTrack.tsx index f2825855879..ccda1c9e24d 100644 --- a/packages/web/src/pages/chat-page/components/ChatMessageTrack.tsx +++ b/packages/web/src/pages/chat-page/components/ChatMessageTrack.tsx @@ -96,7 +96,6 @@ export const ChatMessageTrack = ({ isLoading={status === Status.LOADING || status === Status.IDLE} hasLoaded={() => {}} isTrending={false} - showRankIcon={false} isActive={isTrackPlaying} variant='readonly' source={ModalSource.DirectMessageTrackTile} 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 8ad9969f6f4..a7e7ce90d05 100644 --- a/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx +++ b/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx @@ -30,8 +30,6 @@ const messages = { disabledTabTooltip: 'Nothing available' } -const RANK_ICON_COUNT = 5 - // Creates a unique cache key for a time range & genre combination const getTimeGenreCacheKey = (timeRange: TimeRange, genre: string | null) => { const newGenre = genre || 'all' @@ -201,7 +199,6 @@ const TrendingPageContent = (props: TrendingPageContentProps) => { , text: messages.thisWeek, label: TimeRange.WEEK }, { icon: , text: messages.thisMonth, label: TimeRange.MONTH }, @@ -109,7 +107,6 @@ const TrendingPageMobileContent = ({ actions={trendingWeekActions} variant={LineupVariant.MAIN} isTrending - rankIconCount={trendingGenre === null ? RANK_ICON_COUNT : undefined} endOfLineup={ { variant: LineupVariant.PLAYLIST, numPlaylistSkeletonRows: 5, scrollParent: containerRef, - rankIconCount: 5, isTrending: true, isOrdered: true }) diff --git a/packages/web/src/pages/trending-underground/TrendingUndergroundPage.tsx b/packages/web/src/pages/trending-underground/TrendingUndergroundPage.tsx index 2607622168b..340b3f29c82 100644 --- a/packages/web/src/pages/trending-underground/TrendingUndergroundPage.tsx +++ b/packages/web/src/pages/trending-underground/TrendingUndergroundPage.tsx @@ -29,7 +29,6 @@ const useTrendingUndergroundLineup = (containerRef: HTMLElement) => { getLineupSelector: getLineup, variant: LineupVariant.MAIN, scrollParent: containerRef, - rankIconCount: 5, isTrending: true, isOrdered: true })