Skip to content

Commit

Permalink
[PAY-2681] Artist dashboard album support (#8136)
Browse files Browse the repository at this point in the history
  • Loading branch information
dharit-tan authored Apr 22, 2024
1 parent 8feb22b commit 37258ec
Show file tree
Hide file tree
Showing 10 changed files with 754 additions and 9 deletions.
8 changes: 4 additions & 4 deletions packages/common/src/models/Track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,24 @@ export const isContentCollectibleGated = (
nft_collection:
| AccessConditionsEthNFTCollection
| AccessConditionsSolNFTCollection
} => 'nft_collection' in (gatedConditions ?? {})
} => !!gatedConditions && 'nft_collection' in (gatedConditions ?? {})

export const isContentFollowGated = (
gatedConditions?: Nullable<AccessConditions>
): gatedConditions is FollowGatedConditions =>
'follow_user_id' in (gatedConditions ?? {})
!!gatedConditions && 'follow_user_id' in (gatedConditions ?? {})

export const isContentTipGated = (
gatedConditions?: Nullable<AccessConditions>
): gatedConditions is TipGatedConditions =>
'tip_user_id' in (gatedConditions ?? {})
!!gatedConditions && 'tip_user_id' in (gatedConditions ?? {})

export const isContentUSDCPurchaseGated = (
gatedConditions?: Nullable<
AccessConditions | DeepOmit<USDCPurchaseConditions, 'splits'>
> // data coming from upload/edit forms will not have splits on the type
): gatedConditions is USDCPurchaseConditions =>
'usdc_purchase' in (gatedConditions ?? {})
!!gatedConditions && 'usdc_purchase' in (gatedConditions ?? {})

export type AccessSignature = {
data: string
Expand Down
8 changes: 8 additions & 0 deletions packages/common/src/store/account/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ export const getAccountWithAlbums = createSelector(
}
)

export const getAccountAlbums = createSelector(
[getAccountWithCollections],
(account) => {
if (!account) return undefined
return account.collections.filter((c) => c.is_album)
}
)

export const getAccountWithNameSortedPlaylistsAndAlbums = createSelector(
[getAccountWithCollections],
(account) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,11 @@ export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
)}
>
{StartIcon ? (
<StartIcon size='m' color='subdued' {...IconProps} />
<StartIcon
size={size === TextInputSize.SMALL ? 's' : 'm'}
color='subdued'
{...IconProps}
/>
) : null}
<Flex direction='column' gap='xs' justifyContent='center' w='100%'>
{shouldShowLabel ? (
Expand Down
14 changes: 10 additions & 4 deletions packages/web/src/pages/dashboard-page/DashboardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState, Suspense, ReactNode, useEffect, useCallback } from 'react'

import { Status, Track } from '@audius/common/models'
import { FeatureFlags } from '@audius/common/services'
import { themeSelectors } from '@audius/common/store'
import { formatCount } from '@audius/common/utils'
import cn from 'classnames'
Expand All @@ -12,15 +13,17 @@ import Header from 'components/header/desktop/Header'
import LoadingSpinner from 'components/loading-spinner/LoadingSpinner'
import Page from 'components/page/Page'
import { useGoToRoute } from 'hooks/useGoToRoute'
import { useFlag } from 'hooks/useRemoteConfig'
import lazyWithPreload from 'utils/lazyWithPreload'

import styles from './DashboardPage.module.css'
import { ArtistCard } from './components/ArtistCard'
import { ArtistContentSection } from './components/ArtistContentSection'
import {
TracksTableContainer,
DataSourceTrack,
tablePageSize
DataSourceTrack
} from './components/TracksTableContainer'
import { TABLE_PAGE_SIZE } from './components/constants'
import {
getDashboardListenData,
getDashboardStatus,
Expand Down Expand Up @@ -67,6 +70,9 @@ const StatTile = (props: { title: string; value: any }) => {
export const DashboardPage = () => {
const goToRoute = useGoToRoute()
const dispatch = useDispatch()
const { isEnabled: isPremiumAlbumsEnabled } = useFlag(
FeatureFlags.PREMIUM_ALBUMS_ENABLED
)
const [selectedTrack, setSelectedTrack] = useState(-1)
const { account, tracks, stats } = useSelector(makeGetDashboard())
const listenData = useSelector(getDashboardListenData)
Expand All @@ -76,7 +82,7 @@ export const DashboardPage = () => {
const header = <Header primary={messages.title} />

useEffect(() => {
dispatch(fetch({ offset: 0, limit: tablePageSize }))
dispatch(fetch({ offset: 0, limit: TABLE_PAGE_SIZE }))
TotalPlaysChart.preload()
return () => {
dispatch(reset({}))
Expand Down Expand Up @@ -194,7 +200,7 @@ export const DashboardPage = () => {
<div className={styles.sectionContainer}>
{renderChart()}
{renderStats()}
{renderTable()}
{isPremiumAlbumsEnabled ? <ArtistContentSection /> : renderTable()}
</div>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { useState, useCallback } from 'react'

import { Nullable } from '@audius/common/utils'
import {
SelectablePill,
IconSearch,
Paper,
Flex,
FilterButton,
TextInput,
TextInputSize
} from '@audius/harmony'

import { ArtistDashboardAlbumsTab } from './ArtistDashboardAlbumsTab'
import { ArtistDashboardTracksTab } from './ArtistDashboardTracksTab'
import {
useArtistDashboardAlbumFilters,
useArtistDashboardTrackFilters,
useFormattedAlbumData,
useFormattedTrackData
} from './hooks'
import { AlbumFilters, TrackFilters } from './types'

const messages = {
allReleases: 'All Releases',
tracks: 'Tracks',
albums: 'Albums',
search: (type: Pills) =>
`Search ${type === Pills.TRACKS ? 'Tracks' : 'Albums'}`
}

enum Pills {
TRACKS,
ALBUMS
}

export const ArtistContentSection = () => {
const [filterText, setFilterText] = useState('')
const [selectedPill, setSelectedPill] = useState(Pills.TRACKS)
const [selectedTrackFilter, setSelectedTrackFilter] =
useState<Nullable<TrackFilters>>(null)
const [selectedAlbumFilter, setSelectedAlbumFilter] =
useState<Nullable<AlbumFilters>>(null)
const isTracks = selectedPill === Pills.TRACKS
const tracks = useFormattedTrackData()
const albums = useFormattedAlbumData()

const {
filterButtonOptions: filterButtonTrackOptions,
hasOnlyOneSection: hasOnlyOneTrackSection
} = useArtistDashboardTrackFilters()
const {
filterButtonOptions: filterButtonAlbumOptions,
hasOnlyOneSection: hasOnlyOneAlbumSection
} = useArtistDashboardAlbumFilters()

const filterButtonOptions = isTracks
? filterButtonTrackOptions
: filterButtonAlbumOptions
const shouldShowFilterButton =
(isTracks && !hasOnlyOneTrackSection) ||
(!isTracks && !hasOnlyOneAlbumSection)
const shouldShowPills = tracks.length && albums.length

const onClickPill = useCallback(
(pill: Pills) => {
setSelectedPill(pill)
setFilterText('')

// Reset filter button state when switching content types
if (!isTracks && pill === Pills.TRACKS) {
setSelectedAlbumFilter(null)
} else if (isTracks && pill === Pills.ALBUMS) {
setSelectedTrackFilter(null)
}
},
[isTracks]
)

const handleSelectFilter = (value: string) => {
if (isTracks) {
setSelectedTrackFilter(value as TrackFilters)
} else {
setSelectedAlbumFilter(value as AlbumFilters)
}
}

const handleFilterChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const val = e.target.value
setFilterText(val)
}

if (!tracks.length && !albums.length) return null

return (
<Paper w='100%' direction='column' mt='xl'>
<Flex ph='2xl' pv='l' justifyContent='space-between'>
<Flex gap='2xl'>
{shouldShowPills ? (
<Flex gap='s'>
<SelectablePill
isSelected={selectedPill === Pills.TRACKS}
label={messages.tracks}
size='large'
onClick={() => onClickPill(Pills.TRACKS)}
/>
<SelectablePill
isSelected={selectedPill === Pills.ALBUMS}
label={messages.albums}
size='large'
onClick={() => onClickPill(Pills.ALBUMS)}
/>
</Flex>
) : null}
{
// Only show filter button if there are multiple sections for the selected content type
shouldShowFilterButton ? (
<FilterButton
onSelect={handleSelectFilter}
selection={isTracks ? selectedTrackFilter : selectedAlbumFilter}
label={messages.allReleases}
options={filterButtonOptions}
popupAnchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
popupTransformOrigin={{ vertical: 'top', horizontal: 'left' }}
/>
) : null
}
</Flex>
<Flex>
<TextInput
placeholder={messages.search(selectedPill)}
label={messages.search(selectedPill)}
value={filterText}
onChange={handleFilterChange}
size={TextInputSize.SMALL}
startIcon={IconSearch}
/>
</Flex>
</Flex>
{selectedPill === Pills.TRACKS ? (
<ArtistDashboardTracksTab
selectedFilter={selectedTrackFilter}
filterText={filterText}
/>
) : (
<ArtistDashboardAlbumsTab
selectedFilter={selectedAlbumFilter}
filterText={filterText}
/>
)}
</Paper>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useCallback } from 'react'

import { Nullable } from '@audius/common/utils'
import { Paper } from '@audius/harmony'
import { useSelector } from 'react-redux'

import { TracksTable, TracksTableColumn } from 'components/tracks-table'
import { useGoToRoute } from 'hooks/useGoToRoute'

import { makeGetDashboard } from '../store/selectors'

import { SHOW_MORE_LIMIT, TABLE_PAGE_SIZE } from './constants'
import { useFilteredAlbumData } from './hooks'
import { AlbumFilters } from './types'

const albumTableColumns: TracksTableColumn[] = [
'spacer',
'trackName',
'releaseDate',
'reposts',
'overflowMenu'
]

type ArtistDashboardAlbumsTabProps = {
selectedFilter: Nullable<AlbumFilters>
filterText: string
}

export const ArtistDashboardAlbumsTab = ({
selectedFilter,
filterText
}: ArtistDashboardAlbumsTabProps) => {
const goToRoute = useGoToRoute()
const { account } = useSelector(makeGetDashboard())
const filteredData = useFilteredAlbumData({
selectedFilter,
filterText
})

const onClickRow = useCallback(
(collection: any) => {
if (!account) return
goToRoute(collection.permalink)
},
[account, goToRoute]
)

if (!filteredData.length || !account) return null

return (
<Paper w='100%' direction='column' mt='xl'>
<TracksTable
data={filteredData}
disabledTrackEdit
columns={albumTableColumns}
onClickRow={onClickRow}
pageSize={TABLE_PAGE_SIZE}
userId={account.user_id}
showMoreLimit={SHOW_MORE_LIMIT}
totalRowCount={account.track_count}
/>
</Paper>
)
}
Loading

0 comments on commit 37258ec

Please sign in to comment.