diff --git a/packages/web/src/pages/collection-page/CollectionPageProvider.tsx b/packages/web/src/pages/collection-page/CollectionPageProvider.tsx index 36e5834ea5b..bfd4f792393 100644 --- a/packages/web/src/pages/collection-page/CollectionPageProvider.tsx +++ b/packages/web/src/pages/collection-page/CollectionPageProvider.tsx @@ -449,9 +449,8 @@ class CollectionPage extends Component< ) const filteredMetadata = this.formatMetadata(trackMetadatas).filter( (item) => - !item.is_delete && - (item.title.toLowerCase().indexOf(filterText.toLowerCase()) > -1 || - item.user.name.toLowerCase().indexOf(filterText.toLowerCase()) > -1) + item.title.toLowerCase().indexOf(filterText.toLowerCase()) > -1 || + item.user.name.toLowerCase().indexOf(filterText.toLowerCase()) > -1 ) const filteredIndex = playingIndex > -1 diff --git a/packages/web/src/pages/dashboard-page/components/TracksTableContainer.module.css b/packages/web/src/pages/dashboard-page/components/TracksTableContainer.module.css new file mode 100644 index 00000000000..d420893c90e --- /dev/null +++ b/packages/web/src/pages/dashboard-page/components/TracksTableContainer.module.css @@ -0,0 +1,60 @@ +.tableContainer { + border-radius: 6px; + background: var(--harmony-white); + box-shadow: var(--table-shadow) 0px var(--harmony-unit-4) + var(--harmony-unit-5) 0px; + overflow: hidden; +} + +.sectionContainer { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + margin: var(--harmony-unit-3) 0px; +} + +.header { + width: 100%; + padding: var(--harmony-unit-6); + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: var(--harmony-unit-2); +} + +.pills { + display: flex; + gap: var(--harmony-unit-2); +} + +.filterInput { + width: 160px; + height: var(--harmony-unit-6); + border-radius: var(--harmony-unit-1); + border-color: var(--harmony-n-100); + background: var(--harmony-n-25); +} + +.close { + cursor: pointer; + height: var(--harmony-unit-6); + width: var(--harmony-unit-6); +} + +.trackName { + max-width: 350px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +:global( + .ant-table-thead + > tr + > th.ant-table-column-has-actions.ant-table-column-has-sorters + ).col:global(.colName), +.col:global(.colName) { + padding-left: var(--harmony-unit-6) !important; +} diff --git a/packages/web/src/pages/dashboard-page/components/TracksTableContainer.tsx b/packages/web/src/pages/dashboard-page/components/TracksTableContainer.tsx new file mode 100644 index 00000000000..59eb9e239d2 --- /dev/null +++ b/packages/web/src/pages/dashboard-page/components/TracksTableContainer.tsx @@ -0,0 +1,280 @@ +import { useState, useCallback, useMemo } from 'react' + +import { + Status, + isContentUSDCPurchaseGated, + Track, + User +} from '@audius/common/models' +import { + SelectablePill, + IconClose, + IconSpecialAccess, + IconCollectible, + IconSearch, + IconVisibilityHidden, + IconVisibilityPublic, + IconCart +} from '@audius/harmony' +import { useDispatch, useSelector } from 'react-redux' + +import { Input } from 'components/input' +import { TracksTable, TracksTableColumn } from 'components/tracks-table' + +import { getDashboardTracksStatus } from '../store/selectors' +import { fetchTracks } from '../store/slice' + +import styles from './TracksTableContainer.module.css' + +// Pagination Constants +export const tablePageSize = 50 + +const messages = { + filterInputPlacehoder: 'Search Tracks', + all: 'All', + public: 'Public', + premium: 'Premium', + specialAcess: 'SpecialAccess', + gated: 'Gated', + hidden: 'Hidden', + tracks: 'Tracks' +} + +const tableColumns: TracksTableColumn[] = [ + 'spacer', + 'trackName', + 'releaseDate', + 'length', + 'plays', + 'reposts', + 'overflowMenu' +] + +export type DataSourceTrack = Track & { + key: string + name: string + date: string + time?: number + saves: number + reposts: number + plays: number +} + +type TracksTableProps = { + onClickRow: (record: any) => void + dataSource: DataSourceTrack[] + account: User +} + +enum Pills { + ALL, + PUBLIC, + PREMIUM, + SPECIAL_ACCESS, + COLLECTIBLE_GATED, + HIDDEN +} + +export const TracksTableContainer = ({ + onClickRow, + dataSource, + account +}: TracksTableProps) => { + const [filterText, setFilterText] = useState('') + const dispatch = useDispatch() + const tracksStatus = useSelector(getDashboardTracksStatus) + const [selectedPill, setSelectedPill] = useState(Pills.ALL) + + const handleFilterChange = (e: React.ChangeEvent) => { + const val = e.target.value + setFilterText(val) + } + + let filteredData: DataSourceTrack[] + const { + hasOnlyOneSection, + pub, + collectibleGated, + hidden, + premium, + specialAccess + } = useMemo(() => { + const pub = dataSource.filter( + (data) => + data.is_unlisted === false && + !isContentUSDCPurchaseGated(data.stream_conditions) + ) + const specialAccess = dataSource.filter( + (data) => + 'tip_user_id' in (data.stream_conditions || {}) || + 'follow_user_id' in (data.stream_conditions || {}) + ) + const hidden = dataSource.filter((data) => data.is_unlisted === true) + const premium = dataSource.filter( + (data) => 'usdc_purchase' in (data.stream_conditions || {}) + ) + const collectibleGated = dataSource.filter( + (data) => 'nft_collection' in (data.stream_conditions || {}) + ) + + const arrays = [pub, specialAccess, hidden, premium, collectibleGated] + const nonEmptyArrays = arrays.filter((arr) => arr.length > 0) + const hasOnlyOneSection = nonEmptyArrays.length === 1 + + return { + hasOnlyOneSection, + pub, + specialAccess, + hidden, + premium, + collectibleGated + } + }, [dataSource]) + + switch (selectedPill) { + case Pills.ALL: + // Keep all data + filteredData = dataSource + break + case Pills.PUBLIC: + filteredData = pub + break + case Pills.COLLECTIBLE_GATED: + filteredData = collectibleGated + break + case Pills.HIDDEN: + filteredData = hidden + break + case Pills.PREMIUM: + filteredData = premium + break + case Pills.SPECIAL_ACCESS: + filteredData = specialAccess + break + } + + if (filterText) { + filteredData = filteredData.filter((data) => + data.title.toLowerCase().includes(filterText.toLowerCase()) + ) + } + + const handleFetchPage = useCallback( + (page: number) => { + dispatch( + fetchTracks({ offset: page * tablePageSize, limit: tablePageSize }) + ) + }, + [dispatch] + ) + + return ( +
+
+
+ {!hasOnlyOneSection ? ( + setSelectedPill(Pills.ALL)} + /> + ) : null} + {pub.length > 0 ? ( + setSelectedPill(Pills.PUBLIC)} + /> + ) : null} + {premium.length > 0 ? ( + setSelectedPill(Pills.PREMIUM)} + /> + ) : null} + {specialAccess.length > 0 ? ( + setSelectedPill(Pills.SPECIAL_ACCESS)} + /> + ) : null} + {collectibleGated.length > 0 ? ( + setSelectedPill(Pills.COLLECTIBLE_GATED)} + /> + ) : null} + {hidden.length > 0 ? ( + setSelectedPill(Pills.HIDDEN)} + /> + ) : null} +
+
+ } + suffix={ + filterText ? ( + setFilterText('')} + /> + ) : null + } + size='default' + onChange={handleFilterChange} + value={filterText} + variant='bordered' + /> +
+
+ +
+ ) +}