diff --git a/web/components/bet-summary.tsx b/web/components/bet-summary.tsx
new file mode 100644
index 00000000..aa64da43
--- /dev/null
+++ b/web/components/bet-summary.tsx
@@ -0,0 +1,120 @@
+import { sumBy } from 'lodash'
+import clsx from 'clsx'
+
+import { Bet } from 'web/lib/firebase/bets'
+import { formatMoney, formatWithCommas } from 'common/util/format'
+import { Col } from './layout/col'
+import { Contract } from 'web/lib/firebase/contracts'
+import { Row } from './layout/row'
+import { YesLabel, NoLabel } from './outcome-label'
+import {
+ calculatePayout,
+ getContractBetMetrics,
+ getProbability,
+} from 'common/calculate'
+import { InfoTooltip } from './info-tooltip'
+import { ProfitBadge } from './profit-badge'
+
+export function BetsSummary(props: {
+ contract: Contract
+ userBets: Bet[]
+ className?: string
+}) {
+ const { contract, className } = props
+ const { resolution, outcomeType } = contract
+ const isBinary = outcomeType === 'BINARY'
+
+ const bets = props.userBets.filter((b) => !b.isAnte)
+ const { profitPercent, payout, profit, invested } = getContractBetMetrics(
+ contract,
+ bets
+ )
+
+ const excludeSales = bets.filter((b) => !b.isSold && !b.sale)
+ const yesWinnings = sumBy(excludeSales, (bet) =>
+ calculatePayout(contract, bet, 'YES')
+ )
+ const noWinnings = sumBy(excludeSales, (bet) =>
+ calculatePayout(contract, bet, 'NO')
+ )
+
+ const position = yesWinnings - noWinnings
+
+ const prob = isBinary ? getProbability(contract) : 0
+ const expectation = prob * yesWinnings + (1 - prob) * noWinnings
+
+ if (bets.length === 0) return <>>
+
+ return (
+
+
+ {resolution ? (
+
+ Payout
+
+ {formatMoney(payout)}{' '}
+
+
+
+ ) : isBinary ? (
+
+
+ Position{' '}
+
+
+
+ {position > 1e-7 ? (
+ <>
+ {formatWithCommas(position)}
+ >
+ ) : position < -1e-7 ? (
+ <>
+ {formatWithCommas(-position)}
+ >
+ ) : (
+ '——'
+ )}
+
+
+ ) : (
+
+
+ Expectation{''}
+
+
+ {formatMoney(payout)}
+
+ )}
+
+
+
+ Invested{' '}
+
+
+ {formatMoney(invested)}
+
+
+ {isBinary && !resolution && (
+
+
+ Expectation{' '}
+
+
+ {formatMoney(expectation)}
+
+ )}
+
+
+
+ Profit{' '}
+
+
+
+ {formatMoney(profit)}
+
+
+
+
+
+ )
+}
diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx
index dbb2db56..5a95f22f 100644
--- a/web/components/bets-list.tsx
+++ b/web/components/bets-list.tsx
@@ -22,7 +22,7 @@ import {
import { Row } from './layout/row'
import { sellBet } from 'web/lib/firebase/api'
import { ConfirmationButton } from './confirmation-button'
-import { OutcomeLabel, YesLabel, NoLabel } from './outcome-label'
+import { OutcomeLabel } from './outcome-label'
import { LoadingIndicator } from './loading-indicator'
import { SiteLink } from './site-link'
import {
@@ -38,14 +38,14 @@ import { NumericContract } from 'common/contract'
import { formatNumericProbability } from 'common/pseudo-numeric'
import { useUser } from 'web/hooks/use-user'
import { useUserBets } from 'web/hooks/use-user-bets'
-import { SellSharesModal } from './sell-modal'
import { useUnfilledBets } from 'web/hooks/use-bets'
import { LimitBet } from 'common/bet'
-import { floatingEqual } from 'common/util/math'
import { Pagination } from './pagination'
import { LimitOrderTable } from './limit-bets'
import { UserLink } from 'web/components/user-link'
import { useUserBetContracts } from 'web/hooks/use-contracts'
+import { BetsSummary } from './bet-summary'
+import { ProfitBadge } from './profit-badge'
type BetSort = 'newest' | 'profit' | 'closeTime' | 'value'
type BetFilter = 'open' | 'limit_bet' | 'sold' | 'closed' | 'resolved' | 'all'
@@ -337,8 +337,7 @@ function ContractBets(props: {
{contract.mechanism === 'cpmm-1' && limitBets.length > 0 && (
@@ -364,125 +363,6 @@ function ContractBets(props: {
)
}
-export function BetsSummary(props: {
- contract: Contract
- bets: Bet[]
- isYourBets: boolean
- className?: string
-}) {
- const { contract, isYourBets, className } = props
- const { resolution, closeTime, outcomeType, mechanism } = contract
- const isBinary = outcomeType === 'BINARY'
- const isPseudoNumeric = outcomeType === 'PSEUDO_NUMERIC'
- const isCpmm = mechanism === 'cpmm-1'
- const isClosed = closeTime && Date.now() > closeTime
-
- const bets = props.bets.filter((b) => !b.isAnte)
- const { hasShares, invested, profitPercent, payout, profit, totalShares } =
- getContractBetMetrics(contract, bets)
-
- const excludeSales = bets.filter((b) => !b.isSold && !b.sale)
- const yesWinnings = sumBy(excludeSales, (bet) =>
- calculatePayout(contract, bet, 'YES')
- )
- const noWinnings = sumBy(excludeSales, (bet) =>
- calculatePayout(contract, bet, 'NO')
- )
-
- const [showSellModal, setShowSellModal] = useState(false)
- const user = useUser()
-
- const sharesOutcome = floatingEqual(totalShares.YES ?? 0, 0)
- ? floatingEqual(totalShares.NO ?? 0, 0)
- ? undefined
- : 'NO'
- : 'YES'
-
- const canSell =
- isYourBets &&
- isCpmm &&
- (isBinary || isPseudoNumeric) &&
- !isClosed &&
- !resolution &&
- hasShares &&
- sharesOutcome &&
- user
-
- return (
-
-
-
-
- Invested
-
- {formatMoney(invested)}
-
-
- Profit
-
- {formatMoney(profit)}
-
-
- {canSell && (
- <>
-
- {showSellModal && (
-
- )}
- >
- )}
-
-
- {resolution ? (
-
- Payout
-
- {formatMoney(payout)}{' '}
-
-
-
- ) : isBinary ? (
- <>
-
-
- Payout if
-
-
- {formatMoney(yesWinnings)}
-
-
-
-
- Payout if
-
- {formatMoney(noWinnings)}
-
- >
- ) : (
-
-
- Expected value
-
- {formatMoney(payout)}
-
- )}
-
-
- )
-}
-
export function ContractBetsTable(props: {
contract: Contract
bets: Bet[]
@@ -750,30 +630,3 @@ function SellButton(props: {
)
}
-
-export function ProfitBadge(props: {
- profitPercent: number
- round?: boolean
- className?: string
-}) {
- const { profitPercent, round, className } = props
- if (!profitPercent) return null
- const colors =
- profitPercent > 0
- ? 'bg-green-100 text-green-800'
- : 'bg-red-100 text-red-800'
-
- return (
-
- {(profitPercent > 0 ? '+' : '') +
- profitPercent.toFixed(round ? 0 : 1) +
- '%'}
-
- )
-}
diff --git a/web/components/contract/contract-tabs.tsx b/web/components/contract/contract-tabs.tsx
index 17471796..bd3204ed 100644
--- a/web/components/contract/contract-tabs.tsx
+++ b/web/components/contract/contract-tabs.tsx
@@ -9,7 +9,7 @@ import { groupBy, sortBy } from 'lodash'
import { Bet } from 'common/bet'
import { Contract } from 'common/contract'
import { PAST_BETS } from 'common/user'
-import { ContractBetsTable, BetsSummary } from '../bets-list'
+import { ContractBetsTable } from '../bets-list'
import { Spacer } from '../layout/spacer'
import { Tabs } from '../layout/tabs'
import { Col } from '../layout/col'
@@ -17,59 +17,45 @@ import { LoadingIndicator } from 'web/components/loading-indicator'
import { useComments } from 'web/hooks/use-comments'
import { useLiquidity } from 'web/hooks/use-liquidity'
import { useTipTxns } from 'web/hooks/use-tip-txns'
-import { useUser } from 'web/hooks/use-user'
import { capitalize } from 'lodash'
import {
DEV_HOUSE_LIQUIDITY_PROVIDER_ID,
HOUSE_LIQUIDITY_PROVIDER_ID,
} from 'common/antes'
-import { useIsMobile } from 'web/hooks/use-is-mobile'
+import { buildArray } from 'common/util/array'
-export function ContractTabs(props: { contract: Contract; bets: Bet[] }) {
- const { contract, bets } = props
-
- const isMobile = useIsMobile()
- const user = useUser()
- const userBets =
- user && bets.filter((bet) => !bet.isAnte && bet.userId === user.id)
+export function ContractTabs(props: {
+ contract: Contract
+ bets: Bet[]
+ userBets: Bet[]
+}) {
+ const { contract, bets, userBets } = props
const yourTrades = (
-
-
+
)
+ const tabs = buildArray(
+ {
+ title: 'Comments',
+ content: ,
+ },
+ {
+ title: capitalize(PAST_BETS),
+ content: ,
+ },
+ userBets.length > 0 && {
+ title: 'Your trades',
+ content: yourTrades,
+ }
+ )
+
return (
- ,
- },
- {
- title: capitalize(PAST_BETS),
- content: ,
- },
- ...(!user || !userBets?.length
- ? []
- : [
- {
- title: isMobile ? `You` : `Your ${PAST_BETS}`,
- content: yourTrades,
- },
- ]),
- ]}
- />
+
)
}
diff --git a/web/components/profit-badge.tsx b/web/components/profit-badge.tsx
new file mode 100644
index 00000000..f82159e6
--- /dev/null
+++ b/web/components/profit-badge.tsx
@@ -0,0 +1,28 @@
+import clsx from 'clsx'
+
+export function ProfitBadge(props: {
+ profitPercent: number
+ round?: boolean
+ className?: string
+}) {
+ const { profitPercent, round, className } = props
+ if (!profitPercent) return null
+ const colors =
+ profitPercent > 0
+ ? 'bg-green-100 text-green-800'
+ : 'bg-red-100 text-red-800'
+
+ return (
+
+ {(profitPercent > 0 ? '+' : '') +
+ profitPercent.toFixed(round ? 0 : 1) +
+ '%'}
+
+ )
+}
diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx
index 38df2fbf..1dde2f95 100644
--- a/web/pages/[username]/[contractSlug].tsx
+++ b/web/pages/[username]/[contractSlug].tsx
@@ -1,5 +1,6 @@
import React, { memo, useEffect, useMemo, useState } from 'react'
import { ArrowLeftIcon } from '@heroicons/react/outline'
+import dayjs from 'dayjs'
import { useContractWithPreload } from 'web/hooks/use-contract'
import { ContractOverview } from 'web/components/contract/contract-overview'
@@ -44,8 +45,7 @@ import { useAdmin } from 'web/hooks/use-admin'
import { BetSignUpPrompt } from 'web/components/sign-up-prompt'
import { PlayMoneyDisclaimer } from 'web/components/play-money-disclaimer'
import BetButton from 'web/components/bet-button'
-
-import dayjs from 'dayjs'
+import { BetsSummary } from 'web/components/bet-summary'
export const getStaticProps = fromPropz(getStaticPropz)
export async function getStaticPropz(props: {
@@ -167,6 +167,10 @@ export function ContractPageContent(
[bets]
)
+ const userBets = user
+ ? bets.filter((bet) => !bet.isAnte && bet.userId === user.id)
+ : []
+
const [showConfetti, setShowConfetti] = useState(false)
useEffect(() => {
@@ -248,7 +252,14 @@ export function ContractPageContent(
>
)}
-
+
+
+
+
{!user ? (
diff --git a/web/pages/home/index.tsx b/web/pages/home/index.tsx
index b42b37bb..ba2851bf 100644
--- a/web/pages/home/index.tsx
+++ b/web/pages/home/index.tsx
@@ -33,7 +33,6 @@ import { groupPath, joinGroup, leaveGroup } from 'web/lib/firebase/groups'
import { usePortfolioHistory } from 'web/hooks/use-portfolio-history'
import { formatMoney } from 'common/util/format'
import { useProbChanges } from 'web/hooks/use-prob-changes'
-import { ProfitBadge } from 'web/components/bets-list'
import { calculatePortfolioProfit } from 'common/calculate-metrics'
import { hasCompletedStreakToday } from 'web/components/profile/betting-streak-modal'
import { ContractsGrid } from 'web/components/contract/contracts-grid'
@@ -45,6 +44,7 @@ import { usePrefetch } from 'web/hooks/use-prefetch'
import { Title } from 'web/components/title'
import { CPMMBinaryContract } from 'common/contract'
import { useContractsByDailyScoreGroups } from 'web/hooks/use-contracts'
+import { ProfitBadge } from 'web/components/profit-badge'
import { LoadingIndicator } from 'web/components/loading-indicator'
export default function Home() {