diff --git a/packages/common/src/utils/route.ts b/packages/common/src/utils/route.ts index 1e282cbcf78..0cec375b858 100644 --- a/packages/common/src/utils/route.ts +++ b/packages/common/src/utils/route.ts @@ -2,6 +2,7 @@ import qs from 'query-string' import { matchPath, generatePath } from 'react-router' import { SearchCategory, SearchFilters } from '~/api/search' +import { ID } from '~/models' import { encodeUrlName } from './formatUtil' import { convertGenreLabelToValue, Genre } from './genres' @@ -347,6 +348,27 @@ export const profilePage = (handle: string) => { return `/${encodeUrlName(handle)}` } +export const collectionPage = ( + handle?: string | null, + playlistName?: string | null, + playlistId?: ID | null, + permalink?: string | null, + isAlbum?: boolean +) => { + // Prioritize permalink if available. If not, default to legacy routing + if (permalink) { + return permalink + } else if (playlistName && playlistId && handle) { + const collectionType = isAlbum ? 'album' : 'playlist' + return `/${encodeUrlName(handle)}/${collectionType}/${encodeUrlName( + playlistName + )}-${playlistId}` + } else { + console.error('Missing required arguments to get PlaylistPage route.') + return '' + } +} + /** * Generate a short base36 hash for a given string. * Used to generate short hashes for for queries and urls. diff --git a/packages/web/src/common/store/cache/collections/createPlaylistSaga.ts b/packages/web/src/common/store/cache/collections/createPlaylistSaga.ts index 1e6bd104bce..2a50e067367 100644 --- a/packages/web/src/common/store/cache/collections/createPlaylistSaga.ts +++ b/packages/web/src/common/store/cache/collections/createPlaylistSaga.ts @@ -25,13 +25,12 @@ import { EditCollectionValues, RequestConfirmationError } from '@audius/common/store' -import { makeKindId, Nullable } from '@audius/common/utils' +import { makeKindId, Nullable, route } from '@audius/common/utils' import { call, put, select, takeLatest } from 'typed-redux-saga' import { make } from 'common/store/analytics/actions' import { addPlaylistsNotInLibrary } from 'common/store/playlist-library/sagas' import { ensureLoggedIn } from 'common/utils/ensureLoggedIn' -import { collectionPage } from 'utils/route' import { waitForWrite } from 'utils/sagaHelpers' import { getUnclaimedPlaylistId } from './utils/getUnclaimedPlaylistId' @@ -42,6 +41,7 @@ const { requestConfirmation } = confirmerActions const { getAccountUser } = accountSelectors const { getTrack } = cacheTracksSelectors const { getCollection } = cacheCollectionsSelectors +const { collectionPage } = route export function* createPlaylistSaga() { yield* takeLatest( diff --git a/packages/web/src/common/store/social/collections/sagas.ts b/packages/web/src/common/store/social/collections/sagas.ts index 47de6d97f23..d4d18b8864b 100644 --- a/packages/web/src/common/store/social/collections/sagas.ts +++ b/packages/web/src/common/store/social/collections/sagas.ts @@ -22,7 +22,12 @@ import { confirmerActions, confirmTransaction } from '@audius/common/store' -import { formatShareText, makeUid, makeKindId } from '@audius/common/utils' +import { + formatShareText, + makeUid, + makeKindId, + route +} from '@audius/common/utils' import { call, select, takeEvery, put } from 'typed-redux-saga' import { make } from 'common/store/analytics/actions' @@ -32,7 +37,7 @@ import { addPlaylistsNotInLibrary, removePlaylistFromLibrary } from 'common/store/playlist-library/sagas' -import { audioNftPlaylistPage, collectionPage } from 'utils/route' +import { audioNftPlaylistPage } from 'utils/route' import { waitForWrite } from 'utils/sagaHelpers' import watchCollectionErrors from './errorSagas' @@ -43,6 +48,7 @@ const { getUser } = cacheUsersSelectors const { getCollections, getCollection } = cacheCollectionsSelectors const { addLocalCollection, removeLocalCollection } = savedPageActions const { getPlaylistLibrary, getUserId } = accountSelectors +const { collectionPage } = route /* REPOST COLLECTION */ diff --git a/packages/web/src/components/add-to-collection/desktop/AddToCollectionModal.tsx b/packages/web/src/components/add-to-collection/desktop/AddToCollectionModal.tsx index dafc2563969..a0ebc24210a 100644 --- a/packages/web/src/components/add-to-collection/desktop/AddToCollectionModal.tsx +++ b/packages/web/src/components/add-to-collection/desktop/AddToCollectionModal.tsx @@ -13,6 +13,7 @@ import { duplicateAddConfirmationModalUIActions, toastActions } from '@audius/common/store' +import { route } from '@audius/common/utils' import { Modal, Scrollbar, IconMultiselectAdd } from '@audius/harmony' import cn from 'classnames' import { capitalize } from 'lodash' @@ -24,7 +25,6 @@ import SearchBar from 'components/search-bar/SearchBar' import { Tooltip } from 'components/tooltip' import { useCollectionCoverArt } from 'hooks/useCollectionCoverArt' import { useFlag } from 'hooks/useRemoteConfig' -import { collectionPage } from 'utils/route' import styles from './AddToCollectionModal.module.css' const { getCollectionType, getTrackId, getTrackTitle, getTrackIsUnlisted } = @@ -35,6 +35,7 @@ const { getAccountWithNameSortedPlaylistsAndAlbums } = accountSelectors const { requestOpen: openDuplicateAddConfirmation } = duplicateAddConfirmationModalUIActions const { toast } = toastActions +const { collectionPage } = route const getMessages = (collectionType: 'album' | 'playlist') => ({ title: `Add to ${capitalize(collectionType)}`, diff --git a/packages/web/src/components/card-legacy/desktop/CollectionArtCard.tsx b/packages/web/src/components/card-legacy/desktop/CollectionArtCard.tsx index 1356d7e285e..1725fffe624 100644 --- a/packages/web/src/components/card-legacy/desktop/CollectionArtCard.tsx +++ b/packages/web/src/components/card-legacy/desktop/CollectionArtCard.tsx @@ -32,12 +32,11 @@ import { UserListEntityType } from 'store/application/ui/userListModal/types' import { AppState } from 'store/types' -import { collectionPage } from 'utils/route' import { withNullGuard } from 'utils/withNullGuard' import styles from './CollectionArtCard.module.css' -const { profilePage } = route +const { profilePage, collectionPage } = route const { getUserFromCollection } = cacheUsersSelectors const { getCollection } = cacheCollectionsSelectors const getUserId = accountSelectors.getUserId diff --git a/packages/web/src/components/duplicate-add-confirmation-modal/DuplicateAddConfirmationModal.tsx b/packages/web/src/components/duplicate-add-confirmation-modal/DuplicateAddConfirmationModal.tsx index 928b2452a96..71c389ee299 100644 --- a/packages/web/src/components/duplicate-add-confirmation-modal/DuplicateAddConfirmationModal.tsx +++ b/packages/web/src/components/duplicate-add-confirmation-modal/DuplicateAddConfirmationModal.tsx @@ -6,7 +6,7 @@ import { cacheCollectionsSelectors, duplicateAddConfirmationModalUISelectors } from '@audius/common/store' -import { fillString } from '@audius/common/utils' +import { fillString, route } from '@audius/common/utils' import { Button, Modal, @@ -23,12 +23,12 @@ import { useModalState } from 'common/hooks/useModalState' import { useSelector } from 'common/hooks/useSelector' import { ToastContext } from 'components/toast/ToastContext' import ToastLinkContent from 'components/toast/mobile/ToastLinkContent' -import { collectionPage } from 'utils/route' const { addTrackToPlaylist } = cacheCollectionsActions const { getCollection } = cacheCollectionsSelectors const { getPlaylistId, getTrackId } = duplicateAddConfirmationModalUISelectors const { getAccountUser } = accountSelectors +const { collectionPage } = route const messages = { title: 'Already Added', diff --git a/packages/web/src/components/menu/CollectionMenu.tsx b/packages/web/src/components/menu/CollectionMenu.tsx index 13a0ba005b2..a0701835600 100644 --- a/packages/web/src/components/menu/CollectionMenu.tsx +++ b/packages/web/src/components/menu/CollectionMenu.tsx @@ -18,9 +18,8 @@ import { Dispatch } from 'redux' import * as embedModalActions from 'components/embed-modal/store/actions' import { AppState } from 'store/types' -import { collectionPage } from 'utils/route' const { getUser } = cacheUsersSelectors -const { profilePage } = route +const { profilePage, collectionPage } = route type PlaylistId = number diff --git a/packages/web/src/components/nav/desktop/PlaylistLibrary/PlaylistNavItem.tsx b/packages/web/src/components/nav/desktop/PlaylistLibrary/PlaylistNavItem.tsx index e65db1e92b7..7633725366c 100644 --- a/packages/web/src/components/nav/desktop/PlaylistLibrary/PlaylistNavItem.tsx +++ b/packages/web/src/components/nav/desktop/PlaylistLibrary/PlaylistNavItem.tsx @@ -4,15 +4,16 @@ import { playlistUpdatesActions, playlistUpdatesSelectors } from '@audius/common/store' +import { route } from '@audius/common/utils' import { useDispatch } from 'react-redux' import { useSelector } from 'utils/reducer' -import { collectionPage } from 'utils/route' import { CollectionNavItem } from './CollectionNavItem' const { selectPlaylistUpdateById } = playlistUpdatesSelectors const { updatedPlaylistViewed } = playlistUpdatesActions +const { collectionPage } = route type PlaylistNavItemProps = { playlistId: number diff --git a/packages/web/src/components/notification/Notification/utils.ts b/packages/web/src/components/notification/Notification/utils.ts index 3e10a962e87..c634c070940 100644 --- a/packages/web/src/components/notification/Notification/utils.ts +++ b/packages/web/src/components/notification/Notification/utils.ts @@ -1,7 +1,9 @@ import { Entity, EntityType } from '@audius/common/store' +import { route } from '@audius/common/utils' import { UserListEntityType } from 'store/application/ui/userListModal/types' -import { fullCollectionPage, fullTrackPage, collectionPage } from 'utils/route' +import { fullCollectionPage, fullTrackPage } from 'utils/route' +const { collectionPage } = route export const getEntityLink = (entity: EntityType, fullRoute = false) => { if (!entity.user) return '' diff --git a/packages/web/src/components/search-bar/ConnectedSearchBar.jsx b/packages/web/src/components/search-bar/ConnectedSearchBar.jsx index faa9d14aad0..4a5ba021303 100644 --- a/packages/web/src/components/search-bar/ConnectedSearchBar.jsx +++ b/packages/web/src/components/search-bar/ConnectedSearchBar.jsx @@ -25,9 +25,9 @@ import { getSearch } from 'common/store/search-bar/selectors' import SearchBar from 'components/search/SearchBar' import SearchBarV2 from 'components/search/SearchBarV2' import { getFeatureEnabled } from 'services/remote-config/featureFlagHelpers' -import { collectionPage, getPathname } from 'utils/route' +import { getPathname } from 'utils/route' -const { profilePage, SEARCH_PAGE } = route +const { profilePage, collectionPage, SEARCH_PAGE } = route const { addItem: addRecentSearch } = searchActions class ConnectedSearchBar extends Component { diff --git a/packages/web/src/components/track-overflow-modal/ConnectedMobileOverflowModal.tsx b/packages/web/src/components/track-overflow-modal/ConnectedMobileOverflowModal.tsx index 577978b8ef7..0cd880bbbda 100644 --- a/packages/web/src/components/track-overflow-modal/ConnectedMobileOverflowModal.tsx +++ b/packages/web/src/components/track-overflow-modal/ConnectedMobileOverflowModal.tsx @@ -34,11 +34,11 @@ import { Dispatch } from 'redux' import { useAuthenticatedCallback } from 'hooks/useAuthenticatedCallback' import { AppState } from 'store/types' -import { collectibleDetailsPage, collectionPage } from 'utils/route' +import { collectibleDetailsPage } from 'utils/route' import MobileOverflowModal from './components/MobileOverflowModal' -const { profilePage } = route +const { profilePage, collectionPage } = route const { makeGetCurrent } = queueSelectors const { setVisibility } = modalsActions const { getModalVisibility } = modalsSelectors diff --git a/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx b/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx index 6770f29f004..0a9dda80c80 100644 --- a/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx +++ b/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx @@ -30,6 +30,7 @@ import { usePremiumContentPurchaseModal, PurchaseableContentType } from '@audius/common/store' +import { route } from '@audius/common/utils' import { Text, IconKebabHorizontal } from '@audius/harmony' import cn from 'classnames' import { push as pushRoute } from 'connected-react-router' @@ -56,7 +57,7 @@ import { } from 'store/application/ui/userListModal/types' import { AppState } from 'store/types' import { isDescendantElementOf } from 'utils/domUtils' -import { fullCollectionPage, fullTrackPage, collectionPage } from 'utils/route' +import { fullCollectionPage, fullTrackPage } from 'utils/route' import { isDarkMode, isMatrix } from 'utils/theme/theme' import { getCollectionWithFallback, getUserWithFallback } from '../helpers' @@ -77,6 +78,7 @@ const { } = collectionsSocialActions const { getCollection, getTracksFromCollection } = cacheCollectionsSelectors const getUserHandle = accountSelectors.getUserHandle +const { collectionPage } = route type OwnProps = { uid: UID diff --git a/packages/web/src/components/track/mobile/ConnectedPlaylistTile.tsx b/packages/web/src/components/track/mobile/ConnectedPlaylistTile.tsx index d0212f4b1aa..f66093ed1b6 100644 --- a/packages/web/src/components/track/mobile/ConnectedPlaylistTile.tsx +++ b/packages/web/src/components/track/mobile/ConnectedPlaylistTile.tsx @@ -33,13 +33,12 @@ import { Dispatch } from 'redux' import { useRecord, make } from 'common/store/analytics/actions' import { PlaylistTileProps } from 'components/track/types' import { AppState } from 'store/types' -import { collectionPage } from 'utils/route' import { isMatrix, shouldShowDark } from 'utils/theme/theme' import { getCollectionWithFallback, getUserWithFallback } from '../helpers' import PlaylistTile from './PlaylistTile' -const { REPOSTING_USERS_ROUTE, FAVORITING_USERS_ROUTE } = route +const { REPOSTING_USERS_ROUTE, FAVORITING_USERS_ROUTE, collectionPage } = route const { getUid, getBuffering, getPlaying } = playerSelectors const { setFavorite } = favoritesUserListActions const { setRepost } = repostsUserListActions diff --git a/packages/web/src/pages/collection-page/CollectionPageProvider.tsx b/packages/web/src/pages/collection-page/CollectionPageProvider.tsx index 1183e121e9a..36e5834ea5b 100644 --- a/packages/web/src/pages/collection-page/CollectionPageProvider.tsx +++ b/packages/web/src/pages/collection-page/CollectionPageProvider.tsx @@ -70,7 +70,7 @@ import { } from 'store/application/ui/userListModal/types' import { getLocationPathname } from 'store/routing/selectors' import { AppState } from 'store/types' -import { collectionPage, getPathname } from 'utils/route' +import { getPathname } from 'utils/route' import { parseCollectionRoute } from 'utils/route/collectionRouteParser' import { getCollectionPageSEOFields } from 'utils/seo' @@ -79,6 +79,7 @@ import { CollectionPageProps as MobileCollectionPageProps } from './components/m const { profilePage, + collectionPage, NOT_FOUND_PAGE, REPOSTING_USERS_ROUTE, FAVORITING_USERS_ROUTE diff --git a/packages/web/src/pages/upload-page/components/ShareBanner.tsx b/packages/web/src/pages/upload-page/components/ShareBanner.tsx index 4eaf19da280..312c84c2c95 100644 --- a/packages/web/src/pages/upload-page/components/ShareBanner.tsx +++ b/packages/web/src/pages/upload-page/components/ShareBanner.tsx @@ -8,6 +8,7 @@ import { ShareContent, UploadType } from '@audius/common/store' +import { route } from '@audius/common/utils' import { Button, IconLink, @@ -26,7 +27,6 @@ import { ToastContext } from 'components/toast/ToastContext' import { copyLinkToClipboard } from 'utils/clipboardUtil' import { SHARE_TOAST_TIMEOUT_MILLIS } from 'utils/constants' import { useSelector } from 'utils/reducer' -import { collectionPage } from 'utils/route' import { openTwitterLink } from 'utils/tweet' import styles from './ShareBanner.module.css' @@ -35,6 +35,7 @@ const { shareUser } = usersSocialActions const { shareTrack } = tracksSocialActions const { getAccountUser } = accountSelectors +const { collectionPage } = route const uploadTypeMap = { [UploadType.INDIVIDUAL_TRACK]: 'new track', diff --git a/packages/web/src/pages/upload-page/pages/FinishPage.tsx b/packages/web/src/pages/upload-page/pages/FinishPage.tsx index b26e5133d84..52e7ee596e5 100644 --- a/packages/web/src/pages/upload-page/pages/FinishPage.tsx +++ b/packages/web/src/pages/upload-page/pages/FinishPage.tsx @@ -28,14 +28,13 @@ import { make } from 'common/store/analytics/actions' import DynamicImage from 'components/dynamic-image/DynamicImage' import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' import { Tile } from 'components/tile' -import { collectionPage } from 'utils/route' import { ShareBanner } from '../components/ShareBanner' import { CollectionFormState, TrackFormState } from '../types' import styles from './FinishPage.module.css' -const { profilePage } = route +const { profilePage, collectionPage } = route const { getAccountUser } = accountSelectors const { getCombinedUploadPercentage } = uploadSelectors diff --git a/packages/web/src/public-site/pages/landing-page/components/FeaturedContent.tsx b/packages/web/src/public-site/pages/landing-page/components/FeaturedContent.tsx index 4f6271ea4ee..717fee7b245 100644 --- a/packages/web/src/public-site/pages/landing-page/components/FeaturedContent.tsx +++ b/packages/web/src/public-site/pages/landing-page/components/FeaturedContent.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import { useAppContext } from '@audius/common/context' import { SquareSizes, UserCollectionMetadata } from '@audius/common/models' -import { Nullable, Maybe } from '@audius/common/utils' +import { Nullable, Maybe, route } from '@audius/common/utils' import { StorageNodeSelectorService } from '@audius/sdk' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web import { useSpring, animated } from 'react-spring' @@ -21,10 +21,11 @@ import useHasViewed from 'hooks/useHasViewed' import { handleClickRoute } from 'public-site/components/handleClickRoute' import { audiusBackendInstance } from 'services/audius-backend/audius-backend-instance' import { env } from 'services/env' -import { collectionPage } from 'utils/route' import styles from './FeaturedContent.module.css' +const { collectionPage } = route + const messages = { title: 'Featured Content', subTitle: 'Check out the playlists we are listening to right now' diff --git a/packages/web/src/utils/route.ts b/packages/web/src/utils/route.ts index 54d4d9aa7ed..11b73d08cdf 100644 --- a/packages/web/src/utils/route.ts +++ b/packages/web/src/utils/route.ts @@ -11,7 +11,8 @@ import { env } from 'services/env' import { encodeUrlName } from './urlUtils' -const { getHash, SIGN_UP_PAGE, SEARCH_PAGE, profilePage } = route +const { getHash, SIGN_UP_PAGE, SEARCH_PAGE, profilePage, collectionPage } = + route const USE_HASH_ROUTING = env.USE_HASH_ROUTING @@ -43,26 +44,6 @@ export const fullAlbumPage = (handle: string, title: string, id: ID) => { return `${BASE_URL}${albumPage(handle, title, id)}` } -export const collectionPage = ( - handle?: string | null, - playlistName?: string | null, - playlistId?: ID | null, - permalink?: string | null, - isAlbum?: boolean -) => { - // Prioritize permalink if available. If not, default to legacy routing - if (permalink) { - return permalink - } else if (playlistName && playlistId && handle) { - const collectionType = isAlbum ? 'album' : 'playlist' - return `/${encodeUrlName(handle)}/${collectionType}/${encodeUrlName( - playlistName - )}-${playlistId}` - } else { - console.error('Missing required arguments to get PlaylistPage route.') - return '' - } -} export const fullCollectionPage = ( handle: string, playlistName?: string | null,