From e17a59ae233fa3b14d4b3396bc6483f4110452ed Mon Sep 17 00:00:00 2001
From: ingawei <46611122+ingawei@users.noreply.github.com>
Date: Mon, 26 Sep 2022 19:28:54 -0500
Subject: [PATCH] Inga/mobilebetting (#911)
* mobile binary betting
---
web/components/amount-input.tsx | 129 +++++----
web/components/answers/answer-bet-panel.tsx | 2 +-
web/components/bet-button.tsx | 53 +++-
web/components/bet-panel.tsx | 251 +++++++++++-------
web/components/contract/contract-overview.tsx | 18 +-
web/components/contract/quick-bet.tsx | 4 +-
web/components/outcome-label.tsx | 2 +-
.../warning-confirmation-button.tsx | 16 +-
web/components/yes-no-selector.tsx | 14 +-
web/tailwind.config.js | 1 +
10 files changed, 305 insertions(+), 185 deletions(-)
diff --git a/web/components/amount-input.tsx b/web/components/amount-input.tsx
index 76581d9e..fbb49677 100644
--- a/web/components/amount-input.tsx
+++ b/web/components/amount-input.tsx
@@ -5,7 +5,8 @@ import { formatMoney } from 'common/util/format'
import { Col } from './layout/col'
import { SiteLink } from './site-link'
import { ENV_CONFIG } from 'common/envs/constants'
-import { useIsMobile } from 'web/hooks/use-is-mobile'
+import { useWindowSize } from 'web/hooks/use-window-size'
+import { Row } from './layout/row'
export function AmountInput(props: {
amount: number | undefined
@@ -34,45 +35,53 @@ export function AmountInput(props: {
const isInvalid = !str || isNaN(amount)
onChange(isInvalid ? undefined : amount)
}
- const isMobile = useIsMobile(768)
- return (
-
-
- {error && (
-
- {error === 'Insufficient balance' ? (
- <>
- Not enough funds.
-
- Buy more?
-
- >
- ) : (
- error
- )}
-
- )}
-
+ const { width } = useWindowSize()
+ const isMobile = (width ?? 0) < 768
+
+ return (
+ <>
+
+
+
+ {error && (
+
+ {error === 'Insufficient balance' ? (
+ <>
+ Not enough funds.
+
+ Buy more?
+
+ >
+ ) : (
+ error
+ )}
+
+ )}
+
+ >
)
}
@@ -135,27 +144,29 @@ export function BuyAmountInput(props: {
return (
<>
-
- {showSlider && (
- onAmountChange(parseRaw(parseInt(e.target.value)))}
- className="range range-lg only-thumb z-40 mb-2 xl:hidden"
- step="5"
+
+
- )}
+ {showSlider && (
+ onAmountChange(parseRaw(parseInt(e.target.value)))}
+ className="range range-lg only-thumb z-40 my-auto align-middle xl:hidden"
+ step="5"
+ />
+ )}
+
>
)
}
diff --git a/web/components/answers/answer-bet-panel.tsx b/web/components/answers/answer-bet-panel.tsx
index 3339ded5..ac3a8fa3 100644
--- a/web/components/answers/answer-bet-panel.tsx
+++ b/web/components/answers/answer-bet-panel.tsx
@@ -182,9 +182,9 @@ export function AnswerBetPanel(props: {
-
{user ? (
setOpen(false)}
hasShares={hasYesShares || hasNoShares}
/>
@@ -72,3 +78,44 @@ export default function BetButton(props: {
>
)
}
+
+export function BinaryMobileBetting(props: { contract: BinaryContract }) {
+ const { contract } = props
+ const user = useUser()
+ if (user) {
+ return
+ } else {
+ return
+ }
+}
+
+export function SignedInBinaryMobileBetting(props: {
+ contract: BinaryContract
+ user: User
+}) {
+ const { contract, user } = props
+ const unfilledBets = useUnfilledBets(contract.id) ?? []
+
+ return (
+ <>
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx
index 00db5cb4..33f8e643 100644
--- a/web/components/bet-panel.tsx
+++ b/web/components/bet-panel.tsx
@@ -43,6 +43,11 @@ import { PlayMoneyDisclaimer } from './play-money-disclaimer'
import { isAndroid, isIOS } from 'web/lib/util/device'
import { WarningConfirmationButton } from './warning-confirmation-button'
import { MarketIntroPanel } from './market-intro-panel'
+import { Modal } from './layout/modal'
+import { Title } from './title'
+import toast from 'react-hot-toast'
+import { CheckIcon } from '@heroicons/react/solid'
+import { useWindowSize } from 'web/hooks/use-window-size'
export function BetPanel(props: {
contract: CPMMBinaryContract | PseudoNumericContract
@@ -105,11 +110,10 @@ export function BetPanel(props: {
export function SimpleBetPanel(props: {
contract: CPMMBinaryContract | PseudoNumericContract
className?: string
- selected?: 'YES' | 'NO'
hasShares?: boolean
onBetSuccess?: () => void
}) {
- const { contract, className, selected, hasShares, onBetSuccess } = props
+ const { contract, className, hasShares, onBetSuccess } = props
const user = useUser()
const [isLimitOrder, setIsLimitOrder] = useState(false)
@@ -139,7 +143,6 @@ export function SimpleBetPanel(props: {
contract={contract}
user={user}
unfilledBets={unfilledBets}
- selected={selected}
onBuySuccess={onBetSuccess}
/>
void
+ mobileView?: boolean
}) {
- const { contract, user, unfilledBets, hidden, selected, onBuySuccess } = props
+ const { contract, user, unfilledBets, hidden, onBuySuccess, mobileView } =
+ props
const initialProb = getProbability(contract)
const isPseudoNumeric = contract.outcomeType === 'PSEUDO_NUMERIC'
- const [outcome, setOutcome] = useState<'YES' | 'NO' | undefined>(selected)
- const [betAmount, setBetAmount] = useState(undefined)
+ const windowSize = useWindowSize()
+ const initialOutcome =
+ windowSize.width && windowSize.width >= 1280 ? 'YES' : undefined
+ const [outcome, setOutcome] = useState<'YES' | 'NO' | undefined>(
+ initialOutcome
+ )
+ const [betAmount, setBetAmount] = useState(10)
const [error, setError] = useState()
const [isSubmitting, setIsSubmitting] = useState(false)
- const [wasSubmitted, setWasSubmitted] = useState(false)
const [inputRef, focusAmountInput] = useFocus()
function onBetChoice(choice: 'YES' | 'NO') {
setOutcome(choice)
- setWasSubmitted(false)
if (!isIOS() && !isAndroid()) {
focusAmountInput()
}
}
+ function mobileOnBetChoice(choice: 'YES' | 'NO' | undefined) {
+ if (outcome === choice) {
+ setOutcome(undefined)
+ } else {
+ setOutcome(choice)
+ }
+ if (!isIOS() && !isAndroid()) {
+ focusAmountInput()
+ }
+ }
+
function onBetChange(newAmount: number | undefined) {
- setWasSubmitted(false)
setBetAmount(newAmount)
if (!outcome) {
setOutcome('YES')
@@ -214,9 +231,13 @@ function BuyPanel(props: {
.then((r) => {
console.log('placed bet. Result:', r)
setIsSubmitting(false)
- setWasSubmitted(true)
setBetAmount(undefined)
if (onBuySuccess) onBuySuccess()
+ else {
+ toast('Trade submitted!', {
+ icon: ,
+ })
+ }
})
.catch((e) => {
if (e instanceof APIError) {
@@ -249,6 +270,7 @@ function BuyPanel(props: {
unfilledBets as LimitBet[]
)
+ const [seeLimit, setSeeLimit] = useState(false)
const resultProb = getCpmmProbability(newPool, newP)
const probStayedSame =
formatPercent(resultProb) === formatPercent(initialProb)
@@ -281,92 +303,132 @@ function BuyPanel(props: {
return (
-
- {isPseudoNumeric ? 'Direction' : 'Outcome'}
-
onBetChoice(choice)}
+ onSelect={(choice) => {
+ if (mobileView) {
+ mobileOnBetChoice(choice)
+ } else {
+ onBetChoice(choice)
+ }
+ }}
isPseudoNumeric={isPseudoNumeric}
/>
-
- Amount
-
- Balance: {formatMoney(user?.balance ?? 0)}
-
-
-
-
-
-
-
-
- {isPseudoNumeric ? 'Estimated value' : 'Probability'}
-
- {probStayedSame ? (
- {format(initialProb)}
- ) : (
-
- {format(initialProb)}
- →
- {format(resultProb)}
-
- )}
-
-
-
-
-
- {isPseudoNumeric ? (
- 'Max payout'
- ) : (
- <>
- Payout if
- >
- )}
-
-
-
-
- {formatMoney(currentPayout)}
-
- (+{currentReturnPercent})
-
-
-
-
-
-
- {user && (
-
- )}
+ ? 'bg-teal-50'
+ : 'hidden'
+ : 'bg-white',
+ mobileView ? 'rounded-lg px-4 py-2' : 'px-0'
+ )}
+ >
+
+
+
+
+ {isPseudoNumeric ? (
+ 'Max payout'
+ ) : (
+ <>Payout if {outcome ?? 'YES'}>
+ )}
+
+
+
+
+ {formatMoney(currentPayout)}
+
+
+ {' '}
+ +{currentReturnPercent}
+
+
+
+
+
+ {isPseudoNumeric ? 'Estimated value' : 'New Probability'}
+
+ {probStayedSame ? (
+ {format(initialProb)}
+ ) : (
+
+ {format(resultProb)}
+
+ {isPseudoNumeric ? (
+ <>>
+ ) : (
+ <>
+ {' '}
+ {outcome != 'NO' && '+'}
+ {format(resultProb - initialProb)}
+ >
+ )}
+
+
+ )}
+
+
+
+ Amount
+
- {wasSubmitted && Trade submitted!
}
+
+
+
+
+ {user && (
+
+ )}
+
+
+
+
+
+
)
}
@@ -389,7 +451,6 @@ function LimitOrderPanel(props: {
const betChoice = 'YES'
const [error, setError] = useState()
const [isSubmitting, setIsSubmitting] = useState(false)
- const [wasSubmitted, setWasSubmitted] = useState(false)
const rangeError =
lowLimitProb !== undefined &&
@@ -437,7 +498,6 @@ function LimitOrderPanel(props: {
const noAmount = shares * (1 - (noLimitProb ?? 0))
function onBetChange(newAmount: number | undefined) {
- setWasSubmitted(false)
setBetAmount(newAmount)
}
@@ -482,7 +542,6 @@ function LimitOrderPanel(props: {
.then((r) => {
console.log('placed bet. Result:', r)
setIsSubmitting(false)
- setWasSubmitted(true)
setBetAmount(undefined)
setLowLimitProb(undefined)
setHighLimitProb(undefined)
@@ -718,8 +777,6 @@ function LimitOrderPanel(props: {
: `Submit order${hasTwoBets ? 's' : ''}`}
)}
-
- {wasSubmitted && Order submitted!
}
)
}
@@ -866,11 +923,7 @@ export function SellPanel(props: {
<>
{
-
-
- {tradingAllowed(contract) && (
-
- )}
-
+
+ {tradingAllowed(contract) && (
+
+ )}
+
)
}
diff --git a/web/components/contract/quick-bet.tsx b/web/components/contract/quick-bet.tsx
index 7b19306f..a71b6c7d 100644
--- a/web/components/contract/quick-bet.tsx
+++ b/web/components/contract/quick-bet.tsx
@@ -344,7 +344,7 @@ export function getColor(contract: Contract) {
return (
OUTCOME_TO_COLOR[resolution as resolution] ??
// If resolved to a FR answer, use 'primary'
- 'primary'
+ 'teal-500'
)
}
@@ -355,5 +355,5 @@ export function getColor(contract: Contract) {
}
// TODO: Not sure why eg green-400 doesn't work here; try upgrading Tailwind
- return 'primary'
+ return 'teal-500'
}
diff --git a/web/components/outcome-label.tsx b/web/components/outcome-label.tsx
index 94b2b878..60b4403b 100644
--- a/web/components/outcome-label.tsx
+++ b/web/components/outcome-label.tsx
@@ -106,7 +106,7 @@ export const OUTCOME_TO_COLOR = {
}
export function YesLabel() {
- return YES
+ return YES
}
export function HigherLabel() {
diff --git a/web/components/warning-confirmation-button.tsx b/web/components/warning-confirmation-button.tsx
index 7b707098..4b37e2e9 100644
--- a/web/components/warning-confirmation-button.tsx
+++ b/web/components/warning-confirmation-button.tsx
@@ -4,8 +4,11 @@ import React from 'react'
import { Row } from './layout/row'
import { ConfirmationButton } from './confirmation-button'
import { ExclamationIcon } from '@heroicons/react/solid'
+import { formatMoney } from 'common/util/format'
export function WarningConfirmationButton(props: {
+ amount: number | undefined
+ outcome?: 'YES' | 'NO' | undefined
warning?: string
onSubmit: () => void
disabled?: boolean
@@ -14,12 +17,14 @@ export function WarningConfirmationButton(props: {
submitButtonClassName?: string
}) {
const {
+ amount,
onSubmit,
warning,
disabled,
isSubmitting,
openModalButtonClass,
submitButtonClassName,
+ outcome,
} = props
if (!warning) {
@@ -28,12 +33,15 @@ export function WarningConfirmationButton(props: {
className={clsx(
openModalButtonClass,
isSubmitting ? 'loading' : '',
- disabled && 'btn-disabled'
+ (disabled || !outcome) && 'btn-disabled bg-greyscale-2'
)}
onClick={onSubmit}
- disabled={disabled}
>
- {isSubmitting ? 'Submitting...' : 'Submit'}
+ {isSubmitting
+ ? 'Submitting...'
+ : amount
+ ? `Wager ${formatMoney(amount)}`
+ : 'Wager'}
)
}
@@ -45,7 +53,7 @@ export function WarningConfirmationButton(props: {
openModalButtonClass,
isSubmitting && 'btn-disabled loading'
),
- label: 'Submit',
+ label: amount ? `Wager ${formatMoney(amount)}` : 'Wager',
}}
cancelBtn={{
label: 'Cancel',
diff --git a/web/components/yes-no-selector.tsx b/web/components/yes-no-selector.tsx
index 719308bf..f73cdef2 100644
--- a/web/components/yes-no-selector.tsx
+++ b/web/components/yes-no-selector.tsx
@@ -35,10 +35,11 @@ export function YesNoSelector(props: {