Skip to content

Commit

Permalink
Merge pull request #167 from dappforce/deploy/leaderboard
Browse files Browse the repository at this point in the history
Add Post Reward
  • Loading branch information
teodorus-nathaniel authored Jan 12, 2024
2 parents 2436173 + af4f776 commit 3f3f2a6
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 81 deletions.
34 changes: 34 additions & 0 deletions src/components/posts/view-post/PostRewardStat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import clsx from 'clsx'
import { ComponentProps } from 'react'
import { TbCoins } from 'react-icons/tb'
import { FormatBalance } from 'src/components/common/balances'
import { useSelectPostReward } from 'src/rtk/features/activeStaking/hooks'

export type PostRewardStatProps = ComponentProps<'div'> & { postId: string }

export default function PostRewardStat({ postId, ...props }: PostRewardStatProps) {
const postEarn = useSelectPostReward(postId)
if (!postEarn?.isNotZero) return null

return (
<div
{...props}
className={clsx('d-flex align-items-center GapMini FontWeightMedium', props.className)}
style={{ alignSelf: 'end', ...props.style }}
>
<span className='d-flex align-items-center GapMini ColorMuted'>
<TbCoins className='FontNormal' />
<span>Post earned:</span>
</span>
<span className='FontWeightSemibold'>
<FormatBalance
currency='SUB'
decimals={10}
precision={2}
withMutedDecimals={false}
value={postEarn.amount}
/>
</span>
</div>
)
}
2 changes: 2 additions & 0 deletions src/components/posts/view-post/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import ViewTags from '../../utils/ViewTags'
import Embed from '../embed/Embed'
import ViewPostLink from '../ViewPostLink'
import { PostDropDownMenu } from './PostDropDownMenu'
import PostRewardStat from './PostRewardStat'
import TwitterPost from './TwitterPost'

type IsUnlistedPostProps = {
Expand Down Expand Up @@ -297,6 +298,7 @@ export const PostActionsPanel: FC<PostActionsPanelProps> = props => {
return (
<div className={`DfActionsPanel ${withBorder && 'DfActionBorder'} ${className ?? ''}`}>
<ReactionsAction />
<PostRewardStat postId={postDetails.id} />
{/* <ShareDropdown postDetails={postDetails} space={space} className='DfAction' /> */}
</div>
)
Expand Down
35 changes: 35 additions & 0 deletions src/components/utils/datahub/super-likes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
fetchAddressLikeCounts,
} from 'src/rtk/features/activeStaking/addressLikeCountSlice'
import { CanPostSuperLiked } from 'src/rtk/features/activeStaking/canPostSuperLikedSlice'
import { PostRewards } from 'src/rtk/features/activeStaking/postRewardSlice'
import { RewardHistory } from 'src/rtk/features/activeStaking/rewardHistorySlice'
import { fetchRewardReport, RewardReport } from 'src/rtk/features/activeStaking/rewardReportSlice'
import {
Expand Down Expand Up @@ -64,6 +65,40 @@ export async function getSuperLikeCounts(postIds: string[]): Promise<SuperLikeCo
return postIds.map(postId => resultMap.get(postId) ?? { postId, count: 0 })
}

const GET_POST_REWARDS = gql`
query GetPostRewards($postIds: [String!]!) {
activeStakingRewardsByPosts(args: { postPersistentIds: $postIds }) {
persistentPostId
amount
}
}
`
export async function getPostRewards(postIds: string[]): Promise<PostRewards[]> {
const res = await datahubQueryRequest<
{
activeStakingRewardsByPosts: {
persistentPostId: string
amount: string
}[]
},
{ postIds: string[] }
>({
document: GET_POST_REWARDS,
variables: { postIds },
})

const resultMap = new Map<string, PostRewards>()
res.activeStakingRewardsByPosts.forEach(item =>
resultMap.set(item.persistentPostId, {
postId: item.persistentPostId,
amount: item.amount,
isNotZero: BigInt(item.amount) > 0,
}),
)

return postIds.map(postId => resultMap.get(postId) ?? { postId, amount: '0', isNotZero: false })
}

const GET_ADDRESS_LIKE_COUNT_TO_POSTS = gql`
query GetAddressLikeCountToPosts($address: String!, $postIds: [String!]!) {
activeStakingSuperLikeCountsByStaker(args: { postPersistentIds: $postIds, address: $address }) {
Expand Down
3 changes: 2 additions & 1 deletion src/components/voting/SuperLike.module.sass
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
.SuperLike
background: #F8FAFC
color: #7779F3
padding: 0.2em $space_small
padding: $space_mini $space_small
height: auto
display: flex
align-items: center
border: none
Expand Down
2 changes: 2 additions & 0 deletions src/rtk/app/rootReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import myAccount from '../features/accounts/myAccountSlice'
import spaceEditors from '../features/accounts/spaceEditorsSlice'
import addressLikeCount from '../features/activeStaking/addressLikeCountSlice'
import canPostSuperLiked from '../features/activeStaking/canPostSuperLikedSlice'
import postReward from '../features/activeStaking/postRewardSlice'
import rewardHistory from '../features/activeStaking/rewardHistorySlice'
import rewardReport from '../features/activeStaking/rewardReportSlice'
import superLikeCounts from '../features/activeStaking/superLikeCountsSlice'
Expand Down Expand Up @@ -65,6 +66,7 @@ const rootReducer = combineReducers({
rewardReport,
rewardHistory,
canPostSuperLiked,
postReward,
})

export type RootState = ReturnType<typeof rootReducer>
Expand Down
51 changes: 51 additions & 0 deletions src/rtk/app/wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,54 @@ export function createSimpleFetchWrapper<Args, ReturnValue>({
},
)
}

export function createSimpleManyFetchWrapper<Args, ReturnValue>({
sliceName,
fetchData,
saveToCacheAction,
getCachedData,
filterNewArgs,
shouldFetchCondition,
}: {
sliceName: string
saveToCacheAction: (data: ReturnValue[]) => any
getCachedData: (state: RootState, id: string) => ReturnValue | undefined
fetchData: (args: Args, state: RootState) => Promise<ReturnValue[]>
filterNewArgs: (args: Args, isNewId: (id: string) => boolean) => Args
shouldFetchCondition: (filteredArgs: Args) => boolean
}) {
const currentlyFetchingMap = new Map<string, Promise<ReturnValue[]>>()
return createAsyncThunk<ReturnValue[], Args & { reload?: boolean }, ThunkApiConfig>(
`${sliceName}/fetchMany`,
async (allArgs, { getState, dispatch }): Promise<ReturnValue[]> => {
const { reload } = allArgs

let filteredArgs: Args = allArgs
let shouldFetchIds: string[] = []
if (!reload) {
filteredArgs = filterNewArgs(allArgs, id => {
const shouldFetch = !currentlyFetchingMap.get(id) && !getCachedData(getState(), id)
if (!shouldFetch) return false

shouldFetchIds.push(id)
return true
})
}

if (!shouldFetchCondition(filteredArgs)) return []

const promise = fetchData(filteredArgs, getState())
shouldFetchIds.forEach(id => {
currentlyFetchingMap.set(id, promise)
})
const res = await promise

await dispatch(saveToCacheAction(res))
shouldFetchIds.forEach(id => {
currentlyFetchingMap.delete(id)
})

return promise
},
)
}
46 changes: 13 additions & 33 deletions src/rtk/features/activeStaking/addressLikeCountSlice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'
import { getAddressLikeCountToPosts } from 'src/components/utils/datahub/super-likes'
import { RootState } from 'src/rtk/app/rootReducer'
import { createSimpleFetchWrapper } from 'src/rtk/app/wrappers'
import { createSimpleManyFetchWrapper } from 'src/rtk/app/wrappers'

export type AddressLikeCount = {
address: string
Expand All @@ -28,48 +28,28 @@ export const selectAllAddressLikeCounts = selectors.selectEntities
function getAllPostIdsFromStore(state: RootState) {
return state.posts.ids as string[]
}
export const fetchAddressLikeCounts = createSimpleFetchWrapper<
export const fetchAddressLikeCounts = createSimpleManyFetchWrapper<
{ postIds: string[] | null; address: string },
AddressLikeCount[]
AddressLikeCount
>({
sliceName,
fetchData: async function ({ postIds, address }, state) {
if (postIds === null) {
postIds = getAllPostIdsFromStore(state)
}
const entities = selectAllAddressLikeCounts(state)
const newIds = postIds.filter(postId => {
const id = getAddressLikeCountId({ address, postId })
return !entities[id]
})
if (!newIds.length) return []
return await getAddressLikeCountToPosts(address, postIds)
},
getCachedData: (state, id) => selectAddressLikeCount(state, id),
saveToCacheAction: data => slice.actions.setAddressLikeCounts(data),
getCachedData: (state, { postIds, address }) => {
if (postIds === null) {
postIds = getAllPostIdsFromStore(state)
}

const entities = selectAllAddressLikeCounts(state)
let isEveryDataCached = true

const postEntities: AddressLikeCount[] = []
for (let i = 0; i < postIds.length; i++) {
const id = getAddressLikeCountId({ address, postId: postIds[i] })
if (!entities[id]) {
isEveryDataCached = false
break
} else {
postEntities.push(entities[id]!)
}
}

if (isEveryDataCached) {
return postEntities
}
return undefined
shouldFetchCondition: ({ address, postIds }) => postIds?.length !== 0 && !!address,
filterNewArgs: ({ address, postIds }, isNewId) => {
// if postIds is null, fetch all postIds
if (postIds === null) return { address, postIds }
const newPostIds = postIds?.filter(postId =>
isNewId(getAddressLikeCountId({ address, postId })),
)
return { address, postIds: newPostIds }
},
sliceName,
})

const slice = createSlice({
Expand Down
32 changes: 9 additions & 23 deletions src/rtk/features/activeStaking/canPostSuperLikedSlice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'
import { getCanPostsSuperLiked } from 'src/components/utils/datahub/super-likes'
import { RootState } from 'src/rtk/app/rootReducer'
import { createSimpleFetchWrapper } from 'src/rtk/app/wrappers'
import { createSimpleManyFetchWrapper } from 'src/rtk/app/wrappers'

export type CanPostSuperLiked = {
postId: string
Expand All @@ -18,35 +18,21 @@ const selectors = adapter.getSelectors<RootState>(state => state.canPostSuperLik
export const selectCanPostSuperLiked = selectors.selectById
export const selectAllCanPostSuperLiked = selectors.selectEntities

export const fetchCanPostsSuperLiked = createSimpleFetchWrapper<
export const fetchCanPostsSuperLiked = createSimpleManyFetchWrapper<
{ postIds: string[] },
CanPostSuperLiked[]
CanPostSuperLiked
>({
sliceName,
fetchData: async function ({ postIds }) {
return await getCanPostsSuperLiked(postIds)
},
getCachedData: (state, id) => selectCanPostSuperLiked(state, id),
saveToCacheAction: data => slice.actions.setCanPostsSuperLiked(data),
getCachedData: (state, { postIds }) => {
const entities = selectAllCanPostSuperLiked(state)
let isEveryDataCached = true

const queriedEntities: CanPostSuperLiked[] = []
for (let i = 0; i < postIds.length; i++) {
const postId = postIds[i]
if (!entities[postId]) {
isEveryDataCached = false
break
} else {
queriedEntities.push(entities[postId]!)
}
}

if (isEveryDataCached) {
return queriedEntities
}
return undefined
shouldFetchCondition: ({ postIds }) => postIds?.length !== 0,
filterNewArgs: ({ postIds }, isNewId) => {
const newPostIds = postIds?.filter(postId => isNewId(postId))
return { postIds: newPostIds }
},
sliceName,
})

const slice = createSlice({
Expand Down
5 changes: 5 additions & 0 deletions src/rtk/features/activeStaking/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
selectAddressLikeCount,
} from './addressLikeCountSlice'
import { selectCanPostSuperLiked } from './canPostSuperLikedSlice'
import { selectPostReward } from './postRewardSlice'
import { fetchRewardHistory, selectUserRewardHistory } from './rewardHistorySlice'
import { fetchRewardReport, selectUserRewardReport } from './rewardReportSlice'
import { selectPostSuperLikeCount } from './superLikeCountsSlice'
Expand Down Expand Up @@ -75,3 +76,7 @@ export function useFetchUserRewardHistory(address?: string, config?: { enabled?:
data,
}
}

export function useSelectPostReward(postId: string) {
return useAppSelector(state => selectPostReward(state, postId))
}
43 changes: 43 additions & 0 deletions src/rtk/features/activeStaking/postRewardSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'
import { getPostRewards } from 'src/components/utils/datahub/super-likes'
import { RootState } from 'src/rtk/app/rootReducer'
import { createSimpleManyFetchWrapper } from 'src/rtk/app/wrappers'

export type PostRewards = {
postId: string
amount: string
isNotZero: boolean
}

const sliceName = 'postRewards'

const adapter = createEntityAdapter<PostRewards>({
selectId: data => data.postId,
})
const selectors = adapter.getSelectors<RootState>(state => state.postReward)

export const selectPostReward = selectors.selectById

export const fetchPostRewards = createSimpleManyFetchWrapper<{ postIds: string[] }, PostRewards>({
sliceName,
fetchData: async function ({ postIds }) {
return await getPostRewards(postIds)
},
getCachedData: (state, id) => selectPostReward(state, id),
saveToCacheAction: data => slice.actions.setPostRewards(data),
shouldFetchCondition: ({ postIds }) => postIds?.length !== 0,
filterNewArgs: ({ postIds }, isNewId) => {
const newPostIds = postIds?.filter(postId => isNewId(postId))
return { postIds: newPostIds }
},
})

const slice = createSlice({
name: sliceName,
initialState: adapter.getInitialState(),
reducers: {
setPostRewards: adapter.upsertMany,
},
})

export default slice.reducer
5 changes: 4 additions & 1 deletion src/rtk/features/activeStaking/rewardReportSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ const slice = createSlice({
const rewardMultiplier = BigInt(
Math.min(newSuperLike, CREATORS_CONSTANTS.SUPER_LIKES_FOR_MAX_REWARD),
)
const oldSuperLikeMultiplier = BigInt(
Math.min(rewardReport.superLikesCount, CREATORS_CONSTANTS.SUPER_LIKES_FOR_MAX_REWARD),
)

const rewardPerLike = BigInt(rewardReport.currentRewardAmount) / rewardMultiplier
const rewardPerLike = BigInt(rewardReport.currentRewardAmount) / oldSuperLikeMultiplier
const weeklyWithoutCurrentReward =
BigInt(rewardReport.weeklyReward) - BigInt(rewardReport.currentRewardAmount)

Expand Down
Loading

0 comments on commit 3f3f2a6

Please sign in to comment.