diff --git a/common/redeem.ts b/common/redeem.ts index e0839ff8..f786a1c2 100644 --- a/common/redeem.ts +++ b/common/redeem.ts @@ -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 diff --git a/docs/docs/api.md b/docs/docs/api.md index e284abdf..64e26de8 100644 --- a/docs/docs/api.md +++ b/docs/docs/api.md @@ -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. +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. +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. +Requires no authorization. +Note: group is singular in the URL. + ### `GET /v0/markets` diff --git a/web/components/amount-input.tsx b/web/components/amount-input.tsx index 9eff26ef..2ad745a8 100644 --- a/web/components/amount-input.tsx +++ b/web/components/amount-input.tsx @@ -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 ( <> 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" /> )} diff --git a/web/components/answers/answer-bet-panel.tsx b/web/components/answers/answer-bet-panel.tsx index 6e54b3b8..f84ff1a3 100644 --- a/web/components/answers/answer-bet-panel.tsx +++ b/web/components/answers/answer-bet-panel.tsx @@ -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 ( @@ -148,21 +157,6 @@ export function AnswerBetPanel(props: { showSliderOnMobile /> - {(betAmount ?? 0) > 10 && - bankrollFraction >= 0.5 && - bankrollFraction <= 1 ? ( - - ) : ( - '' - )} -
Probability
@@ -198,16 +192,17 @@ export function AnswerBetPanel(props: { {user ? ( - + /> ) : ( )} diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index a59d56f2..2dca328a 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -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,17 +185,13 @@ 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) - focusAmountInput() + + if (!isIOS() && !isAndroid()) { + focusAmountInput() + } } function onBetChange(newAmount: number | undefined) { @@ -274,25 +271,15 @@ function BuyPanel(props: { const bankrollFraction = (betAmount ?? 0) / (user?.balance ?? 1e9) const warning = - (betAmount ?? 0) > 10 && - bankrollFraction >= 0.5 && - bankrollFraction <= 1 ? ( - 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 ? ( - - ) : ( - <> - ) + )}` + : (betAmount ?? 0) > 10 && probChange >= 0.3 && bankrollFraction <= 1 + ? `Are you sure you want to move the market by ${displayedDifference}?` + : undefined return ( @@ -325,8 +312,6 @@ function BuyPanel(props: { showSliderOnMobile /> - {warning} -
@@ -367,20 +352,20 @@ function BuyPanel(props: { {user && ( - + /> )} {wasSubmitted &&
Trade submitted!
} diff --git a/web/components/confirmation-button.tsx b/web/components/confirmation-button.tsx index bc014902..8dbe90c2 100644 --- a/web/components/confirmation-button.tsx +++ b/web/components/confirmation-button.tsx @@ -47,13 +47,13 @@ export function ConfirmationButton(props: { {children}
updateOpen(false)} > {cancelBtn?.label ?? 'Cancel'}
@@ -69,7 +69,7 @@ export function ConfirmationButton(props: {
updateOpen(true)} > {openModalBtn.icon} diff --git a/web/components/contract/contract-tabs.tsx b/web/components/contract/contract-tabs.tsx index 40fa9da0..d63d3963 100644 --- a/web/components/contract/contract-tabs.tsx +++ b/web/components/contract/contract-tabs.tsx @@ -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 && ( void + disabled?: boolean + isSubmitting: boolean + openModalButtonClass?: string + submitButtonClassName?: string +}) { + const { + onSubmit, + warning, + disabled, + isSubmitting, + openModalButtonClass, + submitButtonClassName, + } = props + + if (!warning) { + return ( + + ) + } + + return ( + + + + +

{warning}

+
+ ) +} diff --git a/web/lib/util/device.ts b/web/lib/util/device.ts index 20eabf75..8c54b731 100644 --- a/web/lib/util/device.ts +++ b/web/lib/util/device.ts @@ -12,3 +12,7 @@ export function isIOS() { (navigator.userAgent.includes('Mac') && 'ontouchend' in document) ) } + +export function isAndroid() { + return navigator.userAgent.includes('Android') +} diff --git a/web/pages/tournaments/index.tsx b/web/pages/tournaments/index.tsx index b308ee7f..1494786b 100644 --- a/web/pages/tournaments/index.tsx +++ b/web/pages/tournaments/index.tsx @@ -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" /> - + {sections.map(({ tourney, slug, numPeople }) => (