Refactor useSaveShares to actually read from localStorage, use less bug-prone interface.
This commit is contained in:
parent
600203a675
commit
9d9dcea9b5
|
@ -37,7 +37,7 @@ import {
|
|||
getPseudoProbability,
|
||||
} from 'common/pseudo-numeric'
|
||||
import { SellRow } from './sell-row'
|
||||
import { useSaveShares } from './use-save-shares'
|
||||
import { useSaveBinaryShares } from './use-save-binary-shares'
|
||||
import { SignUpPrompt } from './sign-up-prompt'
|
||||
import { isIOS } from 'web/lib/util/device'
|
||||
import { ProbabilityInput } from './probability-input'
|
||||
|
@ -56,12 +56,7 @@ export function BetPanel(props: {
|
|||
const userBets = useUserContractBets(user?.id, contract.id)
|
||||
const unfilledBets = useUnfilledBets(contract.id) ?? []
|
||||
const yourUnfilledBets = unfilledBets.filter((bet) => bet.userId === user?.id)
|
||||
const { yesFloorShares, noFloorShares } = useSaveShares(contract, userBets)
|
||||
const sharesOutcome = yesFloorShares
|
||||
? 'YES'
|
||||
: noFloorShares
|
||||
? 'NO'
|
||||
: undefined
|
||||
const { sharesOutcome } = useSaveBinaryShares(contract, userBets)
|
||||
|
||||
const [isLimitOrder, setIsLimitOrder] = useState(false)
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Modal } from './layout/modal'
|
|||
import { SellButton } from './sell-button'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { useUserContractBets } from 'web/hooks/use-user-bets'
|
||||
import { useSaveShares } from './use-save-shares'
|
||||
import { useSaveBinaryShares } from './use-save-binary-shares'
|
||||
|
||||
// Inline version of a bet panel. Opens BetPanel in a new modal.
|
||||
export default function BetRow(props: {
|
||||
|
@ -24,10 +24,8 @@ export default function BetRow(props: {
|
|||
)
|
||||
const user = useUser()
|
||||
const userBets = useUserContractBets(user?.id, contract.id)
|
||||
const { yesFloorShares, noFloorShares, yesShares, noShares } = useSaveShares(
|
||||
contract,
|
||||
userBets
|
||||
)
|
||||
const { yesShares, noShares, hasYesShares, hasNoShares } =
|
||||
useSaveBinaryShares(contract, userBets)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -40,7 +38,7 @@ export default function BetRow(props: {
|
|||
setBetChoice(choice)
|
||||
}}
|
||||
replaceNoButton={
|
||||
yesFloorShares > 0 ? (
|
||||
hasYesShares ? (
|
||||
<SellButton
|
||||
panelClassName={betPanelClassName}
|
||||
contract={contract}
|
||||
|
@ -51,7 +49,7 @@ export default function BetRow(props: {
|
|||
) : undefined
|
||||
}
|
||||
replaceYesButton={
|
||||
noFloorShares > 0 ? (
|
||||
hasNoShares ? (
|
||||
<SellButton
|
||||
panelClassName={betPanelClassName}
|
||||
contract={contract}
|
||||
|
|
|
@ -52,10 +52,7 @@ export function ContractCard(props: {
|
|||
const showQuickBet =
|
||||
user &&
|
||||
!marketClosed &&
|
||||
!(
|
||||
outcomeType === 'FREE_RESPONSE' && getTopAnswer(contract) === undefined
|
||||
) &&
|
||||
outcomeType !== 'NUMERIC' &&
|
||||
(outcomeType === 'BINARY' || outcomeType === 'PSEUDO_NUMERIC') &&
|
||||
!hideQuickBet
|
||||
|
||||
return (
|
||||
|
|
|
@ -7,7 +7,13 @@ import {
|
|||
} from 'common/calculate'
|
||||
import { getExpectedValue } from 'common/calculate-dpm'
|
||||
import { User } from 'common/user'
|
||||
import { Contract, NumericContract, resolution } from 'common/contract'
|
||||
import {
|
||||
BinaryContract,
|
||||
Contract,
|
||||
NumericContract,
|
||||
PseudoNumericContract,
|
||||
resolution,
|
||||
} from 'common/contract'
|
||||
import {
|
||||
formatLargeNumber,
|
||||
formatMoney,
|
||||
|
@ -22,7 +28,7 @@ import TriangleDownFillIcon from 'web/lib/icons/triangle-down-fill-icon'
|
|||
import TriangleFillIcon from 'web/lib/icons/triangle-fill-icon'
|
||||
import { Col } from '../layout/col'
|
||||
import { OUTCOME_TO_COLOR } from '../outcome-label'
|
||||
import { useSaveShares } from '../use-save-shares'
|
||||
import { useSaveBinaryShares } from '../use-save-binary-shares'
|
||||
import { sellShares } from 'web/lib/firebase/api-call'
|
||||
import { calculateCpmmSale, getCpmmProbability } from 'common/calculate-cpmm'
|
||||
import { track } from 'web/lib/service/analytics'
|
||||
|
@ -31,26 +37,21 @@ import { useUnfilledBets } from 'web/hooks/use-bets'
|
|||
|
||||
const BET_SIZE = 10
|
||||
|
||||
export function QuickBet(props: { contract: Contract; user: User }) {
|
||||
export function QuickBet(props: {
|
||||
contract: BinaryContract | PseudoNumericContract
|
||||
user: User
|
||||
}) {
|
||||
const { contract, user } = props
|
||||
const { mechanism, outcomeType } = contract
|
||||
const isCpmm = mechanism === 'cpmm-1'
|
||||
|
||||
const userBets = useUserContractBets(user.id, contract.id)
|
||||
const unfilledBets = useUnfilledBets(contract.id) ?? []
|
||||
const topAnswer =
|
||||
outcomeType === 'FREE_RESPONSE' ? getTopAnswer(contract) : undefined
|
||||
|
||||
// TODO: yes/no from useSaveShares doesn't work on numeric contracts
|
||||
const { yesFloorShares, noFloorShares, yesShares, noShares } = useSaveShares(
|
||||
contract,
|
||||
userBets,
|
||||
topAnswer?.number.toString() || undefined
|
||||
)
|
||||
const hasUpShares =
|
||||
yesFloorShares || (noFloorShares && outcomeType === 'NUMERIC')
|
||||
const hasDownShares =
|
||||
noFloorShares && yesFloorShares <= 0 && outcomeType !== 'NUMERIC'
|
||||
const { hasYesShares, hasNoShares, yesShares, noShares } =
|
||||
useSaveBinaryShares(contract, userBets)
|
||||
const hasUpShares = hasYesShares
|
||||
const hasDownShares = hasNoShares && !hasUpShares
|
||||
|
||||
const [upHover, setUpHover] = useState(false)
|
||||
const [downHover, setDownHover] = useState(false)
|
||||
|
@ -134,13 +135,6 @@ export function QuickBet(props: { contract: Contract; user: User }) {
|
|||
})
|
||||
}
|
||||
|
||||
if (outcomeType === 'FREE_RESPONSE')
|
||||
return (
|
||||
<Col className="relative -my-4 -mr-5 min-w-[5.5rem] justify-center gap-2 pr-5 pl-1 align-middle">
|
||||
<QuickOutcomeView contract={contract} previewProb={previewProb} />
|
||||
</Col>
|
||||
)
|
||||
|
||||
return (
|
||||
<Col
|
||||
className={clsx(
|
||||
|
@ -161,7 +155,7 @@ export function QuickBet(props: { contract: Contract; user: User }) {
|
|||
{formatMoney(10)}
|
||||
</div>
|
||||
|
||||
{hasUpShares > 0 ? (
|
||||
{hasUpShares ? (
|
||||
<TriangleFillIcon
|
||||
className={clsx(
|
||||
'mx-auto h-5 w-5',
|
||||
|
@ -196,7 +190,7 @@ export function QuickBet(props: { contract: Contract; user: User }) {
|
|||
onMouseLeave={() => setDownHover(false)}
|
||||
onClick={() => placeQuickBet('DOWN')}
|
||||
></div>
|
||||
{hasDownShares > 0 ? (
|
||||
{hasDownShares ? (
|
||||
<TriangleDownFillIcon
|
||||
className={clsx(
|
||||
'mx-auto h-5 w-5',
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Row } from './layout/row'
|
|||
import { formatWithCommas } from 'common/util/format'
|
||||
import { OutcomeLabel } from './outcome-label'
|
||||
import { useUserContractBets } from 'web/hooks/use-user-bets'
|
||||
import { useSaveShares } from './use-save-shares'
|
||||
import { useSaveBinaryShares } from './use-save-binary-shares'
|
||||
import { SellSharesModal } from './sell-modal'
|
||||
|
||||
export function SellRow(props: {
|
||||
|
@ -20,16 +20,7 @@ export function SellRow(props: {
|
|||
const [showSellModal, setShowSellModal] = useState(false)
|
||||
|
||||
const { mechanism } = contract
|
||||
const { yesFloorShares, noFloorShares, yesShares, noShares } = useSaveShares(
|
||||
contract,
|
||||
userBets
|
||||
)
|
||||
const floorShares = yesFloorShares || noFloorShares
|
||||
const sharesOutcome = yesFloorShares
|
||||
? 'YES'
|
||||
: noFloorShares
|
||||
? 'NO'
|
||||
: undefined
|
||||
const { sharesOutcome, shares } = useSaveBinaryShares(contract, userBets)
|
||||
|
||||
if (sharesOutcome && user && mechanism === 'cpmm-1') {
|
||||
return (
|
||||
|
@ -37,7 +28,7 @@ export function SellRow(props: {
|
|||
<Col className={className}>
|
||||
<Row className="items-center justify-between gap-2 ">
|
||||
<div>
|
||||
You have {formatWithCommas(floorShares)}{' '}
|
||||
You have {formatWithCommas(shares)}{' '}
|
||||
<OutcomeLabel
|
||||
outcome={sharesOutcome}
|
||||
contract={contract}
|
||||
|
@ -64,7 +55,7 @@ export function SellRow(props: {
|
|||
contract={contract}
|
||||
user={user}
|
||||
userBets={userBets ?? []}
|
||||
shares={sharesOutcome === 'YES' ? yesShares : noShares}
|
||||
shares={shares}
|
||||
sharesOutcome={sharesOutcome}
|
||||
setOpen={setShowSellModal}
|
||||
/>
|
||||
|
|
56
web/components/use-save-binary-shares.ts
Normal file
56
web/components/use-save-binary-shares.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { BinaryContract, PseudoNumericContract } from 'common/contract'
|
||||
import { Bet } from 'common/bet'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { partition, sumBy } from 'lodash'
|
||||
import { safeLocalStorage } from 'web/lib/util/local'
|
||||
|
||||
export const useSaveBinaryShares = (
|
||||
contract: BinaryContract | PseudoNumericContract,
|
||||
userBets: Bet[] | undefined
|
||||
) => {
|
||||
const [savedShares, setSavedShares] = useState({ yesShares: 0, noShares: 0 })
|
||||
|
||||
const [yesBets, noBets] = partition(
|
||||
userBets ?? [],
|
||||
(bet) => bet.outcome === 'YES'
|
||||
)
|
||||
const [yesShares, noShares] = userBets
|
||||
? [sumBy(yesBets, (bet) => bet.shares), sumBy(noBets, (bet) => bet.shares)]
|
||||
: [savedShares.yesShares, savedShares.noShares]
|
||||
|
||||
useEffect(() => {
|
||||
const local = safeLocalStorage()
|
||||
|
||||
// Read shares from local storage.
|
||||
const savedShares = local?.getItem(`${contract.id}-shares`)
|
||||
if (savedShares) {
|
||||
setSavedShares(JSON.parse(savedShares))
|
||||
}
|
||||
|
||||
if (userBets) {
|
||||
// Save shares to local storage.
|
||||
const sharesData = JSON.stringify({ yesShares, noShares })
|
||||
local?.setItem(`${contract.id}-shares`, sharesData)
|
||||
}
|
||||
}, [contract.id, userBets, noShares, yesShares])
|
||||
|
||||
const hasYesShares = yesShares >= 1
|
||||
const hasNoShares = noShares >= 1
|
||||
|
||||
const sharesOutcome = hasYesShares
|
||||
? ('YES' as const)
|
||||
: hasNoShares
|
||||
? ('NO' as const)
|
||||
: undefined
|
||||
const shares =
|
||||
sharesOutcome === 'YES' ? yesShares : sharesOutcome === 'NO' ? noShares : 0
|
||||
|
||||
return {
|
||||
yesShares,
|
||||
noShares,
|
||||
shares,
|
||||
sharesOutcome,
|
||||
hasYesShares,
|
||||
hasNoShares,
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
import { Contract } from 'common/contract'
|
||||
import { Bet } from 'common/bet'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { partition, sumBy } from 'lodash'
|
||||
import { safeLocalStorage } from 'web/lib/util/local'
|
||||
|
||||
export const useSaveShares = (
|
||||
contract: Contract,
|
||||
userBets: Bet[] | undefined,
|
||||
freeResponseAnswerOutcome?: string
|
||||
) => {
|
||||
const [savedShares, setSavedShares] = useState<
|
||||
| {
|
||||
yesShares: number
|
||||
noShares: number
|
||||
yesFloorShares: number
|
||||
noFloorShares: number
|
||||
}
|
||||
| undefined
|
||||
>()
|
||||
|
||||
// TODO: How do we handle numeric yes / no bets? - maybe bet amounts above vs below the highest peak
|
||||
const [yesBets, noBets] = partition(userBets ?? [], (bet) =>
|
||||
freeResponseAnswerOutcome
|
||||
? bet.outcome === freeResponseAnswerOutcome
|
||||
: bet.outcome === 'YES'
|
||||
)
|
||||
const [yesShares, noShares] = [
|
||||
sumBy(yesBets, (bet) => bet.shares),
|
||||
sumBy(noBets, (bet) => bet.shares),
|
||||
]
|
||||
|
||||
const yesFloorShares = Math.round(yesShares) === 0 ? 0 : Math.floor(yesShares)
|
||||
const noFloorShares = Math.round(noShares) === 0 ? 0 : Math.floor(noShares)
|
||||
|
||||
useEffect(() => {
|
||||
const local = safeLocalStorage()
|
||||
// Save yes and no shares to local storage.
|
||||
const savedShares = local?.getItem(`${contract.id}-shares`)
|
||||
if (!userBets && savedShares) {
|
||||
setSavedShares(JSON.parse(savedShares))
|
||||
}
|
||||
|
||||
if (userBets) {
|
||||
const updatedShares = { yesShares, noShares }
|
||||
local?.setItem(`${contract.id}-shares`, JSON.stringify(updatedShares))
|
||||
}
|
||||
}, [contract.id, userBets, noShares, yesShares])
|
||||
|
||||
if (userBets) return { yesShares, noShares, yesFloorShares, noFloorShares }
|
||||
return (
|
||||
savedShares ?? {
|
||||
yesShares: 0,
|
||||
noShares: 0,
|
||||
yesFloorShares: 0,
|
||||
noFloorShares: 0,
|
||||
}
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user