Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
420 changes: 9 additions & 411 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions packages/common/src/api/tan-query/comments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export * from './useMuteUser'
export * from './useGetTrackCommentNotificationSetting'
export * from './useUpdateTrackCommentNotificationSetting'
export * from './useUpdateCommentNotificationSetting'
export * from './useFanClubFeed'
export * from './usePostTextUpdate'
115 changes: 115 additions & 0 deletions packages/common/src/api/tan-query/comments/useFanClubFeed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { useEffect } from 'react'

import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query'
import { useDispatch } from 'react-redux'

import { commentFromSDK } from '~/adapters'
import { useQueryContext } from '~/api/tan-query/utils'
import { Feature, ID } from '~/models'
import { toast } from '~/store/ui/toast/slice'

import { QUERY_KEYS } from '../queryKeys'
import { QueryKey } from '../types'
import { useCurrentUserId } from '../users/account/useCurrentUserId'
import { primeCommentData } from '../utils/primeCommentData'
import { primeRelatedData } from '../utils/primeRelatedData'

export type FanClubFeedItem =
| { itemType: 'text_post'; commentId: ID }
| { itemType: 'track'; trackId: ID }

const FAN_CLUB_FEED_PAGE_SIZE = 20

export const getFanClubFeedQueryKey = ({
mint,
sortMethod
}: {
mint: string
sortMethod?: string
}) => {
return [QUERY_KEYS.fanClubFeed, mint, { sortMethod }] as unknown as QueryKey<
FanClubFeedItem[]
>
}

type UseFanClubFeedArgs = {
mint: string
sortMethod?: 'top' | 'newest' | 'timestamp'
pageSize?: number
enabled?: boolean
}

export const useFanClubFeed = ({
mint,
sortMethod = 'newest',
pageSize = FAN_CLUB_FEED_PAGE_SIZE,
enabled = true
}: UseFanClubFeedArgs) => {
const { audiusSdk, reportToSentry } = useQueryContext()
const queryClient = useQueryClient()
const dispatch = useDispatch()
const { data: currentUserId } = useCurrentUserId()

const queryRes = useInfiniteQuery({
initialPageParam: 0,
getNextPageParam: (lastPage: FanClubFeedItem[], pages) => {
if (lastPage?.length < pageSize) return undefined
return (pages.length ?? 0) * pageSize
},
queryKey: getFanClubFeedQueryKey({ mint, sortMethod }),
queryFn: async ({ pageParam }): Promise<FanClubFeedItem[]> => {
const sdk = await audiusSdk()
const response = await sdk.comments.getFanClubFeed({
mint,
userId: currentUserId?.toString(),
offset: pageParam,
limit: pageSize,
sortMethod
})

// Prime related data (users, tracks) in cache
primeRelatedData({ related: response.related, queryClient })

// Prime individual comment data and build feed items
const feedItems: FanClubFeedItem[] = []

for (const item of response.data) {
if (item.item_type === 'text_post') {
const comment = commentFromSDK(item.comment)
if (comment) {
primeCommentData({ comments: [comment], queryClient })
feedItems.push({ itemType: 'text_post', commentId: comment.id })
}
} else if (item.item_type === 'track') {
const trackId = item.track?.id
if (trackId) {
feedItems.push({ itemType: 'track', trackId: Number(trackId) })
}
}
}

return feedItems
},
select: (data) => data.pages.flat(),
enabled: enabled && !!mint
})

const { error } = queryRes

useEffect(() => {
if (error) {
reportToSentry({
error,
name: 'Comments',
feature: Feature.Comments
})
dispatch(
toast({
content: 'There was an error loading the feed. Please try again.'
})
)
}
}, [error, dispatch, reportToSentry])

return queryRes
}
108 changes: 108 additions & 0 deletions packages/common/src/api/tan-query/comments/usePostTextUpdate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Id } from '@audius/sdk'
import { useMutation, useQueryClient } from '@tanstack/react-query'

import { useQueryContext } from '~/api/tan-query/utils'
import { Comment, Feature, ID } from '~/models'
import { toast } from '~/store/ui/toast/slice'

import { getFanClubFeedQueryKey } from './useFanClubFeed'
import { getCommentQueryKey } from './utils'

export type PostTextUpdateArgs = {
userId: ID
entityId: ID // artist user_id (coin owner)
body: string
mint: string
}

export const usePostTextUpdate = () => {
const { audiusSdk, reportToSentry } = useQueryContext()
const queryClient = useQueryClient()

return useMutation({
mutationFn: async (args: PostTextUpdateArgs & { newId?: ID }) => {
const sdk = await audiusSdk()
return await sdk.comments.createComment({
userId: Id.parse(args.userId)!,
metadata: {
commentId: args.newId,
entityId: args.entityId,
entityType: 'FanClub',
body: args.body,
mentions: []
}
})
},
onMutate: async (args: PostTextUpdateArgs & { newId?: ID }) => {
const { userId, body, entityId, mint } = args
const sdk = await audiusSdk()
const newId = await sdk.comments.generateCommentId()
args.newId = newId

const newComment: Comment = {
id: newId,
entityId,
entityType: 'FanClub',
userId,
message: body,
mentions: [],
isEdited: false,
trackTimestampS: undefined,
reactCount: 0,
replyCount: 0,
replies: undefined,
createdAt: new Date().toISOString(),
updatedAt: undefined
}

// Prime the individual comment cache
queryClient.setQueryData(getCommentQueryKey(newId), newComment)

// Optimistically prepend to the fan club feed
const feedQueryKey = getFanClubFeedQueryKey({
mint,
sortMethod: 'newest'
})
queryClient.setQueryData(feedQueryKey, (prevData: any) => {
if (!prevData) return prevData
const newState = structuredClone(prevData)
if (newState.pages?.[0]) {
newState.pages[0].unshift({
itemType: 'text_post' as const,
commentId: newId
})
}
return newState
})

return { newId }
},
onSuccess: (_data, args) => {
// Invalidate the fan club feed to get fresh data from server
queryClient.invalidateQueries({
queryKey: getFanClubFeedQueryKey({
mint: args.mint,
sortMethod: 'newest'
})
})
},
onError: (error: Error, args) => {
reportToSentry({
error,
additionalInfo: args,
name: 'Comments',
feature: Feature.Comments
})
toast({
content: 'There was an error posting your update. Please try again.'
})
// Invalidate to reset to server state
queryClient.invalidateQueries({
queryKey: getFanClubFeedQueryKey({
mint: args.mint,
sortMethod: 'newest'
})
})
}
})
}
3 changes: 2 additions & 1 deletion packages/common/src/api/tan-query/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,6 @@ export const QUERY_KEYS = {
exclusiveTracksCount: 'exclusiveTracksCount',
coinRedeemAmount: 'coinRedeemAmount',
coinRedeemCodeAmount: 'coinRedeemCodeAmount',
uploadStatus: 'uploadStatus'
uploadStatus: 'uploadStatus',
fanClubFeed: 'fanClubFeed'
} as const
Loading
Loading