beautify accept bet screen
This commit is contained in:
parent
48435c91ad
commit
7acac0a5d6
|
@ -117,12 +117,12 @@ export function AcceptChallengeButton(props: {
|
||||||
|
|
||||||
{challenge.creatorId != user.id && (
|
{challenge.creatorId != user.id && (
|
||||||
<Button
|
<Button
|
||||||
color={'indigo'}
|
color="gradient"
|
||||||
size={'xl'}
|
size="2xl"
|
||||||
onClick={() => setOpen(true)}
|
onClick={() => setOpen(true)}
|
||||||
className={clsx('whitespace-nowrap')}
|
className={clsx('whitespace-nowrap')}
|
||||||
>
|
>
|
||||||
I accept this challenge
|
Accept bet
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import Confetti from 'react-confetti'
|
||||||
|
|
||||||
import { fromPropz, usePropz } from 'web/hooks/use-propz'
|
import { fromPropz, usePropz } from 'web/hooks/use-propz'
|
||||||
import {
|
import {
|
||||||
Contract,
|
Contract,
|
||||||
|
@ -10,28 +13,24 @@ import { Col } from 'web/components/layout/col'
|
||||||
import { SiteLink } from 'web/components/site-link'
|
import { SiteLink } from 'web/components/site-link'
|
||||||
import { Spacer } from 'web/components/layout/spacer'
|
import { Spacer } from 'web/components/layout/spacer'
|
||||||
import { Row } from 'web/components/layout/row'
|
import { Row } from 'web/components/layout/row'
|
||||||
|
|
||||||
import { Challenge } from 'common/challenge'
|
import { Challenge } from 'common/challenge'
|
||||||
import {
|
import {
|
||||||
getChallenge,
|
getChallenge,
|
||||||
getChallengeUrl,
|
getChallengeUrl,
|
||||||
useChallenge,
|
useChallenge,
|
||||||
} from 'web/lib/firebase/challenges'
|
} from 'web/lib/firebase/challenges'
|
||||||
import { getPortfolioHistory, getUserByUsername } from 'web/lib/firebase/users'
|
import { getUserByUsername } from 'web/lib/firebase/users'
|
||||||
import { PortfolioMetrics, User } from 'common/user'
|
import { User } from 'common/user'
|
||||||
import { Page } from 'web/components/page'
|
import { Page } from 'web/components/page'
|
||||||
import { useUser, useUserById } from 'web/hooks/use-user'
|
import { useUser, useUserById } from 'web/hooks/use-user'
|
||||||
import { AcceptChallengeButton } from 'web/components/challenges/accept-challenge-button'
|
import { AcceptChallengeButton } from 'web/components/challenges/accept-challenge-button'
|
||||||
import { Avatar } from 'web/components/avatar'
|
import { Avatar } from 'web/components/avatar'
|
||||||
import { UserLink } from 'web/components/user-page'
|
import { UserLink } from 'web/components/user-page'
|
||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
import { BinaryOutcomeLabel } from 'web/components/outcome-label'
|
import { BinaryOutcomeLabel } from 'web/components/outcome-label'
|
||||||
import { formatMoney } from 'common/util/format'
|
import { formatMoney } from 'common/util/format'
|
||||||
import { last } from 'lodash'
|
|
||||||
import { LoadingIndicator } from 'web/components/loading-indicator'
|
import { LoadingIndicator } from 'web/components/loading-indicator'
|
||||||
import { useWindowSize } from 'web/hooks/use-window-size'
|
import { useWindowSize } from 'web/hooks/use-window-size'
|
||||||
import { Bet, listAllBets } from 'web/lib/firebase/bets'
|
import { Bet, listAllBets } from 'web/lib/firebase/bets'
|
||||||
import Confetti from 'react-confetti'
|
|
||||||
import {
|
import {
|
||||||
BinaryResolutionOrChance,
|
BinaryResolutionOrChance,
|
||||||
PseudoNumericResolutionOrExpectation,
|
PseudoNumericResolutionOrExpectation,
|
||||||
|
@ -41,8 +40,11 @@ import { SEO } from 'web/components/SEO'
|
||||||
import { getOpenGraphProps } from 'web/components/contract/contract-card-preview'
|
import { getOpenGraphProps } from 'web/components/contract/contract-card-preview'
|
||||||
import Custom404 from 'web/pages/404'
|
import Custom404 from 'web/pages/404'
|
||||||
import { useSaveReferral } from 'web/hooks/use-save-referral'
|
import { useSaveReferral } from 'web/hooks/use-save-referral'
|
||||||
|
import { BinaryContract } from 'common/contract'
|
||||||
|
import { Title } from 'web/components/title'
|
||||||
|
|
||||||
export const getStaticProps = fromPropz(getStaticPropz)
|
export const getStaticProps = fromPropz(getStaticPropz)
|
||||||
|
|
||||||
export async function getStaticPropz(props: {
|
export async function getStaticPropz(props: {
|
||||||
params: { username: string; contractSlug: string; challengeSlug: string }
|
params: { username: string; contractSlug: string; challengeSlug: string }
|
||||||
}) {
|
}) {
|
||||||
|
@ -73,7 +75,7 @@ export async function getStaticPaths() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ChallengePage(props: {
|
export default function ChallengePage(props: {
|
||||||
contract: Contract | null
|
contract: BinaryContract | null
|
||||||
user: User
|
user: User
|
||||||
slug: string
|
slug: string
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
|
@ -88,18 +90,22 @@ export default function ChallengePage(props: {
|
||||||
challenge: null,
|
challenge: null,
|
||||||
slug: '',
|
slug: '',
|
||||||
}
|
}
|
||||||
const contract = useContractWithPreload(props.contract) ?? props.contract
|
const contract = (useContractWithPreload(props.contract) ??
|
||||||
|
props.contract) as BinaryContract
|
||||||
|
|
||||||
const challenge =
|
const challenge =
|
||||||
useChallenge(props.challengeSlug, contract?.id) ?? props.challenge
|
useChallenge(props.challengeSlug, contract?.id) ?? props.challenge
|
||||||
|
|
||||||
const { user, bets } = props
|
const { user, bets } = props
|
||||||
const currentUser = useUser()
|
const currentUser = useUser()
|
||||||
|
|
||||||
useSaveReferral(currentUser, {
|
useSaveReferral(currentUser, {
|
||||||
defaultReferrerUsername: challenge?.creatorUsername,
|
defaultReferrerUsername: challenge?.creatorUsername,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!contract || !challenge) return <Custom404 />
|
if (!contract || !challenge) return <Custom404 />
|
||||||
const ogCardProps = getOpenGraphProps(contract)
|
|
||||||
|
|
||||||
|
const ogCardProps = getOpenGraphProps(contract)
|
||||||
ogCardProps.creatorUsername = challenge.creatorUsername
|
ogCardProps.creatorUsername = challenge.creatorUsername
|
||||||
ogCardProps.creatorName = challenge.creatorName
|
ogCardProps.creatorName = challenge.creatorName
|
||||||
ogCardProps.creatorAvatarUrl = challenge.creatorAvatarUrl
|
ogCardProps.creatorAvatarUrl = challenge.creatorAvatarUrl
|
||||||
|
@ -152,7 +158,7 @@ const userRow = (challenger: User) => (
|
||||||
)
|
)
|
||||||
|
|
||||||
function ClosedChallengeContent(props: {
|
function ClosedChallengeContent(props: {
|
||||||
contract: Contract
|
contract: BinaryContract
|
||||||
challenge: Challenge
|
challenge: Challenge
|
||||||
creator: User
|
creator: User
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
|
@ -323,13 +329,13 @@ function ChallengeContract(props: { contract: Contract; bets: Bet[] }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function OpenChallengeContent(props: {
|
function OpenChallengeContent(props: {
|
||||||
contract: Contract
|
contract: BinaryContract
|
||||||
challenge: Challenge
|
challenge: Challenge
|
||||||
creator: User
|
creator: User
|
||||||
user: User | null | undefined
|
user: User | null | undefined
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
}) {
|
}) {
|
||||||
const { contract, challenge, creator, user, bets } = props
|
const { contract, challenge, creator, user } = props
|
||||||
const { question } = contract
|
const { question } = contract
|
||||||
const {
|
const {
|
||||||
creatorAmount,
|
creatorAmount,
|
||||||
|
@ -339,120 +345,44 @@ function OpenChallengeContent(props: {
|
||||||
yourOutcome,
|
yourOutcome,
|
||||||
} = challenge
|
} = challenge
|
||||||
|
|
||||||
const [creatorPortfolioHistory, setUsersCreatorPortfolioHistory] = useState<
|
|
||||||
PortfolioMetrics[]
|
|
||||||
>([])
|
|
||||||
const [portfolioHistory, setUsersPortfolioHistory] = useState<
|
|
||||||
PortfolioMetrics[]
|
|
||||||
>([])
|
|
||||||
useEffect(() => {
|
|
||||||
getPortfolioHistory(creator.id).then(setUsersCreatorPortfolioHistory)
|
|
||||||
if (user) getPortfolioHistory(user.id).then(setUsersPortfolioHistory)
|
|
||||||
}, [creator.id, user])
|
|
||||||
|
|
||||||
const href = `https://${DOMAIN}${contractPath(contract)}`
|
const href = `https://${DOMAIN}${contractPath(contract)}`
|
||||||
const { width, height } = useWindowSize()
|
|
||||||
const [containerRef, setContainerRef] = useState<HTMLDivElement | null>(null)
|
|
||||||
const bottomBarHeight = (width ?? 0) < 1024 ? 58 : 0
|
|
||||||
const remainingHeight =
|
|
||||||
(height ?? 0) - (containerRef?.offsetTop ?? 0) - bottomBarHeight
|
|
||||||
|
|
||||||
const isBinary = contract.outcomeType === 'BINARY'
|
|
||||||
const isPseudoNumeric = contract.outcomeType === 'PSEUDO_NUMERIC'
|
|
||||||
const yourCost =
|
const yourCost =
|
||||||
((1 - creatorOutcomeProb) / creatorOutcomeProb) * creatorAmount
|
((1 - creatorOutcomeProb) / creatorOutcomeProb) * creatorAmount
|
||||||
|
|
||||||
const userColumn = (
|
const title = `${creator.name} is challenging you to bet`
|
||||||
challenger: User | null | undefined,
|
|
||||||
portfolioHistory: PortfolioMetrics[],
|
|
||||||
outcome: string,
|
|
||||||
amount: number
|
|
||||||
) => {
|
|
||||||
const lastPortfolioMetrics = last(portfolioHistory)
|
|
||||||
const prob =
|
|
||||||
(outcome === creatorOutcome
|
|
||||||
? creatorOutcomeProb
|
|
||||||
: 1 - creatorOutcomeProb) * 100
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Col className="w-full items-start justify-center gap-1">
|
|
||||||
{challenger ? (
|
|
||||||
userRow(challenger)
|
|
||||||
) : (
|
|
||||||
<Row className={'mb-2 w-full items-center justify-center gap-2'}>
|
|
||||||
<Avatar size={12} avatarUrl={undefined} username={undefined} />
|
|
||||||
<span className={'text-2xl'}>Your name here</span>
|
|
||||||
</Row>
|
|
||||||
)}
|
|
||||||
<Row className={'w-full items-center justify-center'}>
|
|
||||||
<span className={'text-lg'}>
|
|
||||||
is betting {formatMoney(amount)}
|
|
||||||
{' on '}
|
|
||||||
<BinaryOutcomeLabel outcome={outcome as any} /> at{' '}
|
|
||||||
{Math.round(prob)}%
|
|
||||||
</span>
|
|
||||||
</Row>
|
|
||||||
{/*// It could be fun to show each user's portfolio history here*/}
|
|
||||||
{/*// Also show how many challenges they've won*/}
|
|
||||||
{/*<Row className={'mt-4 hidden w-full items-center sm:block'}>*/}
|
|
||||||
{/* <PortfolioValueSection*/}
|
|
||||||
{/* disableSelector={true}*/}
|
|
||||||
{/* portfolioHistory={portfolioHistory}*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/*</Row>*/}
|
|
||||||
<Row className={'w-full'}>
|
|
||||||
<Col className={'w-full items-center justify-center'}>
|
|
||||||
<div className="text-sm text-gray-500">Portfolio value</div>
|
|
||||||
|
|
||||||
{challenger
|
|
||||||
? formatMoney(
|
|
||||||
(lastPortfolioMetrics?.balance ?? 0) +
|
|
||||||
(lastPortfolioMetrics?.investmentValue ?? 0)
|
|
||||||
)
|
|
||||||
: 'xxxx'}
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Col>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Col className="items-center">
|
||||||
<Col
|
<Col className="h-full rounded bg-white p-4 py-8 sm:p-8 sm:shadow-md">
|
||||||
ref={setContainerRef}
|
<Title className="!mt-0" text={`⚔️ ${title} ⚔️`} />
|
||||||
style={{ height: remainingHeight }}
|
|
||||||
className=" relative w-full justify-between rounded border-0 border-gray-100 bg-white py-6 pl-1 pr-2 sm:px-2 md:px-6 md:py-8"
|
<Row className="my-4 justify-center px-8 pb-4 text-lg sm:text-xl">
|
||||||
>
|
|
||||||
{(isBinary || isPseudoNumeric) && (
|
|
||||||
<div
|
|
||||||
className={`absolute top-52 flex h-[${
|
|
||||||
remainingHeight / 2
|
|
||||||
}] w-full flex-row opacity-40`}
|
|
||||||
>
|
|
||||||
<ContractProbGraph contract={contract} bets={bets} height={400} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<Row className="px-3 pb-4 text-xl text-indigo-700 md:text-2xl">
|
|
||||||
<SiteLink href={href}>{question}</SiteLink>
|
<SiteLink href={href}>{question}</SiteLink>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Col
|
<Col
|
||||||
className={
|
className={
|
||||||
'h-full max-h-[50vh] w-full content-between justify-between gap-1 py-10 sm:flex-row'
|
'h-full max-h-[50vh] w-full content-between justify-between gap-1 sm:flex-row'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{userColumn(
|
<UserBetColumn
|
||||||
creator,
|
challenger={creator}
|
||||||
creatorPortfolioHistory,
|
outcome={creatorOutcome}
|
||||||
creatorOutcome,
|
amount={creatorAmount}
|
||||||
creatorAmount
|
/>
|
||||||
)}
|
|
||||||
<Col className="items-center justify-center py-4 text-4xl">VS</Col>
|
<Col className="items-center justify-center py-8 text-2xl sm:text-4xl">
|
||||||
{userColumn(
|
VS
|
||||||
user?.id === creatorId ? undefined : user,
|
</Col>
|
||||||
portfolioHistory,
|
|
||||||
yourOutcome,
|
<UserBetColumn
|
||||||
yourCost
|
challenger={user?.id === creatorId ? undefined : user}
|
||||||
)}
|
outcome={yourOutcome}
|
||||||
|
amount={yourCost}
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Spacer h={3} />
|
<Spacer h={3} />
|
||||||
|
|
||||||
<Row className="my-4 w-full items-center justify-center">
|
<Row className="my-4 w-full items-center justify-center">
|
||||||
|
@ -463,6 +393,39 @@ function OpenChallengeContent(props: {
|
||||||
/>
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
</>
|
</Col>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function UserBetColumn(props: {
|
||||||
|
challenger: User | null | undefined
|
||||||
|
outcome: string
|
||||||
|
amount: number
|
||||||
|
}) {
|
||||||
|
const { challenger, outcome, amount } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Col className="w-full items-start justify-center gap-1">
|
||||||
|
{challenger ? (
|
||||||
|
userRow(challenger)
|
||||||
|
) : (
|
||||||
|
<Row className={'mb-2 w-full items-center justify-center gap-2'}>
|
||||||
|
<Avatar size={12} avatarUrl={undefined} username={undefined} />
|
||||||
|
<span className={'text-2xl'}>You</span>
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
<Row className={'w-full items-center justify-center'}>
|
||||||
|
<span className={'text-lg'}>{challenger ? 'is' : 'are'} betting </span>
|
||||||
|
</Row>
|
||||||
|
<Row className={'w-full items-center justify-center'}>
|
||||||
|
<span className={'text-lg'}>
|
||||||
|
<span className="bold text-2xl">{formatMoney(amount)}</span>
|
||||||
|
{' on '}
|
||||||
|
<span className="bold text-2xl">
|
||||||
|
<BinaryOutcomeLabel outcome={outcome as any} />
|
||||||
|
</span>{' '}
|
||||||
|
</span>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user