Merge branch 'manifoldmarkets:main' into main
This commit is contained in:
commit
6e77b4a987
|
@ -13,7 +13,10 @@ export const getRedeemableAmount = (bets: RedeemableBet[]) => {
|
|||
const yesShares = sumBy(yesBets, (b) => b.shares)
|
||||
const noShares = sumBy(noBets, (b) => b.shares)
|
||||
const shares = Math.max(Math.min(yesShares, noShares), 0)
|
||||
const soldFrac = shares > 0 ? Math.min(yesShares, noShares) / shares : 0
|
||||
const soldFrac =
|
||||
shares > 0
|
||||
? Math.min(yesShares, noShares) / Math.max(yesShares, noShares)
|
||||
: 0
|
||||
const loanAmount = sumBy(bets, (bet) => bet.loanAmount ?? 0)
|
||||
const loanPayment = loanAmount * soldFrac
|
||||
const netAmount = shares - loanPayment
|
||||
|
|
|
@ -60,23 +60,27 @@ Parameters:
|
|||
|
||||
Requires no authorization.
|
||||
|
||||
### `GET /v0/groups/[slug]`
|
||||
### `GET /v0/group/[slug]`
|
||||
|
||||
Gets a group by its slug.
|
||||
|
||||
Requires no authorization.
|
||||
Note: group is singular in the URL.
|
||||
|
||||
### `GET /v0/group/by-id/[id]`
|
||||
|
||||
Gets a group by its unique ID.
|
||||
|
||||
Requires no authorization.
|
||||
Note: group is singular in the URL.
|
||||
|
||||
### `GET /v0/group/by-id/[id]/markets`
|
||||
|
||||
Gets a group's markets by its unique ID.
|
||||
|
||||
Requires no authorization.
|
||||
Note: group is singular in the URL.
|
||||
|
||||
|
||||
### `GET /v0/markets`
|
||||
|
||||
|
|
|
@ -122,6 +122,18 @@ export function BuyAmountInput(props: {
|
|||
}
|
||||
}
|
||||
|
||||
const parseRaw = (x: number) => {
|
||||
if (x <= 100) return x
|
||||
if (x <= 130) return 100 + (x - 100) * 5
|
||||
return 250 + (x - 130) * 10
|
||||
}
|
||||
|
||||
const getRaw = (x: number) => {
|
||||
if (x <= 100) return x
|
||||
if (x <= 250) return 100 + (x - 100) / 5
|
||||
return 130 + (x - 250) / 10
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AmountInput
|
||||
|
@ -138,10 +150,10 @@ export function BuyAmountInput(props: {
|
|||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="200"
|
||||
value={amount ?? 0}
|
||||
onChange={(e) => onAmountChange(parseInt(e.target.value))}
|
||||
className="range range-lg z-40 mb-2 xl:hidden"
|
||||
max="205"
|
||||
value={getRaw(amount ?? 0)}
|
||||
onChange={(e) => onAmountChange(parseRaw(parseInt(e.target.value)))}
|
||||
className="range range-lg only-thumb z-40 mb-2 xl:hidden"
|
||||
step="5"
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -26,7 +26,7 @@ import { Bet } from 'common/bet'
|
|||
import { track } from 'web/lib/service/analytics'
|
||||
import { BetSignUpPrompt } from '../sign-up-prompt'
|
||||
import { isIOS } from 'web/lib/util/device'
|
||||
import { AlertBox } from '../alert-box'
|
||||
import { WarningConfirmationButton } from '../warning-confirmation-button'
|
||||
|
||||
export function AnswerBetPanel(props: {
|
||||
answer: Answer
|
||||
|
@ -116,6 +116,15 @@ export function AnswerBetPanel(props: {
|
|||
|
||||
const bankrollFraction = (betAmount ?? 0) / (user?.balance ?? 1e9)
|
||||
|
||||
const warning =
|
||||
(betAmount ?? 0) > 10 && bankrollFraction >= 0.5 && bankrollFraction <= 1
|
||||
? `You might not want to spend ${formatPercent(
|
||||
bankrollFraction
|
||||
)} of your balance on a single bet. \n\nCurrent balance: ${formatMoney(
|
||||
user?.balance ?? 0
|
||||
)}`
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<Col className={clsx('px-2 pb-2 pt-4 sm:pt-0', className)}>
|
||||
<Row className="items-center justify-between self-stretch">
|
||||
|
@ -148,21 +157,6 @@ export function AnswerBetPanel(props: {
|
|||
showSliderOnMobile
|
||||
/>
|
||||
|
||||
{(betAmount ?? 0) > 10 &&
|
||||
bankrollFraction >= 0.5 &&
|
||||
bankrollFraction <= 1 ? (
|
||||
<AlertBox
|
||||
title="Whoa, there!"
|
||||
text={`You might not want to spend ${formatPercent(
|
||||
bankrollFraction
|
||||
)} of your balance on a single bet. \n\nCurrent balance: ${formatMoney(
|
||||
user?.balance ?? 0
|
||||
)}`}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
<Col className="mt-3 w-full gap-3">
|
||||
<Row className="items-center justify-between text-sm">
|
||||
<div className="text-gray-500">Probability</div>
|
||||
|
@ -198,16 +192,17 @@ export function AnswerBetPanel(props: {
|
|||
<Spacer h={6} />
|
||||
|
||||
{user ? (
|
||||
<button
|
||||
className={clsx(
|
||||
<WarningConfirmationButton
|
||||
warning={warning}
|
||||
onSubmit={submitBet}
|
||||
isSubmitting={isSubmitting}
|
||||
disabled={!!betDisabled}
|
||||
openModalButtonClass={clsx(
|
||||
'btn self-stretch',
|
||||
betDisabled ? 'btn-disabled' : 'btn-primary',
|
||||
isSubmitting ? 'loading' : ''
|
||||
)}
|
||||
onClick={betDisabled ? undefined : submitBet}
|
||||
>
|
||||
{isSubmitting ? 'Submitting...' : 'Submit'}
|
||||
</button>
|
||||
/>
|
||||
) : (
|
||||
<BetSignUpPrompt />
|
||||
)}
|
||||
|
|
|
@ -40,7 +40,8 @@ import { LimitBets } from './limit-bets'
|
|||
import { PillButton } from './buttons/pill-button'
|
||||
import { YesNoSelector } from './yes-no-selector'
|
||||
import { PlayMoneyDisclaimer } from './play-money-disclaimer'
|
||||
import { AlertBox } from './alert-box'
|
||||
import { isAndroid, isIOS } from 'web/lib/util/device'
|
||||
import { WarningConfirmationButton } from './warning-confirmation-button'
|
||||
|
||||
export function BetPanel(props: {
|
||||
contract: CPMMBinaryContract | PseudoNumericContract
|
||||
|
@ -184,18 +185,14 @@ function BuyPanel(props: {
|
|||
|
||||
const [inputRef, focusAmountInput] = useFocus()
|
||||
|
||||
// useEffect(() => {
|
||||
// if (selected) {
|
||||
// if (isIOS()) window.scrollTo(0, window.scrollY + 200)
|
||||
// focusAmountInput()
|
||||
// }
|
||||
// }, [selected, focusAmountInput])
|
||||
|
||||
function onBetChoice(choice: 'YES' | 'NO') {
|
||||
setOutcome(choice)
|
||||
setWasSubmitted(false)
|
||||
|
||||
if (!isIOS() && !isAndroid()) {
|
||||
focusAmountInput()
|
||||
}
|
||||
}
|
||||
|
||||
function onBetChange(newAmount: number | undefined) {
|
||||
setWasSubmitted(false)
|
||||
|
@ -274,25 +271,15 @@ function BuyPanel(props: {
|
|||
const bankrollFraction = (betAmount ?? 0) / (user?.balance ?? 1e9)
|
||||
|
||||
const warning =
|
||||
(betAmount ?? 0) > 10 &&
|
||||
bankrollFraction >= 0.5 &&
|
||||
bankrollFraction <= 1 ? (
|
||||
<AlertBox
|
||||
title="Whoa, there!"
|
||||
text={`You might not want to spend ${formatPercent(
|
||||
(betAmount ?? 0) > 10 && bankrollFraction >= 0.5 && bankrollFraction <= 1
|
||||
? `You might not want to spend ${formatPercent(
|
||||
bankrollFraction
|
||||
)} of your balance on a single trade. \n\nCurrent balance: ${formatMoney(
|
||||
user?.balance ?? 0
|
||||
)}`}
|
||||
/>
|
||||
) : (betAmount ?? 0) > 10 && probChange >= 0.3 && bankrollFraction <= 1 ? (
|
||||
<AlertBox
|
||||
title="Whoa, there!"
|
||||
text={`Are you sure you want to move the market by ${displayedDifference}?`}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
)}`
|
||||
: (betAmount ?? 0) > 10 && probChange >= 0.3 && bankrollFraction <= 1
|
||||
? `Are you sure you want to move the market by ${displayedDifference}?`
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<Col className={hidden ? 'hidden' : ''}>
|
||||
|
@ -325,8 +312,6 @@ function BuyPanel(props: {
|
|||
showSliderOnMobile
|
||||
/>
|
||||
|
||||
{warning}
|
||||
|
||||
<Col className="mt-3 w-full gap-3">
|
||||
<Row className="items-center justify-between text-sm">
|
||||
<div className="text-gray-500">
|
||||
|
@ -367,20 +352,20 @@ function BuyPanel(props: {
|
|||
<Spacer h={8} />
|
||||
|
||||
{user && (
|
||||
<button
|
||||
className={clsx(
|
||||
<WarningConfirmationButton
|
||||
warning={warning}
|
||||
onSubmit={submitBet}
|
||||
isSubmitting={isSubmitting}
|
||||
disabled={!!betDisabled}
|
||||
openModalButtonClass={clsx(
|
||||
'btn mb-2 flex-1',
|
||||
betDisabled
|
||||
? 'btn-disabled'
|
||||
: outcome === 'YES'
|
||||
? 'btn-primary'
|
||||
: 'border-none bg-red-400 hover:bg-red-500',
|
||||
isSubmitting ? 'loading' : ''
|
||||
: 'border-none bg-red-400 hover:bg-red-500'
|
||||
)}
|
||||
onClick={betDisabled ? undefined : submitBet}
|
||||
>
|
||||
{isSubmitting ? 'Submitting...' : 'Submit'}
|
||||
</button>
|
||||
/>
|
||||
)}
|
||||
|
||||
{wasSubmitted && <div className="mt-4">Trade submitted!</div>}
|
||||
|
|
|
@ -47,13 +47,13 @@ export function ConfirmationButton(props: {
|
|||
{children}
|
||||
<Row className="gap-4">
|
||||
<div
|
||||
className={clsx('btn normal-case', cancelBtn?.className)}
|
||||
className={clsx('btn', cancelBtn?.className)}
|
||||
onClick={() => updateOpen(false)}
|
||||
>
|
||||
{cancelBtn?.label ?? 'Cancel'}
|
||||
</div>
|
||||
<div
|
||||
className={clsx('btn normal-case', submitBtn?.className)}
|
||||
className={clsx('btn', submitBtn?.className)}
|
||||
onClick={
|
||||
onSubmitWithSuccess
|
||||
? () =>
|
||||
|
@ -69,7 +69,7 @@ export function ConfirmationButton(props: {
|
|||
</Col>
|
||||
</Modal>
|
||||
<div
|
||||
className={clsx('btn normal-case', openModalBtn.className)}
|
||||
className={clsx('btn', openModalBtn.className)}
|
||||
onClick={() => updateOpen(true)}
|
||||
>
|
||||
{openModalBtn.icon}
|
||||
|
|
|
@ -13,7 +13,6 @@ import { Tabs } from '../layout/tabs'
|
|||
import { Col } from '../layout/col'
|
||||
import { tradingAllowed } from 'web/lib/firebase/contracts'
|
||||
import { CommentTipMap } from 'web/hooks/use-tip-txns'
|
||||
import { useBets } from 'web/hooks/use-bets'
|
||||
import { useComments } from 'web/hooks/use-comments'
|
||||
import { useLiquidity } from 'web/hooks/use-liquidity'
|
||||
import { BetSignUpPrompt } from '../sign-up-prompt'
|
||||
|
@ -27,24 +26,23 @@ export function ContractTabs(props: {
|
|||
comments: ContractComment[]
|
||||
tips: CommentTipMap
|
||||
}) {
|
||||
const { contract, user, tips } = props
|
||||
const { contract, user, bets, tips } = props
|
||||
const { outcomeType } = contract
|
||||
|
||||
const bets = useBets(contract.id) ?? props.bets
|
||||
const lps = useLiquidity(contract.id) ?? []
|
||||
const lps = useLiquidity(contract.id)
|
||||
|
||||
const userBets =
|
||||
user && bets.filter((bet) => !bet.isAnte && bet.userId === user.id)
|
||||
const visibleBets = bets.filter(
|
||||
(bet) => !bet.isAnte && !bet.isRedemption && bet.amount !== 0
|
||||
)
|
||||
const visibleLps = lps.filter((l) => !l.isAnte && l.amount > 0)
|
||||
const visibleLps = lps?.filter((l) => !l.isAnte && l.amount > 0)
|
||||
|
||||
// Load comments here, so the badge count will be correct
|
||||
const updatedComments = useComments(contract.id)
|
||||
const comments = updatedComments ?? props.comments
|
||||
|
||||
const betActivity = (
|
||||
const betActivity = visibleLps && (
|
||||
<ContractBetsActivity
|
||||
contract={contract}
|
||||
bets={visibleBets}
|
||||
|
|
74
web/components/warning-confirmation-button.tsx
Normal file
74
web/components/warning-confirmation-button.tsx
Normal file
|
@ -0,0 +1,74 @@
|
|||
import clsx from 'clsx'
|
||||
import React from 'react'
|
||||
|
||||
import { Row } from './layout/row'
|
||||
import { ConfirmationButton } from './confirmation-button'
|
||||
import { ExclamationIcon } from '@heroicons/react/solid'
|
||||
|
||||
export function WarningConfirmationButton(props: {
|
||||
warning?: string
|
||||
onSubmit: () => void
|
||||
disabled?: boolean
|
||||
isSubmitting: boolean
|
||||
openModalButtonClass?: string
|
||||
submitButtonClassName?: string
|
||||
}) {
|
||||
const {
|
||||
onSubmit,
|
||||
warning,
|
||||
disabled,
|
||||
isSubmitting,
|
||||
openModalButtonClass,
|
||||
submitButtonClassName,
|
||||
} = props
|
||||
|
||||
if (!warning) {
|
||||
return (
|
||||
<button
|
||||
className={clsx(
|
||||
openModalButtonClass,
|
||||
isSubmitting ? 'loading' : '',
|
||||
disabled && 'btn-disabled'
|
||||
)}
|
||||
onClick={onSubmit}
|
||||
disabled={disabled}
|
||||
>
|
||||
{isSubmitting ? 'Submitting...' : 'Submit'}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<ConfirmationButton
|
||||
openModalBtn={{
|
||||
className: clsx(
|
||||
openModalButtonClass,
|
||||
isSubmitting && 'btn-disabled loading'
|
||||
),
|
||||
label: 'Submit',
|
||||
}}
|
||||
cancelBtn={{
|
||||
label: 'Cancel',
|
||||
className: 'btn-warning',
|
||||
}}
|
||||
submitBtn={{
|
||||
label: 'Submit',
|
||||
className: clsx(
|
||||
'border-none btn-sm btn-ghost self-center',
|
||||
submitButtonClassName
|
||||
),
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<Row className="items-center text-xl">
|
||||
<ExclamationIcon
|
||||
className="h-16 w-16 text-yellow-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Whoa, there!
|
||||
</Row>
|
||||
|
||||
<p>{warning}</p>
|
||||
</ConfirmationButton>
|
||||
)
|
||||
}
|
|
@ -12,3 +12,7 @@ export function isIOS() {
|
|||
(navigator.userAgent.includes('Mac') && 'ontouchend' in document)
|
||||
)
|
||||
}
|
||||
|
||||
export function isAndroid() {
|
||||
return navigator.userAgent.includes('Android')
|
||||
}
|
||||
|
|
|
@ -77,13 +77,21 @@ const Salem = {
|
|||
|
||||
const tourneys: Tourney[] = [
|
||||
{
|
||||
title: 'Cause Exploration Prizes',
|
||||
title: 'Manifold F2P Tournament',
|
||||
blurb:
|
||||
'Which new charity ideas will Open Philanthropy find most promising?',
|
||||
award: 'M$100k',
|
||||
endTime: toDate('Sep 9, 2022'),
|
||||
groupId: 'cMcpBQ2p452jEcJD2SFw',
|
||||
'Who can amass the most mana starting from a free-to-play (F2P) account?',
|
||||
award: 'Poem',
|
||||
endTime: toDate('Sep 15, 2022'),
|
||||
groupId: '6rrIja7tVW00lUVwtsYS',
|
||||
},
|
||||
// {
|
||||
// title: 'Cause Exploration Prizes',
|
||||
// blurb:
|
||||
// 'Which new charity ideas will Open Philanthropy find most promising?',
|
||||
// award: 'M$100k',
|
||||
// endTime: toDate('Sep 9, 2022'),
|
||||
// groupId: 'cMcpBQ2p452jEcJD2SFw',
|
||||
// },
|
||||
{
|
||||
title: 'Fantasy Football Stock Exchange',
|
||||
blurb: 'How many points will each NFL player score this season?',
|
||||
|
@ -135,7 +143,7 @@ export default function TournamentPage(props: { sections: SectionInfo[] }) {
|
|||
title="Tournaments"
|
||||
description="Win money by betting in forecasting touraments on current events, sports, science, and more"
|
||||
/>
|
||||
<Col className="mx-4 mt-4 gap-10 sm:mx-10 xl:w-[125%]">
|
||||
<Col className="m-4 gap-10 sm:mx-10 sm:gap-24 xl:w-[125%]">
|
||||
{sections.map(({ tourney, slug, numPeople }) => (
|
||||
<div key={slug}>
|
||||
<SectionHeader
|
||||
|
|
|
@ -60,6 +60,18 @@ module.exports = {
|
|||
'overflow-wrap': 'anywhere',
|
||||
'word-break': 'break-word', // for Safari
|
||||
},
|
||||
'.only-thumb': {
|
||||
'pointer-events': 'none',
|
||||
'&::-webkit-slider-thumb': {
|
||||
'pointer-events': 'auto !important',
|
||||
},
|
||||
'&::-moz-range-thumb': {
|
||||
'pointer-events': 'auto !important',
|
||||
},
|
||||
'&::-ms-thumb': {
|
||||
'pointer-events': 'auto !important',
|
||||
},
|
||||
},
|
||||
})
|
||||
}),
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue
Block a user