Skip to content

Commit

Permalink
[PAY-1248] Initial changes to get ready for upcoming PRs that include…
Browse files Browse the repository at this point in the history
… track and playlist tiles in DMs (#3391)

Co-authored-by: Saliou Diallo <saliou@audius.co>
Co-authored-by: Andrew Mendelsohn <andrew.mendelsohn@audius.co>
  • Loading branch information
3 people authored May 19, 2023
1 parent c2fabf6 commit 2ebaef5
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 18 deletions.
29 changes: 29 additions & 0 deletions packages/common/src/api/collection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Kind } from 'models'

import { createApi } from './createApi'

const collectionApi = createApi({
reducerPath: 'collectionApi',
endpoints: {
getPlaylistByPermalink: {
fetch: async ({ permalink, currentUserId }, { apiClient }) => {
return {
collection: (
await apiClient.getPlaylistByPermalink({
permalink,
currentUserId
})
)[0]
}
},
options: {
permalinkArgKey: 'permalink',
kind: Kind.COLLECTIONS,
schemaKey: 'collection'
}
}
}
})

export const { useGetPlaylistByPermalink } = collectionApi.hooks
export default collectionApi.reducer
49 changes: 36 additions & 13 deletions packages/common/src/api/createApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { isEqual } from 'lodash'
import { denormalize, normalize } from 'normalizr'
import { useDispatch, useSelector } from 'react-redux'

import { Kind } from 'models/Kind'
import { Status } from 'models/Status'
import { getCollection } from 'store/cache/collections/selectors'
import { getTrack } from 'store/cache/tracks/selectors'
import { CommonState } from 'store/reducers'
import { getErrorMessage } from 'utils/error'

Expand Down Expand Up @@ -128,26 +131,45 @@ const buildEndpointHooks = (
// Retrieve data from cache if lookup args provided
if (!endpointState[key]) {
if (
!endpoint.options?.idArgKey ||
!(endpoint.options?.idArgKey || endpoint.options?.permalinkArgKey) ||
!endpoint.options?.kind ||
!endpoint.options?.schemaKey
)
return null
const { kind, idArgKey, schemaKey } = endpoint.options
if (!fetchArgs[idArgKey]) return null
const idAsNumber =
typeof fetchArgs[idArgKey] === 'number'
const { kind, idArgKey, permalinkArgKey, schemaKey } = endpoint.options
if (idArgKey && !fetchArgs[idArgKey]) return null
if (permalinkArgKey && !fetchArgs[permalinkArgKey]) return null

const idAsNumber = idArgKey
? typeof fetchArgs[idArgKey] === 'number'
? parseInt(fetchArgs[idArgKey])
: fetchArgs[idArgKey]
const initialCachedEntity = cacheSelectors.getEntry(state, {
kind,
id: idAsNumber
})
: null
const idCachedEntity = idAsNumber
? cacheSelectors.getEntry(state, {
kind,
id: idAsNumber
})
: null

let permalinkCachedEntity = null
if (kind === Kind.TRACKS && permalinkArgKey) {
permalinkCachedEntity = getTrack(state, {
permalink: fetchArgs[permalinkArgKey]
})
}
if (kind === Kind.COLLECTIONS && permalinkArgKey) {
permalinkCachedEntity = getCollection(state, {
permalink: fetchArgs[permalinkArgKey]
})
}

const cachedEntity = idCachedEntity || permalinkCachedEntity

// cache hit
if (initialCachedEntity) {
if (cachedEntity) {
const { result, entities } = normalize(
{ [schemaKey]: initialCachedEntity },
{ [schemaKey]: cachedEntity },
apiResponseSchema
)
return {
Expand Down Expand Up @@ -198,8 +220,9 @@ const buildEndpointHooks = (
}

const fetchWrapped = async () => {
if (cachedData || !context) return
if (status === Status.LOADING) return
if (!context) return
if ([Status.LOADING, Status.ERROR, Status.SUCCESS].includes(status))
return
if (hookOptions?.disabled) return

try {
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './AudiusQueryContext'
export * from './relatedArtists'
export * from './track'
export * from './collection'
export * from './user'
export * from './hooks'
2 changes: 2 additions & 0 deletions packages/common/src/api/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { combineReducers } from 'redux'

import collectionApi from './collection'
import relatedArtistsApi from './relatedArtists'
import trackApi from './track'
import userApi from './user'

export default combineReducers({
relatedArtistsApi,
trackApi,
collectionApi,
userApi
})
12 changes: 11 additions & 1 deletion packages/common/src/api/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,26 @@ export const trackSchema = new schema.Entity(
{ idAttribute: 'track_id' }
)

export const collectionSchema = new schema.Entity(
Kind.COLLECTIONS,
{ user: userSchema, tracks: new schema.Array(trackSchema) },
{ idAttribute: 'playlist_id' }
)

export const apiResponseSchema = new schema.Object({
user: userSchema,
track: trackSchema,
collection: collectionSchema,
users: new schema.Array(userSchema),
tracks: new schema.Array(trackSchema)
tracks: new schema.Array(trackSchema),
collections: new schema.Array(collectionSchema)
})

export const apiResponseKeyToKind: Record<string, Kind> = {
user: Kind.USERS,
users: Kind.USERS,
collection: Kind.COLLECTIONS,
collections: Kind.COLLECTIONS,
track: Kind.TRACKS,
tracks: Kind.TRACKS
}
27 changes: 26 additions & 1 deletion packages/common/src/api/track.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Kind } from 'models'
import { parseTrackRouteFromPermalink } from 'utils/stringUtils'

import { createApi } from './createApi'

const trackApi = createApi({
Expand All @@ -8,10 +11,32 @@ const trackApi = createApi({
return {
track: await apiClient.getTrack({ id })
}
},
options: {
idArgKey: 'id',
kind: Kind.TRACKS,
schemaKey: 'track'
}
},
getTrackByPermalink: {
fetch: async ({ permalink, currentUserId }, { apiClient }) => {
const { handle, slug } = parseTrackRouteFromPermalink(permalink)
return {
track: await apiClient.getTrackByHandleAndSlug({
handle,
slug,
currentUserId
})
}
},
options: {
permalinkArgKey: 'permalink',
kind: Kind.TRACKS,
schemaKey: 'track'
}
}
}
})

export const { useGetTrackById } = trackApi.hooks
export const { useGetTrackById, useGetTrackByPermalink } = trackApi.hooks
export default trackApi.reducer
1 change: 1 addition & 0 deletions packages/common/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type SliceConfig = CreateSliceOptions<any, any, any>

type EndpointOptions = {
idArgKey?: string
permalinkArgKey?: string
schemaKey?: string
kind?: Kind
}
Expand Down
4 changes: 3 additions & 1 deletion packages/common/src/models/Analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,9 @@ export enum PlaybackSource {
HISTORY_PAGE = 'history page',
FAVORITES_PAGE = 'favorites page',
PASSIVE = 'passive',
EMBED_PLAYER = 'embed player'
EMBED_PLAYER = 'embed player',
DM_TRACK = 'dm_track',
DM_PLAYLIST_TRACK = 'dm_playlist_track'
}

type PlaybackPlay = {
Expand Down
4 changes: 3 additions & 1 deletion packages/common/src/store/queue/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export enum QueueSource {
SAVED_TRACKS = 'SAVED_TRACKS',
SEARCH_TRACKS = 'SEARCH_TRACKS',
TRACK_TRACKS = 'TRACK_TRACKS',
RECOMMENDED_TRACKS = 'RECOMMENDED_TRACKS'
RECOMMENDED_TRACKS = 'RECOMMENDED_TRACKS',
DM_TRACKS = 'DM_TRACKS',
DM_PLAYLIST_TRACKS = 'DM_PLAYLIST_TRACKS'
}

export type Queueable = {
Expand Down
25 changes: 24 additions & 1 deletion packages/common/src/utils/urlUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
const audiusUrlRegex =
// eslint-disable-next-line no-useless-escape
/^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?(staging\.)?(audius.co)(\/.+)?/gim
/^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?(staging\.)?(audius\.co)(\/.+)?/gim

export const isAudiusUrl = (url: string) => new RegExp(audiusUrlRegex).test(url)
export const getPathFromAudiusUrl = (url: string) =>
new RegExp(audiusUrlRegex).exec(url)?.[3] ?? null

const playlistUrlRegex =
// eslint-disable-next-line no-useless-escape
/^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?(staging\.)?(audius\.co)(\/[\S]+\/playlist\/[\S]+)$/gim

export const isPlaylistUrl = (url: string) =>
new RegExp(playlistUrlRegex).test(url)
export const getPathFromPlaylistUrl = (url: string) => {
const results = new RegExp(trackUrlRegex).exec(url)
if (!results) return null
return results[3]
}

const trackUrlRegex =
// eslint-disable-next-line no-useless-escape
/^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?(staging\.)?(audius\.co)(\/[\S]+\/[\S]+)$/gim

export const isTrackUrl = (url: string) => new RegExp(trackUrlRegex).test(url)
export const getPathFromTrackUrl = (url: string) => {
const results = new RegExp(trackUrlRegex).exec(url)
if (!results) return null
return results[3]
}

0 comments on commit 2ebaef5

Please sign in to comment.