Skip to content

Commit 02b2aa9

Browse files
authored
Add contest page (#14122)
1 parent b3a7152 commit 02b2aa9

File tree

30 files changed

+1260
-40
lines changed

30 files changed

+1260
-40
lines changed

packages/common/src/api/tan-query/events/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Queries
22
export * from './useAllEvents'
3+
export * from './useAllRemixContests'
34
export * from './useEvent'
45
export * from './useEvents'
56
export * from './useEventsByEntityId'
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { GetRemixContestsStatusEnum, Event as SDKEvent } from '@audius/sdk'
2+
import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query'
3+
4+
import { eventMetadataFromSDK } from '~/adapters/event'
5+
import { useQueryContext } from '~/api/tan-query/utils'
6+
import { ID } from '~/models'
7+
import { removeNullable } from '~/utils'
8+
9+
import { QUERY_KEYS } from '../queryKeys'
10+
import { QueryKey, QueryOptions } from '../types'
11+
12+
import { getEventQueryKey } from './utils'
13+
14+
const DEFAULT_PAGE_SIZE = 25
15+
16+
export type RemixContestStatus = GetRemixContestsStatusEnum
17+
18+
type UseAllRemixContestsArgs = {
19+
pageSize?: number
20+
/**
21+
* Filter by contest status. Defaults to `'all'` (the backend's default),
22+
* which returns active contests first (ordered by soonest-ending end_date)
23+
* followed by ended contests (most-recently-ended first).
24+
*/
25+
status?: RemixContestStatus
26+
}
27+
28+
export const getAllRemixContestsQueryKey = ({
29+
pageSize = DEFAULT_PAGE_SIZE,
30+
status = GetRemixContestsStatusEnum.All
31+
}: UseAllRemixContestsArgs = {}) =>
32+
[QUERY_KEYS.remixContestsList, { pageSize, status }] as unknown as QueryKey<
33+
ID[]
34+
>
35+
36+
/**
37+
* Hook to fetch all remix contest events with infinite query support.
38+
* Calls the dedicated discovery endpoint `GET /v1/events/remix-contests`
39+
* (SDK: `events.getRemixContests`), which returns events ordered with
40+
* currently-active contests first (by soonest-ending end_date) followed by
41+
* ended contests.
42+
*
43+
* Each page is mapped to the remix contest's parent track ID
44+
* (`event.entityId`) so consumers like `ContestCard` can receive a
45+
* `trackId` prop and resolve the event internally via `useRemixContest`.
46+
*/
47+
export const useAllRemixContests = (
48+
{
49+
pageSize = DEFAULT_PAGE_SIZE,
50+
status = GetRemixContestsStatusEnum.All
51+
}: UseAllRemixContestsArgs = {},
52+
options?: QueryOptions
53+
) => {
54+
const { audiusSdk } = useQueryContext()
55+
const queryClient = useQueryClient()
56+
57+
return useInfiniteQuery({
58+
queryKey: getAllRemixContestsQueryKey({ pageSize, status }),
59+
initialPageParam: 0,
60+
getNextPageParam: (lastPage: ID[], allPages) => {
61+
if (lastPage.length < pageSize) return undefined
62+
return allPages.length * pageSize
63+
},
64+
queryFn: async ({ pageParam }) => {
65+
const sdk = await audiusSdk()
66+
const { data } = await sdk.events.getRemixContests({
67+
limit: pageSize,
68+
offset: pageParam,
69+
status
70+
})
71+
72+
if (!data) return []
73+
74+
return data
75+
.map((sdkEvent: SDKEvent) => {
76+
const event = eventMetadataFromSDK(sdkEvent)
77+
if (!event) return null
78+
// Prime the per-event cache so useEvent / useRemixContest hits
79+
// immediately downstream.
80+
queryClient.setQueryData(getEventQueryKey(event.eventId), event)
81+
// Return the contest's parent track ID (event.entityId). The card
82+
// takes a trackId and resolves the event via useRemixContest.
83+
return event.entityId ?? null
84+
})
85+
.filter(removeNullable)
86+
},
87+
select: (data) => data.pages.flat(),
88+
...options
89+
})
90+
}

packages/common/src/api/tan-query/queryKeys.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export const QUERY_KEYS = {
8989
userCoinBalance: 'userCoinBalance',
9090
events: 'events',
9191
eventsByEntityId: 'eventsByEntityId',
92+
remixContestsList: 'remixContestsList',
9293
walletOwner: 'walletOwner',
9394
tokenPrice: 'tokenPrice',
9495
usdcBalance: 'usdcBalance',

packages/common/src/messages/explore.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const exploreMessages = {
66
featuredPlaylists: 'Community Playlists',
77
fanClubs: 'Fan Clubs',
88
featuredRemixContests: 'Featured Remix Contests',
9+
contests: 'Contests',
910
forYou: 'For You',
1011
recentlyListedForSale: 'Recently Listed for Sale',
1112
bestSelling: 'Best Selling',

packages/common/src/services/remote-config/feature-flags.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ export enum FeatureFlags {
1515
REACT_QUERY_SYNC = 'react_query_sync',
1616
COLLAPSED_EXPLORE_HEADER = 'collapsed_explore_header',
1717
LAUNCHPAD_VERIFICATION = 'launchpad_verification',
18-
FAN_CLUB_TEXT_POST_POSTING = 'fan_club_text_post_posting'
18+
FAN_CLUB_TEXT_POST_POSTING = 'fan_club_text_post_posting',
19+
CONTESTS = 'contests'
1920
}
2021

2122
type FlagDefaults = Record<FeatureFlags, boolean>
@@ -25,7 +26,8 @@ export const environmentFlagDefaults: Record<
2526
Partial<FlagDefaults>
2627
> = {
2728
development: {
28-
[FeatureFlags.FAN_CLUB_TEXT_POST_POSTING]: true
29+
[FeatureFlags.FAN_CLUB_TEXT_POST_POSTING]: true,
30+
[FeatureFlags.CONTESTS]: true
2931
},
3032
production: {}
3133
}
@@ -47,5 +49,6 @@ export const flagDefaults: FlagDefaults = {
4749
[FeatureFlags.REACT_QUERY_SYNC]: false,
4850
[FeatureFlags.COLLAPSED_EXPLORE_HEADER]: false,
4951
[FeatureFlags.LAUNCHPAD_VERIFICATION]: true,
50-
[FeatureFlags.FAN_CLUB_TEXT_POST_POSTING]: false
52+
[FeatureFlags.FAN_CLUB_TEXT_POST_POSTING]: false,
53+
[FeatureFlags.CONTESTS]: false
5154
}

packages/common/src/utils/route.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const TRENDING_PLAYLISTS_PAGE_LEGACY = '/trending/playlists'
3131
export const EXPLORE_PAGE = '/explore'
3232
export const TRENDING_PLAYLISTS_PAGE = '/explore/playlists'
3333
export const TRENDING_UNDERGROUND_PAGE = '/explore/underground'
34+
export const CONTESTS_PAGE = '/contests'
3435

3536
// DEPRECATED - use /library instead.
3637
export const SAVED_PAGE = '/favorites'
@@ -294,6 +295,7 @@ export const orderedRoutes = [
294295
TRENDING_GENRES,
295296
TRENDING_PAGE,
296297
EXPLORE_PAGE,
298+
CONTESTS_PAGE,
297299
EMPTY_PAGE,
298300
SEARCH_PAGE,
299301
UPLOAD_ALBUM_PAGE,
@@ -347,6 +349,7 @@ export const staticRoutes = new Set([
347349
FEED_PAGE,
348350
TRENDING_PAGE,
349351
EXPLORE_PAGE,
352+
CONTESTS_PAGE,
350353
TRENDING_PLAYLISTS_PAGE,
351354
TRENDING_PLAYLISTS_PAGE_LEGACY,
352355
TRENDING_UNDERGROUND_PAGE,

packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/routes/meteora/swap_coin_quote.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CpAmm } from '@meteora-ag/cp-amm-sdk'
1+
import { CpAmm, SwapMode as DammSwapMode } from '@meteora-ag/cp-amm-sdk'
22
import {
33
DynamicBondingCurveClient,
44
SwapMode
@@ -97,13 +97,17 @@ const getDammPoolQuote = async (
9797
const inputTokenMint =
9898
swapDirection === 'audioToCoin' ? audioMintPubkey : coinMintPubkey
9999

100-
const quote = await cpAmm.getQuote({
101-
inAmount: inputAmountBN,
100+
const currentSlot = await connection.getSlot()
101+
const currentPoint = poolState.activationType
102+
? new BN(new Date().getTime())
103+
: new BN(currentSlot)
104+
105+
const quote = cpAmm.getQuote2({
106+
amountIn: inputAmountBN,
102107
inputTokenMint,
103108
slippage: 2,
104109
poolState,
105-
currentTime: new Date().getTime(),
106-
currentSlot: await connection.getSlot(),
110+
currentPoint,
107111
inputTokenInfo: {
108112
mint: tokenAMintInfo,
109113
currentEpoch
@@ -113,10 +117,12 @@ const getDammPoolQuote = async (
113117
currentEpoch
114118
},
115119
tokenADecimal: tokenAMintInfo.decimals,
116-
tokenBDecimal: tokenBMintInfo.decimals
120+
tokenBDecimal: tokenBMintInfo.decimals,
121+
swapMode: DammSwapMode.PartialFill,
122+
hasReferral: false
117123
})
118124

119-
return quote.swapOutAmount.toString()
125+
return quote.outputAmount.toString()
120126
}
121127
/**
122128
* Gets a quote for swapping AUDIO to/from an artist coin using Meteora's DBC

0 commit comments

Comments
 (0)