Single source of truth for predict

This commit is contained in:
Ian Philips 2022-09-15 09:12:56 -06:00
parent 4c10c8499b
commit e9f136a653
23 changed files with 88 additions and 33 deletions

View File

@ -15,6 +15,9 @@ export type EnvConfig = {
// Branding // Branding
moneyMoniker: string // e.g. 'M$' moneyMoniker: string // e.g. 'M$'
bettor?: string // e.g. 'bettor' or 'predictor'
presentBet?: string // e.g. 'bet' or 'predict'
pastBet?: string // e.g. 'bet' or 'prediction'
faviconPath?: string // Should be a file in /public faviconPath?: string // Should be a file in /public
navbarLogoPath?: string navbarLogoPath?: string
newQuestionPlaceholders: string[] newQuestionPlaceholders: string[]
@ -79,6 +82,9 @@ export const PROD_CONFIG: EnvConfig = {
visibility: 'PUBLIC', visibility: 'PUBLIC',
moneyMoniker: 'M$', moneyMoniker: 'M$',
bettor: 'predictor',
pastBet: 'prediction',
presentBet: 'predict',
navbarLogoPath: '', navbarLogoPath: '',
faviconPath: '/favicon.ico', faviconPath: '/favicon.ico',
newQuestionPlaceholders: [ newQuestionPlaceholders: [

View File

@ -7,6 +7,7 @@ type AnyTxnType =
| Referral | Referral
| UniqueBettorBonus | UniqueBettorBonus
| BettingStreakBonus | BettingStreakBonus
| CancelUniqueBettorBonus
type SourceType = 'USER' | 'CONTRACT' | 'CHARITY' | 'BANK' type SourceType = 'USER' | 'CONTRACT' | 'CHARITY' | 'BANK'
export type Txn<T extends AnyTxnType = AnyTxnType> = { export type Txn<T extends AnyTxnType = AnyTxnType> = {
@ -29,6 +30,7 @@ export type Txn<T extends AnyTxnType = AnyTxnType> = {
| 'REFERRAL' | 'REFERRAL'
| 'UNIQUE_BETTOR_BONUS' | 'UNIQUE_BETTOR_BONUS'
| 'BETTING_STREAK_BONUS' | 'BETTING_STREAK_BONUS'
| 'CANCEL_UNIQUE_BETTOR_BONUS'
// Any extra data // Any extra data
data?: { [key: string]: any } data?: { [key: string]: any }
@ -89,9 +91,19 @@ type BettingStreakBonus = {
} }
} }
type CancelUniqueBettorBonus = {
fromType: 'USER'
toType: 'BANK'
category: 'CANCEL_UNIQUE_BETTOR_BONUS'
data: {
contractId: string
}
}
export type DonationTxn = Txn & Donation export type DonationTxn = Txn & Donation
export type TipTxn = Txn & Tip export type TipTxn = Txn & Tip
export type ManalinkTxn = Txn & Manalink export type ManalinkTxn = Txn & Manalink
export type ReferralTxn = Txn & Referral export type ReferralTxn = Txn & Referral
export type BettingStreakBonusTxn = Txn & BettingStreakBonus export type BettingStreakBonusTxn = Txn & BettingStreakBonus
export type UniqueBettorBonusTxn = Txn & UniqueBettorBonus export type UniqueBettorBonusTxn = Txn & UniqueBettorBonus
export type CancelUniqueBettorBonusTxn = Txn & CancelUniqueBettorBonus

View File

@ -1,4 +1,5 @@
import { notification_preferences } from './user-notification-preferences' import { notification_preferences } from './user-notification-preferences'
import { ENV_CONFIG } from 'common/envs/constants'
export type User = { export type User = {
id: string id: string
@ -83,3 +84,10 @@ export type PortfolioMetrics = {
export const MANIFOLD_USERNAME = 'ManifoldMarkets' export const MANIFOLD_USERNAME = 'ManifoldMarkets'
export const MANIFOLD_AVATAR_URL = 'https://manifold.markets/logo-bg-white.png' export const MANIFOLD_AVATAR_URL = 'https://manifold.markets/logo-bg-white.png'
export const BETTOR = ENV_CONFIG.bettor ?? 'bettor' // aka predictor
export const BETTORS = ENV_CONFIG.bettor + 's' ?? 'bettors'
export const PRESENT_BET = ENV_CONFIG.presentBet ?? 'bet' // aka predict
export const PRESENT_BETS = ENV_CONFIG.presentBet + 's' ?? 'bets'
export const PAST_BET = ENV_CONFIG.pastBet ?? 'bet' // aka prediction
export const PAST_BETS = ENV_CONFIG.pastBet + 's' ?? 'bets' // aka predictions

View File

@ -16,6 +16,10 @@ export function formatMoneyWithDecimals(amount: number) {
return ENV_CONFIG.moneyMoniker + amount.toFixed(2) return ENV_CONFIG.moneyMoniker + amount.toFixed(2)
} }
export function capitalFirst(s: string) {
return s.charAt(0).toUpperCase() + s.slice(1)
}
export function formatWithCommas(amount: number) { export function formatWithCommas(amount: number) {
return formatter.format(Math.floor(amount)).replace('$', '') return formatter.format(Math.floor(amount)).replace('$', '')
} }

View File

@ -10,6 +10,7 @@ import { useSaveBinaryShares } from './use-save-binary-shares'
import { Col } from './layout/col' import { Col } from './layout/col'
import { Button } from 'web/components/button' import { Button } from 'web/components/button'
import { BetSignUpPrompt } from './sign-up-prompt' import { BetSignUpPrompt } from './sign-up-prompt'
import { PRESENT_BET } from 'common/user'
/** Button that opens BetPanel in a new modal */ /** Button that opens BetPanel in a new modal */
export default function BetButton(props: { export default function BetButton(props: {
@ -36,12 +37,12 @@ export default function BetButton(props: {
<Button <Button
size="lg" size="lg"
className={clsx( className={clsx(
'my-auto inline-flex min-w-[75px] whitespace-nowrap', 'my-auto inline-flex min-w-[75px] whitespace-nowrap capitalize',
btnClassName btnClassName
)} )}
onClick={() => setOpen(true)} onClick={() => setOpen(true)}
> >
Predict {PRESENT_BET}
</Button> </Button>
) : ( ) : (
<BetSignUpPrompt /> <BetSignUpPrompt />

View File

@ -3,7 +3,7 @@ import algoliasearch from 'algoliasearch/lite'
import { SearchOptions } from '@algolia/client-search' import { SearchOptions } from '@algolia/client-search'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { Contract } from 'common/contract' import { Contract } from 'common/contract'
import { User } from 'common/user' import { PAST_BETS, User } from 'common/user'
import { import {
ContractHighlightOptions, ContractHighlightOptions,
ContractsGrid, ContractsGrid,
@ -41,7 +41,7 @@ const searchIndexName = ENV === 'DEV' ? 'dev-contracts' : 'contractsIndex'
export const SORTS = [ export const SORTS = [
{ label: 'Newest', value: 'newest' }, { label: 'Newest', value: 'newest' },
{ label: 'Trending', value: 'score' }, { label: 'Trending', value: 'score' },
{ label: 'Most traded', value: 'most-traded' }, { label: `Most ${PAST_BETS}`, value: 'most-traded' },
{ label: '24h volume', value: '24-hour-vol' }, { label: '24h volume', value: '24-hour-vol' },
{ label: '24h change', value: 'prob-change-day' }, { label: '24h change', value: 'prob-change-day' },
{ label: 'Last updated', value: 'last-updated' }, { label: 'Last updated', value: 'last-updated' },
@ -450,7 +450,7 @@ function ContractSearchControls(props: {
selected={state.pillFilter === 'your-bets'} selected={state.pillFilter === 'your-bets'}
onSelect={selectPill('your-bets')} onSelect={selectPill('your-bets')}
> >
Your trades Your {PAST_BETS}
</PillButton> </PillButton>
)} )}

View File

@ -18,6 +18,7 @@ import { deleteField } from 'firebase/firestore'
import ShortToggle from '../widgets/short-toggle' import ShortToggle from '../widgets/short-toggle'
import { DuplicateContractButton } from '../copy-contract-button' import { DuplicateContractButton } from '../copy-contract-button'
import { Row } from '../layout/row' import { Row } from '../layout/row'
import { BETTORS } from 'common/user'
export const contractDetailsButtonClassName = export const contractDetailsButtonClassName =
'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500' 'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500'
@ -135,7 +136,7 @@ export function ContractInfoDialog(props: {
</tr> */} </tr> */}
<tr> <tr>
<td>Traders</td> <td>{BETTORS}</td>
<td>{bettorsCount}</td> <td>{bettorsCount}</td>
</tr> </tr>

View File

@ -12,6 +12,7 @@ import { FeedComment } from '../feed/feed-comments'
import { Spacer } from '../layout/spacer' import { Spacer } from '../layout/spacer'
import { Leaderboard } from '../leaderboard' import { Leaderboard } from '../leaderboard'
import { Title } from '../title' import { Title } from '../title'
import { BETTORS } from 'common/user'
export function ContractLeaderboard(props: { export function ContractLeaderboard(props: {
contract: Contract contract: Contract
@ -48,7 +49,7 @@ export function ContractLeaderboard(props: {
return users && users.length > 0 ? ( return users && users.length > 0 ? (
<Leaderboard <Leaderboard
title="🏅 Top traders" title={`🏅 Top ${BETTORS}`}
users={users || []} users={users || []}
columns={[ columns={[
{ {

View File

@ -1,7 +1,7 @@
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { Contract, CPMMBinaryContract } from 'common/contract' import { Contract, CPMMBinaryContract } from 'common/contract'
import { ContractComment } from 'common/comment' import { ContractComment } from 'common/comment'
import { User } from 'common/user' import { PAST_BETS, User } from 'common/user'
import { import {
ContractCommentsActivity, ContractCommentsActivity,
ContractBetsActivity, ContractBetsActivity,
@ -114,13 +114,13 @@ export function ContractTabs(props: {
badge: `${comments.length}`, badge: `${comments.length}`,
}, },
{ {
title: 'Trades', title: PAST_BETS,
content: betActivity, content: betActivity,
badge: `${visibleBets.length}`, badge: `${visibleBets.length}`,
}, },
...(!user || !userBets?.length ...(!user || !userBets?.length
? [] ? []
: [{ title: 'Your trades', content: yourTrades }]), : [{ title: `Your ${PAST_BETS}`, content: yourTrades }]),
]} ]}
/> />
{!user ? ( {!user ? (

View File

@ -14,6 +14,7 @@ import { SiteLink } from 'web/components/site-link'
import { getChallenge, getChallengeUrl } from 'web/lib/firebase/challenges' import { getChallenge, getChallengeUrl } from 'web/lib/firebase/challenges'
import { Challenge } from 'common/challenge' import { Challenge } from 'common/challenge'
import { UserLink } from 'web/components/user-link' import { UserLink } from 'web/components/user-link'
import { BETTOR } from 'common/user'
export function FeedBet(props: { contract: Contract; bet: Bet }) { export function FeedBet(props: { contract: Contract; bet: Bet }) {
const { contract, bet } = props const { contract, bet } = props
@ -94,7 +95,7 @@ export function BetStatusText(props: {
{!hideUser ? ( {!hideUser ? (
<UserLink name={bet.userName} username={bet.userUsername} /> <UserLink name={bet.userName} username={bet.userUsername} />
) : ( ) : (
<span>{self?.id === bet.userId ? 'You' : 'A trader'}</span> <span>{self?.id === bet.userId ? 'You' : `A ${BETTOR}`}</span>
)}{' '} )}{' '}
{bought} {money} {bought} {money}
{outOfTotalAmount} {outOfTotalAmount}

View File

@ -1,6 +1,6 @@
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { ContractComment } from 'common/comment' import { ContractComment } from 'common/comment'
import { User } from 'common/user' import { PRESENT_BET, User } from 'common/user'
import { Contract } from 'common/contract' import { Contract } from 'common/contract'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { minBy, maxBy, partition, sumBy, Dictionary } from 'lodash' import { minBy, maxBy, partition, sumBy, Dictionary } from 'lodash'
@ -255,7 +255,7 @@ function CommentStatus(props: {
const { contract, outcome, prob } = props const { contract, outcome, prob } = props
return ( return (
<> <>
{' betting '} {` ${PRESENT_BET}ing `}
<OutcomeLabel outcome={outcome} contract={contract} truncate="short" /> <OutcomeLabel outcome={outcome} contract={contract} truncate="short" />
{prob && ' at ' + Math.round(prob * 100) + '%'} {prob && ' at ' + Math.round(prob * 100) + '%'}
</> </>

View File

@ -1,6 +1,6 @@
import clsx from 'clsx' import clsx from 'clsx'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { User } from 'common/user' import { BETTOR, User } from 'common/user'
import { useUser, useUserById } from 'web/hooks/use-user' import { useUser, useUserById } from 'web/hooks/use-user'
import { Row } from 'web/components/layout/row' import { Row } from 'web/components/layout/row'
import { Avatar, EmptyAvatar } from 'web/components/avatar' import { Avatar, EmptyAvatar } from 'web/components/avatar'
@ -74,7 +74,7 @@ export function LiquidityStatusText(props: {
{bettor ? ( {bettor ? (
<UserLink name={bettor.name} username={bettor.username} /> <UserLink name={bettor.name} username={bettor.username} />
) : ( ) : (
<span>{isSelf ? 'You' : 'A trader'}</span> <span>{isSelf ? 'You' : `A ${BETTOR}`}</span>
)}{' '} )}{' '}
{bought} a subsidy of {money} {bought} a subsidy of {money}
<RelativeTimestamp time={createdTime} /> <RelativeTimestamp time={createdTime} />

View File

@ -13,6 +13,7 @@ import { NoLabel, YesLabel } from './outcome-label'
import { Col } from './layout/col' import { Col } from './layout/col'
import { track } from 'web/lib/service/analytics' import { track } from 'web/lib/service/analytics'
import { InfoTooltip } from './info-tooltip' import { InfoTooltip } from './info-tooltip'
import { BETTORS, PRESENT_BET } from 'common/user'
export function LiquidityPanel(props: { contract: CPMMContract }) { export function LiquidityPanel(props: { contract: CPMMContract }) {
const { contract } = props const { contract } = props
@ -104,7 +105,9 @@ function AddLiquidityPanel(props: { contract: CPMMContract }) {
<> <>
<div className="mb-4 text-gray-500"> <div className="mb-4 text-gray-500">
Contribute your M$ to make this market more accurate.{' '} Contribute your M$ to make this market more accurate.{' '}
<InfoTooltip text="More liquidity stabilizes the market, encouraging traders to bet. You can withdraw your subsidy at any time." /> <InfoTooltip
text={`More liquidity stabilizes the market, encouraging ${BETTORS} to ${PRESENT_BET}. You can withdraw your subsidy at any time.`}
/>
</div> </div>
<Row> <Row>

View File

@ -17,6 +17,7 @@ import { useRouter } from 'next/router'
import NotificationsIcon from 'web/components/notifications-icon' import NotificationsIcon from 'web/components/notifications-icon'
import { useIsIframe } from 'web/hooks/use-is-iframe' import { useIsIframe } from 'web/hooks/use-is-iframe'
import { trackCallback } from 'web/lib/service/analytics' import { trackCallback } from 'web/lib/service/analytics'
import { PAST_BETS } from 'common/user'
function getNavigation() { function getNavigation() {
return [ return [
@ -64,7 +65,7 @@ export function BottomNavBar() {
item={{ item={{
name: formatMoney(user.balance), name: formatMoney(user.balance),
trackingEventName: 'profile', trackingEventName: 'profile',
href: `/${user.username}?tab=trades`, href: `/${user.username}?tab=${PAST_BETS}`,
icon: () => ( icon: () => (
<Avatar <Avatar
className="mx-auto my-1" className="mx-auto my-1"

View File

@ -4,11 +4,12 @@ import { User } from 'web/lib/firebase/users'
import { formatMoney } from 'common/util/format' import { formatMoney } from 'common/util/format'
import { Avatar } from '../avatar' import { Avatar } from '../avatar'
import { trackCallback } from 'web/lib/service/analytics' import { trackCallback } from 'web/lib/service/analytics'
import { PAST_BETS } from 'common/user'
export function ProfileSummary(props: { user: User }) { export function ProfileSummary(props: { user: User }) {
const { user } = props const { user } = props
return ( return (
<Link href={`/${user.username}?tab=trades`}> <Link href={`/${user.username}?tab=${PAST_BETS}`}>
<a <a
onClick={trackCallback('sidebar: profile')} onClick={trackCallback('sidebar: profile')}
className="group mb-3 flex flex-row items-center gap-4 truncate rounded-md py-3 text-gray-500 hover:bg-gray-100 hover:text-gray-700" className="group mb-3 flex flex-row items-center gap-4 truncate rounded-md py-3 text-gray-500 hover:bg-gray-100 hover:text-gray-700"

View File

@ -10,6 +10,7 @@ import { NumericContract, PseudoNumericContract } from 'common/contract'
import { APIError, resolveMarket } from 'web/lib/firebase/api' import { APIError, resolveMarket } from 'web/lib/firebase/api'
import { BucketInput } from './bucket-input' import { BucketInput } from './bucket-input'
import { getPseudoProbability } from 'common/pseudo-numeric' import { getPseudoProbability } from 'common/pseudo-numeric'
import { BETTOR, BETTORS, PAST_BETS } from 'common/user'
export function NumericResolutionPanel(props: { export function NumericResolutionPanel(props: {
isAdmin: boolean isAdmin: boolean
@ -111,9 +112,12 @@ export function NumericResolutionPanel(props: {
<div> <div>
{outcome === 'CANCEL' ? ( {outcome === 'CANCEL' ? (
<>All trades will be returned with no fees.</> <>
All {PAST_BETS} will be returned. Unique {BETTOR} bonuses will be
withdrawn from your account
</>
) : ( ) : (
<>Resolving this market will immediately pay out traders.</> <>Resolving this market will immediately pay out {BETTORS}.</>
)} )}
</div> </div>

View File

@ -1,5 +1,6 @@
import { Modal } from 'web/components/layout/modal' import { Modal } from 'web/components/layout/modal'
import { Col } from 'web/components/layout/col' import { Col } from 'web/components/layout/col'
import { PAST_BETS } from 'common/user'
export function LoansModal(props: { export function LoansModal(props: {
isOpen: boolean isOpen: boolean
@ -11,7 +12,7 @@ export function LoansModal(props: {
<Modal open={isOpen} setOpen={setOpen}> <Modal open={isOpen} setOpen={setOpen}>
<Col className="items-center gap-4 rounded-md bg-white px-8 py-6"> <Col className="items-center gap-4 rounded-md bg-white px-8 py-6">
<span className={'text-8xl'}>🏦</span> <span className={'text-8xl'}>🏦</span>
<span className="text-xl">Daily loans on your trades</span> <span className="text-xl">Daily loans on your {PAST_BETS}</span>
<Col className={'gap-2'}> <Col className={'gap-2'}>
<span className={'text-indigo-700'}> What are daily loans?</span> <span className={'text-indigo-700'}> What are daily loans?</span>
<span className={'ml-2'}> <span className={'ml-2'}>

View File

@ -10,6 +10,7 @@ import { APIError, resolveMarket } from 'web/lib/firebase/api'
import { ProbabilitySelector } from './probability-selector' import { ProbabilitySelector } from './probability-selector'
import { getProbability } from 'common/calculate' import { getProbability } from 'common/calculate'
import { BinaryContract, resolution } from 'common/contract' import { BinaryContract, resolution } from 'common/contract'
import { BETTOR, BETTORS, PAST_BETS } from 'common/user'
export function ResolutionPanel(props: { export function ResolutionPanel(props: {
isAdmin: boolean isAdmin: boolean
@ -90,23 +91,28 @@ export function ResolutionPanel(props: {
<div> <div>
{outcome === 'YES' ? ( {outcome === 'YES' ? (
<> <>
Winnings will be paid out to traders who bought YES. Winnings will be paid out to {BETTORS} who bought YES.
{/* <br /> {/* <br />
<br /> <br />
You will earn {earnedFees}. */} You will earn {earnedFees}. */}
</> </>
) : outcome === 'NO' ? ( ) : outcome === 'NO' ? (
<> <>
Winnings will be paid out to traders who bought NO. Winnings will be paid out to {BETTORS} who bought NO.
{/* <br /> {/* <br />
<br /> <br />
You will earn {earnedFees}. */} You will earn {earnedFees}. */}
</> </>
) : outcome === 'CANCEL' ? ( ) : outcome === 'CANCEL' ? (
<>All trades will be returned with no fees.</> <>
All {PAST_BETS} will be returned. Unique {BETTOR} bonuses will be
withdrawn from your account
</>
) : outcome === 'MKT' ? ( ) : outcome === 'MKT' ? (
<Col className="gap-6"> <Col className="gap-6">
<div>Traders will be paid out at the probability you specify:</div> <div>
{PAST_BETS} will be paid out at the probability you specify:
</div>
<ProbabilitySelector <ProbabilitySelector
probabilityInt={Math.round(prob)} probabilityInt={Math.round(prob)}
setProbabilityInt={setProb} setProbabilityInt={setProb}
@ -114,7 +120,7 @@ export function ResolutionPanel(props: {
{/* You will earn {earnedFees}. */} {/* You will earn {earnedFees}. */}
</Col> </Col>
) : ( ) : (
<>Resolving this market will immediately pay out traders.</> <>Resolving this market will immediately pay out {BETTORS}.</>
)} )}
</div> </div>

View File

@ -25,7 +25,7 @@ import { UserFollowButton } from './follow-button'
import { GroupsButton } from 'web/components/groups/groups-button' import { GroupsButton } from 'web/components/groups/groups-button'
import { PortfolioValueSection } from './portfolio/portfolio-value-section' import { PortfolioValueSection } from './portfolio/portfolio-value-section'
import { ReferralsButton } from 'web/components/referrals-button' import { ReferralsButton } from 'web/components/referrals-button'
import { formatMoney } from 'common/util/format' import { capitalFirst, formatMoney } from 'common/util/format'
import { ShareIconButton } from 'web/components/share-icon-button' import { ShareIconButton } from 'web/components/share-icon-button'
import { ENV_CONFIG } from 'common/envs/constants' import { ENV_CONFIG } from 'common/envs/constants'
import { import {
@ -35,6 +35,7 @@ import {
import { REFERRAL_AMOUNT } from 'common/economy' import { REFERRAL_AMOUNT } from 'common/economy'
import { LoansModal } from './profile/loans-modal' import { LoansModal } from './profile/loans-modal'
import { UserLikesButton } from 'web/components/profile/user-likes-button' import { UserLikesButton } from 'web/components/profile/user-likes-button'
import { PAST_BETS } from 'common/user'
export function UserPage(props: { user: User }) { export function UserPage(props: { user: User }) {
const { user } = props const { user } = props
@ -269,7 +270,7 @@ export function UserPage(props: { user: User }) {
), ),
}, },
{ {
title: 'Trades', title: capitalFirst(PAST_BETS),
content: ( content: (
<> <>
<BetsList user={user} /> <BetsList user={user} />

View File

@ -8,6 +8,7 @@ import {
usePersistentState, usePersistentState,
urlParamStore, urlParamStore,
} from 'web/hooks/use-persistent-state' } from 'web/hooks/use-persistent-state'
import { PAST_BETS } from 'common/user'
const MAX_CONTRACTS_RENDERED = 100 const MAX_CONTRACTS_RENDERED = 100
@ -101,7 +102,7 @@ export default function ContractSearchFirestore(props: {
> >
<option value="score">Trending</option> <option value="score">Trending</option>
<option value="newest">Newest</option> <option value="newest">Newest</option>
<option value="most-traded">Most traded</option> <option value="most-traded">Most ${PAST_BETS}</option>
<option value="24-hour-vol">24h volume</option> <option value="24-hour-vol">24h volume</option>
<option value="close-date">Closing soon</option> <option value="close-date">Closing soon</option>
</select> </select>

View File

@ -50,6 +50,7 @@ import { usePost } from 'web/hooks/use-post'
import { useAdmin } from 'web/hooks/use-admin' import { useAdmin } from 'web/hooks/use-admin'
import { track } from '@amplitude/analytics-browser' import { track } from '@amplitude/analytics-browser'
import { SelectMarketsModal } from 'web/components/contract-select-modal' import { SelectMarketsModal } from 'web/components/contract-select-modal'
import { BETTORS } from 'common/user'
export const getStaticProps = fromPropz(getStaticPropz) export const getStaticProps = fromPropz(getStaticPropz)
export async function getStaticPropz(props: { params: { slugs: string[] } }) { export async function getStaticPropz(props: { params: { slugs: string[] } }) {
@ -155,7 +156,7 @@ export default function GroupPage(props: {
<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">
<GroupLeaderboard <GroupLeaderboard
topUsers={topTraders} topUsers={topTraders}
title="🏅 Top traders" title={`🏅 Top ${BETTORS}`}
header="Profit" header="Profit"
maxToShow={maxLeaderboardSize} maxToShow={maxLeaderboardSize}
/> />

View File

@ -14,6 +14,7 @@ import { Title } from 'web/components/title'
import { Tabs } from 'web/components/layout/tabs' import { Tabs } from 'web/components/layout/tabs'
import { useTracking } from 'web/hooks/use-tracking' import { useTracking } from 'web/hooks/use-tracking'
import { SEO } from 'web/components/SEO' import { SEO } from 'web/components/SEO'
import { BETTORS } from 'common/user'
export async function getStaticProps() { export async function getStaticProps() {
const props = await fetchProps() const props = await fetchProps()
@ -79,7 +80,7 @@ export default function Leaderboards(_props: {
<> <>
<Col className="mx-4 items-center gap-10 lg:flex-row"> <Col className="mx-4 items-center gap-10 lg:flex-row">
<Leaderboard <Leaderboard
title="🏅 Top traders" title={`🏅 Top ${BETTORS}`}
users={topTraders} users={topTraders}
columns={[ columns={[
{ {
@ -126,7 +127,7 @@ export default function Leaderboards(_props: {
<Page> <Page>
<SEO <SEO
title="Leaderboards" title="Leaderboards"
description="Manifold's leaderboards show the top traders and market creators." description={`Manifold's leaderboards show the top ${BETTORS} and market creators.`}
url="/leaderboards" url="/leaderboards"
/> />
<Title text={'Leaderboards'} className={'hidden md:block'} /> <Title text={'Leaderboards'} className={'hidden md:block'} />

View File

@ -13,6 +13,7 @@ import { SiteLink } from 'web/components/site-link'
import { Linkify } from 'web/components/linkify' import { Linkify } from 'web/components/linkify'
import { getStats } from 'web/lib/firebase/stats' import { getStats } from 'web/lib/firebase/stats'
import { Stats } from 'common/stats' import { Stats } from 'common/stats'
import { PAST_BETS } from 'common/user'
export default function Analytics() { export default function Analytics() {
const [stats, setStats] = useState<Stats | undefined>(undefined) const [stats, setStats] = useState<Stats | undefined>(undefined)
@ -156,7 +157,7 @@ export function CustomAnalytics(props: {
defaultIndex={0} defaultIndex={0}
tabs={[ tabs={[
{ {
title: 'Trades', title: PAST_BETS,
content: ( content: (
<DailyCountChart <DailyCountChart
dailyCounts={dailyBetCounts} dailyCounts={dailyBetCounts}