Members to memberIds
This commit is contained in:
		
							parent
							
								
									cce14cbe1f
								
							
						
					
					
						commit
						c30eca02f5
					
				| 
						 | 
					@ -24,7 +24,6 @@ import { Contract } from 'common/contract'
 | 
				
			||||||
import { getContractFromId, updateContract } from 'web/lib/firebase/contracts'
 | 
					import { getContractFromId, updateContract } from 'web/lib/firebase/contracts'
 | 
				
			||||||
import { db } from 'web/lib/firebase/init'
 | 
					import { db } from 'web/lib/firebase/init'
 | 
				
			||||||
import { filterDefined } from 'common/util/array'
 | 
					import { filterDefined } from 'common/util/array'
 | 
				
			||||||
import { getUser } from 'web/lib/firebase/users'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const groups = coll<Group>('groups')
 | 
					export const groups = coll<Group>('groups')
 | 
				
			||||||
export const groupMembers = (groupId: string) =>
 | 
					export const groupMembers = (groupId: string) =>
 | 
				
			||||||
| 
						 | 
					@ -244,7 +243,7 @@ export function getGroupLinkToDisplay(contract: Contract) {
 | 
				
			||||||
  return groupToDisplay
 | 
					  return groupToDisplay
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function listMembers(group: Group) {
 | 
					export async function listMemberIds(group: Group) {
 | 
				
			||||||
  const members = await getValues<GroupMemberDoc>(groupMembers(group.id))
 | 
					  const members = await getValues<GroupMemberDoc>(groupMembers(group.id))
 | 
				
			||||||
  return await Promise.all(members.map((m) => m.userId).map(getUser))
 | 
					  return members.map((m) => m.userId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,7 @@
 | 
				
			||||||
import React, { useState } from 'react'
 | 
					import React, { useState } from 'react'
 | 
				
			||||||
import Link from 'next/link'
 | 
					import Link from 'next/link'
 | 
				
			||||||
import { useRouter } from 'next/router'
 | 
					import { useRouter } from 'next/router'
 | 
				
			||||||
import { debounce, sortBy, take } from 'lodash'
 | 
					import { sortBy, take } from 'lodash'
 | 
				
			||||||
import { SearchIcon } from '@heroicons/react/outline'
 | 
					 | 
				
			||||||
import { toast } from 'react-hot-toast'
 | 
					import { toast } from 'react-hot-toast'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Group, GROUP_CHAT_SLUG } from 'common/group'
 | 
					import { Group, GROUP_CHAT_SLUG } from 'common/group'
 | 
				
			||||||
| 
						 | 
					@ -14,14 +13,18 @@ import {
 | 
				
			||||||
  getGroupBySlug,
 | 
					  getGroupBySlug,
 | 
				
			||||||
  groupPath,
 | 
					  groupPath,
 | 
				
			||||||
  joinGroup,
 | 
					  joinGroup,
 | 
				
			||||||
  listMembers,
 | 
					  listMemberIds,
 | 
				
			||||||
  updateGroup,
 | 
					  updateGroup,
 | 
				
			||||||
} from 'web/lib/firebase/groups'
 | 
					} from 'web/lib/firebase/groups'
 | 
				
			||||||
import { Row } from 'web/components/layout/row'
 | 
					import { Row } from 'web/components/layout/row'
 | 
				
			||||||
import { firebaseLogin, getUser, User } from 'web/lib/firebase/users'
 | 
					import { firebaseLogin, getUser, User } from 'web/lib/firebase/users'
 | 
				
			||||||
import { Col } from 'web/components/layout/col'
 | 
					import { Col } from 'web/components/layout/col'
 | 
				
			||||||
import { useUser } from 'web/hooks/use-user'
 | 
					import { useUser } from 'web/hooks/use-user'
 | 
				
			||||||
import { useGroup, useGroupContractIds, useMembers } from 'web/hooks/use-group'
 | 
					import {
 | 
				
			||||||
 | 
					  useGroup,
 | 
				
			||||||
 | 
					  useGroupContractIds,
 | 
				
			||||||
 | 
					  useMemberIds,
 | 
				
			||||||
 | 
					} from 'web/hooks/use-group'
 | 
				
			||||||
import { scoreCreators, scoreTraders } from 'common/scoring'
 | 
					import { scoreCreators, scoreTraders } from 'common/scoring'
 | 
				
			||||||
import { Leaderboard } from 'web/components/leaderboard'
 | 
					import { Leaderboard } from 'web/components/leaderboard'
 | 
				
			||||||
import { formatMoney } from 'common/util/format'
 | 
					import { formatMoney } from 'common/util/format'
 | 
				
			||||||
| 
						 | 
					@ -35,9 +38,7 @@ import { LoadingIndicator } from 'web/components/loading-indicator'
 | 
				
			||||||
import { Modal } from 'web/components/layout/modal'
 | 
					import { Modal } from 'web/components/layout/modal'
 | 
				
			||||||
import { ChoicesToggleGroup } from 'web/components/choices-toggle-group'
 | 
					import { ChoicesToggleGroup } from 'web/components/choices-toggle-group'
 | 
				
			||||||
import { ContractSearch } from 'web/components/contract-search'
 | 
					import { ContractSearch } from 'web/components/contract-search'
 | 
				
			||||||
import { FollowList } from 'web/components/follow-list'
 | 
					 | 
				
			||||||
import { JoinOrLeaveGroupButton } from 'web/components/groups/groups-button'
 | 
					import { JoinOrLeaveGroupButton } from 'web/components/groups/groups-button'
 | 
				
			||||||
import { searchInAny } from 'common/util/parse'
 | 
					 | 
				
			||||||
import { CopyLinkButton } from 'web/components/copy-link-button'
 | 
					import { CopyLinkButton } from 'web/components/copy-link-button'
 | 
				
			||||||
import { ENV_CONFIG } from 'common/envs/constants'
 | 
					import { ENV_CONFIG } from 'common/envs/constants'
 | 
				
			||||||
import { useSaveReferral } from 'web/hooks/use-save-referral'
 | 
					import { useSaveReferral } from 'web/hooks/use-save-referral'
 | 
				
			||||||
| 
						 | 
					@ -59,7 +60,7 @@ export async function getStaticPropz(props: { params: { slugs: string[] } }) {
 | 
				
			||||||
  const { slugs } = props.params
 | 
					  const { slugs } = props.params
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const group = await getGroupBySlug(slugs[0])
 | 
					  const group = await getGroupBySlug(slugs[0])
 | 
				
			||||||
  const members = group && (await listMembers(group))
 | 
					  const memberIds = group && (await listMemberIds(group))
 | 
				
			||||||
  const creatorPromise = group ? getUser(group.creatorId) : null
 | 
					  const creatorPromise = group ? getUser(group.creatorId) : null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const contracts =
 | 
					  const contracts =
 | 
				
			||||||
| 
						 | 
					@ -79,9 +80,9 @@ export async function getStaticPropz(props: { params: { slugs: string[] } }) {
 | 
				
			||||||
  const creatorScores = scoreCreators(contracts)
 | 
					  const creatorScores = scoreCreators(contracts)
 | 
				
			||||||
  const traderScores = scoreTraders(contracts, bets)
 | 
					  const traderScores = scoreTraders(contracts, bets)
 | 
				
			||||||
  const [topCreators, topTraders] =
 | 
					  const [topCreators, topTraders] =
 | 
				
			||||||
    (members && [
 | 
					    (memberIds && [
 | 
				
			||||||
      toTopUsers(creatorScores, members),
 | 
					      await toTopUsers(creatorScores, memberIds),
 | 
				
			||||||
      toTopUsers(traderScores, members),
 | 
					      await toTopUsers(traderScores, memberIds),
 | 
				
			||||||
    ]) ??
 | 
					    ]) ??
 | 
				
			||||||
    []
 | 
					    []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,7 +94,7 @@ export async function getStaticPropz(props: { params: { slugs: string[] } }) {
 | 
				
			||||||
    props: {
 | 
					    props: {
 | 
				
			||||||
      contractsCount,
 | 
					      contractsCount,
 | 
				
			||||||
      group,
 | 
					      group,
 | 
				
			||||||
      members,
 | 
					      memberIds,
 | 
				
			||||||
      creator,
 | 
					      creator,
 | 
				
			||||||
      traderScores,
 | 
					      traderScores,
 | 
				
			||||||
      topTraders,
 | 
					      topTraders,
 | 
				
			||||||
| 
						 | 
					@ -108,18 +109,21 @@ export async function getStaticPropz(props: { params: { slugs: string[] } }) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function toTopUsers(userScores: { [userId: string]: number }, users: User[]) {
 | 
					function toTopUsers(
 | 
				
			||||||
 | 
					  userScores: { [userId: string]: number },
 | 
				
			||||||
 | 
					  userIds: string[]
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
  const topUserPairs = take(
 | 
					  const topUserPairs = take(
 | 
				
			||||||
    sortBy(Object.entries(userScores), ([_, score]) => -1 * score),
 | 
					    sortBy(Object.entries(userScores), ([_, score]) => -1 * score),
 | 
				
			||||||
    10
 | 
					    10
 | 
				
			||||||
  ).filter(([_, score]) => score >= 0.5)
 | 
					  ).filter(([_, score]) => score >= 0.5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const topUsers = topUserPairs.map(
 | 
					  const topUserIds = topUserPairs
 | 
				
			||||||
    ([userId]) => users.filter((user) => user.id === userId)[0]
 | 
					    .map(([userId]) => userIds.filter((uid) => uid === userId)[0])
 | 
				
			||||||
  )
 | 
					    .filter((userId) => userId != null) as string[]
 | 
				
			||||||
  return topUsers.filter((user) => user)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Promise.all(topUserIds.map(getUser))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
export async function getStaticPaths() {
 | 
					export async function getStaticPaths() {
 | 
				
			||||||
  return { paths: [], fallback: 'blocking' }
 | 
					  return { paths: [], fallback: 'blocking' }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -134,7 +138,7 @@ const groupSubpages = [
 | 
				
			||||||
export default function GroupPage(props: {
 | 
					export default function GroupPage(props: {
 | 
				
			||||||
  contractsCount: number
 | 
					  contractsCount: number
 | 
				
			||||||
  group: Group | null
 | 
					  group: Group | null
 | 
				
			||||||
  members: User[]
 | 
					  memberIds: string[]
 | 
				
			||||||
  creator: User
 | 
					  creator: User
 | 
				
			||||||
  traderScores: { [userId: string]: number }
 | 
					  traderScores: { [userId: string]: number }
 | 
				
			||||||
  topTraders: User[]
 | 
					  topTraders: User[]
 | 
				
			||||||
| 
						 | 
					@ -147,7 +151,7 @@ export default function GroupPage(props: {
 | 
				
			||||||
  props = usePropz(props, getStaticPropz) ?? {
 | 
					  props = usePropz(props, getStaticPropz) ?? {
 | 
				
			||||||
    contractsCount: 0,
 | 
					    contractsCount: 0,
 | 
				
			||||||
    group: null,
 | 
					    group: null,
 | 
				
			||||||
    members: [],
 | 
					    memberIds: [],
 | 
				
			||||||
    creator: null,
 | 
					    creator: null,
 | 
				
			||||||
    traderScores: {},
 | 
					    traderScores: {},
 | 
				
			||||||
    topTraders: [],
 | 
					    topTraders: [],
 | 
				
			||||||
| 
						 | 
					@ -175,7 +179,7 @@ export default function GroupPage(props: {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const user = useUser()
 | 
					  const user = useUser()
 | 
				
			||||||
  const isAdmin = useAdmin()
 | 
					  const isAdmin = useAdmin()
 | 
				
			||||||
  const members = useMembers(group?.id) ?? props.members
 | 
					  const memberIds = useMemberIds(group?.id ?? null) ?? props.memberIds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useSaveReferral(user, {
 | 
					  useSaveReferral(user, {
 | 
				
			||||||
    defaultReferrerUsername: creator.username,
 | 
					    defaultReferrerUsername: creator.username,
 | 
				
			||||||
| 
						 | 
					@ -186,7 +190,7 @@ export default function GroupPage(props: {
 | 
				
			||||||
    return <Custom404 />
 | 
					    return <Custom404 />
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  const isCreator = user && group && user.id === group.creatorId
 | 
					  const isCreator = user && group && user.id === group.creatorId
 | 
				
			||||||
  const isMember = user && members.map((m) => m.id).includes(user.id)
 | 
					  const isMember = user && memberIds.includes(user.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const leaderboard = (
 | 
					  const leaderboard = (
 | 
				
			||||||
    <Col>
 | 
					    <Col>
 | 
				
			||||||
| 
						 | 
					@ -195,7 +199,7 @@ export default function GroupPage(props: {
 | 
				
			||||||
        creatorScores={creatorScores}
 | 
					        creatorScores={creatorScores}
 | 
				
			||||||
        topTraders={topTraders}
 | 
					        topTraders={topTraders}
 | 
				
			||||||
        topCreators={topCreators}
 | 
					        topCreators={topCreators}
 | 
				
			||||||
        members={members}
 | 
					        memberIds={memberIds}
 | 
				
			||||||
        user={user}
 | 
					        user={user}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </Col>
 | 
					    </Col>
 | 
				
			||||||
| 
						 | 
					@ -216,7 +220,7 @@ export default function GroupPage(props: {
 | 
				
			||||||
        creator={creator}
 | 
					        creator={creator}
 | 
				
			||||||
        isCreator={!!isCreator}
 | 
					        isCreator={!!isCreator}
 | 
				
			||||||
        user={user}
 | 
					        user={user}
 | 
				
			||||||
        members={members}
 | 
					        memberIds={memberIds}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </Col>
 | 
					    </Col>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
| 
						 | 
					@ -311,9 +315,9 @@ function GroupOverview(props: {
 | 
				
			||||||
  creator: User
 | 
					  creator: User
 | 
				
			||||||
  user: User | null | undefined
 | 
					  user: User | null | undefined
 | 
				
			||||||
  isCreator: boolean
 | 
					  isCreator: boolean
 | 
				
			||||||
  members: User[]
 | 
					  memberIds: string[]
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  const { group, creator, isCreator, user, members } = props
 | 
					  const { group, creator, isCreator, user, memberIds } = props
 | 
				
			||||||
  const anyoneCanJoinChoices: { [key: string]: string } = {
 | 
					  const anyoneCanJoinChoices: { [key: string]: string } = {
 | 
				
			||||||
    Closed: 'false',
 | 
					    Closed: 'false',
 | 
				
			||||||
    Open: 'true',
 | 
					    Open: 'true',
 | 
				
			||||||
| 
						 | 
					@ -332,7 +336,7 @@ function GroupOverview(props: {
 | 
				
			||||||
  const shareUrl = `https://${ENV_CONFIG.domain}${groupPath(
 | 
					  const shareUrl = `https://${ENV_CONFIG.domain}${groupPath(
 | 
				
			||||||
    group.slug
 | 
					    group.slug
 | 
				
			||||||
  )}${postFix}`
 | 
					  )}${postFix}`
 | 
				
			||||||
  const isMember = user ? members.map((m) => m.id).includes(user.id) : false
 | 
					  const isMember = user ? memberIds.includes(user.id) : false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
| 
						 | 
					@ -398,66 +402,11 @@ function GroupOverview(props: {
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </Col>
 | 
					          </Col>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
 | 
					 | 
				
			||||||
        <Col className={'mt-2'}>
 | 
					 | 
				
			||||||
          <div className="mb-2 text-lg">Members</div>
 | 
					 | 
				
			||||||
          <GroupMemberSearch members={members} group={group} />
 | 
					 | 
				
			||||||
        </Col>
 | 
					 | 
				
			||||||
      </Col>
 | 
					      </Col>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function SearchBar(props: { setQuery: (query: string) => void }) {
 | 
					 | 
				
			||||||
  const { setQuery } = props
 | 
					 | 
				
			||||||
  const debouncedQuery = debounce(setQuery, 50)
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className={'relative'}>
 | 
					 | 
				
			||||||
      <SearchIcon className={'absolute left-5 top-3.5 h-5 w-5 text-gray-500'} />
 | 
					 | 
				
			||||||
      <input
 | 
					 | 
				
			||||||
        type="text"
 | 
					 | 
				
			||||||
        onChange={(e) => debouncedQuery(e.target.value)}
 | 
					 | 
				
			||||||
        placeholder="Find a member"
 | 
					 | 
				
			||||||
        className="input input-bordered mb-4 w-full pl-12"
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function GroupMemberSearch(props: { members: User[]; group: Group }) {
 | 
					 | 
				
			||||||
  const [query, setQuery] = useState('')
 | 
					 | 
				
			||||||
  const { group } = props
 | 
					 | 
				
			||||||
  let { members } = props
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Use static members on load, but also listen to member changes:
 | 
					 | 
				
			||||||
  const listenToMembers = useMembers(group.id)
 | 
					 | 
				
			||||||
  if (listenToMembers) {
 | 
					 | 
				
			||||||
    members = listenToMembers
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // TODO use find-active-contracts to sort by?
 | 
					 | 
				
			||||||
  const matches = sortBy(members, [(member) => member.name]).filter((m) =>
 | 
					 | 
				
			||||||
    searchInAny(query, m.name, m.username)
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  const matchLimit = 25
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div>
 | 
					 | 
				
			||||||
      <SearchBar setQuery={setQuery} />
 | 
					 | 
				
			||||||
      <Col className={'gap-2'}>
 | 
					 | 
				
			||||||
        {matches.length > 0 && (
 | 
					 | 
				
			||||||
          <FollowList userIds={matches.slice(0, matchLimit).map((m) => m.id)} />
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
        {matches.length > 25 && (
 | 
					 | 
				
			||||||
          <div className={'text-center'}>
 | 
					 | 
				
			||||||
            And {matches.length - matchLimit} more...
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      </Col>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function SortedLeaderboard(props: {
 | 
					function SortedLeaderboard(props: {
 | 
				
			||||||
  users: User[]
 | 
					  users: User[]
 | 
				
			||||||
  scoreFunction: (user: User) => number
 | 
					  scoreFunction: (user: User) => number
 | 
				
			||||||
| 
						 | 
					@ -466,11 +415,11 @@ function SortedLeaderboard(props: {
 | 
				
			||||||
  maxToShow?: number
 | 
					  maxToShow?: number
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  const { users, scoreFunction, title, header, maxToShow } = props
 | 
					  const { users, scoreFunction, title, header, maxToShow } = props
 | 
				
			||||||
  const sortedUsers = users.sort((a, b) => scoreFunction(b) - scoreFunction(a))
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Leaderboard
 | 
					    <Leaderboard
 | 
				
			||||||
      className="max-w-xl"
 | 
					      className="max-w-xl"
 | 
				
			||||||
      users={sortedUsers}
 | 
					      users={users}
 | 
				
			||||||
      title={title}
 | 
					      title={title}
 | 
				
			||||||
      columns={[
 | 
					      columns={[
 | 
				
			||||||
        { header, renderCell: (user) => formatMoney(scoreFunction(user)) },
 | 
					        { header, renderCell: (user) => formatMoney(scoreFunction(user)) },
 | 
				
			||||||
| 
						 | 
					@ -485,28 +434,29 @@ function GroupLeaderboards(props: {
 | 
				
			||||||
  creatorScores: { [userId: string]: number }
 | 
					  creatorScores: { [userId: string]: number }
 | 
				
			||||||
  topTraders: User[]
 | 
					  topTraders: User[]
 | 
				
			||||||
  topCreators: User[]
 | 
					  topCreators: User[]
 | 
				
			||||||
  members: User[]
 | 
					  memberIds: string[]
 | 
				
			||||||
  user: User | null | undefined
 | 
					  user: User | null | undefined
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  const { traderScores, creatorScores, members, topTraders, topCreators } =
 | 
					  const { traderScores, creatorScores, memberIds, topTraders, topCreators } =
 | 
				
			||||||
    props
 | 
					    props
 | 
				
			||||||
  const maxToShow = 50
 | 
					  const maxToShow = 50
 | 
				
			||||||
  // Consider hiding M$0
 | 
					  // Consider hiding M$0
 | 
				
			||||||
  // If it's just one member (curator), show all bettors, otherwise just show members
 | 
					  // If it's just one member (curator), show all bettors, otherwise just show members
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Col>
 | 
					    <Col>
 | 
				
			||||||
      <div className="mt-4 flex flex-col gap-8 px-4 md:flex-row">
 | 
					      <div className="mt-4 flex flex-col gap-8 px-4 md:flex-row">
 | 
				
			||||||
        {members.length > 1 ? (
 | 
					        {memberIds.length > 1 ? (
 | 
				
			||||||
          <>
 | 
					          <>
 | 
				
			||||||
            <SortedLeaderboard
 | 
					            <SortedLeaderboard
 | 
				
			||||||
              users={members}
 | 
					              users={topTraders}
 | 
				
			||||||
              scoreFunction={(user) => traderScores[user.id] ?? 0}
 | 
					              scoreFunction={(user) => traderScores[user.id] ?? 0}
 | 
				
			||||||
              title="🏅 Top traders"
 | 
					              title="🏅 Top traders"
 | 
				
			||||||
              header="Profit"
 | 
					              header="Profit"
 | 
				
			||||||
              maxToShow={maxToShow}
 | 
					              maxToShow={maxToShow}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
            <SortedLeaderboard
 | 
					            <SortedLeaderboard
 | 
				
			||||||
              users={members}
 | 
					              users={topCreators}
 | 
				
			||||||
              scoreFunction={(user) => creatorScores[user.id] ?? 0}
 | 
					              scoreFunction={(user) => creatorScores[user.id] ?? 0}
 | 
				
			||||||
              title="🏅 Top creators"
 | 
					              title="🏅 Top creators"
 | 
				
			||||||
              header="Market volume"
 | 
					              header="Market volume"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user