diff --git a/web/components/answers/answers-graph.tsx b/web/components/answers/answers-graph.tsx index dae3a8b5..e4167d11 100644 --- a/web/components/answers/answers-graph.tsx +++ b/web/components/answers/answers-graph.tsx @@ -18,19 +18,20 @@ export const AnswersGraph = memo(function AnswersGraph(props: { }) { const { contract, bets, height } = props const { createdTime, resolutionTime, closeTime, answers } = contract + const now = Date.now() const { probsByOutcome, sortedOutcomes } = computeProbsByOutcome( bets, contract ) - const isClosed = !!closeTime && Date.now() > closeTime + const isClosed = !!closeTime && now > closeTime const latestTime = dayjs( resolutionTime && isClosed ? Math.min(resolutionTime, closeTime) : isClosed ? closeTime - : resolutionTime ?? Date.now() + : resolutionTime ?? now ) const { width } = useWindowSize() @@ -71,14 +72,14 @@ export const AnswersGraph = memo(function AnswersGraph(props: { const yTickValues = [0, 25, 50, 75, 100] const numXTickValues = isLargeWidth ? 5 : 2 - const startDate = new Date(contract.createdTime) - const endDate = dayjs(startDate).add(1, 'hour').isAfter(latestTime) - ? latestTime.add(1, 'hours').toDate() - : latestTime.toDate() - const includeMinute = dayjs(endDate).diff(startDate, 'hours') < 2 + const startDate = dayjs(contract.createdTime) + const endDate = startDate.add(1, 'hour').isAfter(latestTime) + ? latestTime.add(1, 'hours') + : latestTime + const includeMinute = endDate.diff(startDate, 'hours') < 2 - const multiYear = !dayjs(startDate).isSame(latestTime, 'year') - const lessThanAWeek = dayjs(startDate).add(1, 'week').isAfter(latestTime) + const multiYear = !startDate.isSame(latestTime, 'year') + const lessThanAWeek = startDate.add(1, 'week').isAfter(latestTime) return (
- formatTime(+d.valueOf(), multiYear, lessThanAWeek, lessThanAWeek) + formatTime(now, +d.valueOf(), multiYear, lessThanAWeek, lessThanAWeek) } axisBottom={{ tickValues: numXTickValues, format: (time) => - formatTime(+time, multiYear, lessThanAWeek, includeMinute), + formatTime(now, +time, multiYear, lessThanAWeek, includeMinute), }} colors={[ '#fca5a5', // red-300 @@ -158,23 +159,20 @@ function formatPercent(y: DatumValue) { } function formatTime( + now: number, time: number, includeYear: boolean, includeHour: boolean, includeMinute: boolean ) { const d = dayjs(time) - - if ( - d.add(1, 'minute').isAfter(Date.now()) && - d.subtract(1, 'minute').isBefore(Date.now()) - ) + if (d.add(1, 'minute').isAfter(now) && d.subtract(1, 'minute').isBefore(now)) return 'Now' let format: string - if (d.isSame(Date.now(), 'day')) { + if (d.isSame(now, 'day')) { format = '[Today]' - } else if (d.add(1, 'day').isSame(Date.now(), 'day')) { + } else if (d.add(1, 'day').isSame(now, 'day')) { format = '[Yesterday]' } else { format = 'MMM D' diff --git a/web/components/contract/contract-description.tsx b/web/components/contract/contract-description.tsx index 9bffed9b..53557305 100644 --- a/web/components/contract/contract-description.tsx +++ b/web/components/contract/contract-description.tsx @@ -6,6 +6,7 @@ import Textarea from 'react-expanding-textarea' import { Contract, MAX_DESCRIPTION_LENGTH } from 'common/contract' import { exhibitExts, parseTags } from 'common/util/parse' import { useAdmin } from 'web/hooks/use-admin' +import { useUser } from 'web/hooks/use-user' import { updateContract } from 'web/lib/firebase/contracts' import { Row } from '../layout/row' import { Content } from '../editor' @@ -17,11 +18,12 @@ import { insertContent } from '../editor/utils' export function ContractDescription(props: { contract: Contract - isCreator: boolean className?: string }) { - const { contract, isCreator, className } = props + const { contract, className } = props const isAdmin = useAdmin() + const user = useUser() + const isCreator = user?.id === contract.creatorId return (
{isCreator || isAdmin ? ( diff --git a/web/components/contract/contract-details.tsx b/web/components/contract/contract-details.tsx index a2432397..8edf9299 100644 --- a/web/components/contract/contract-details.tsx +++ b/web/components/contract/contract-details.tsx @@ -30,7 +30,6 @@ import { SiteLink } from 'web/components/site-link' import { getGroupLinkToDisplay, groupPath } from 'web/lib/firebase/groups' import { insertContent } from '../editor/utils' import { contractMetrics } from 'common/contract-details' -import { User } from 'common/user' import { UserLink } from 'web/components/user-link' import { FeaturedContractBadge } from 'web/components/contract/featured-contract-badge' import { Tooltip } from 'web/components/tooltip' @@ -138,11 +137,9 @@ export function AbbrContractDetails(props: { export function ContractDetails(props: { contract: Contract - user: User | null | undefined - isCreator?: boolean disabled?: boolean }) { - const { contract, isCreator, disabled } = props + const { contract, disabled } = props const { closeTime, creatorName, @@ -153,6 +150,7 @@ export function ContractDetails(props: { } = contract const { volumeLabel, resolvedDate } = contractMetrics(contract) const user = useUser() + const isCreator = user?.id === creatorId const [open, setOpen] = useState(false) const { width } = useWindowSize() const isMobile = (width ?? 0) < 600 @@ -279,12 +277,12 @@ export function ContractDetails(props: { export function ExtraMobileContractDetails(props: { contract: Contract - user: User | null | undefined forceShowVolume?: boolean }) { - const { contract, user, forceShowVolume } = props + const { contract, forceShowVolume } = props const { volume, resolutionTime, closeTime, creatorId, uniqueBettorCount } = contract + const user = useUser() const uniqueBettors = uniqueBettorCount ?? 0 const { resolvedDate } = contractMetrics(contract) const volumeTranslation = diff --git a/web/components/contract/contract-overview.tsx b/web/components/contract/contract-overview.tsx index 272de6c5..1bfe84de 100644 --- a/web/components/contract/contract-overview.tsx +++ b/web/components/contract/contract-overview.tsx @@ -1,5 +1,4 @@ import React from 'react' -import clsx from 'clsx' import { tradingAllowed } from 'web/lib/firebase/contracts' import { Col } from '../layout/col' @@ -16,136 +15,154 @@ import { import { Bet } from 'common/bet' import BetButton from '../bet-button' import { AnswersGraph } from '../answers/answers-graph' -import { Contract, CPMMBinaryContract } from 'common/contract' -import { ContractDescription } from './contract-description' +import { + Contract, + BinaryContract, + CPMMContract, + CPMMBinaryContract, + FreeResponseContract, + MultipleChoiceContract, + NumericContract, + PseudoNumericContract, +} from 'common/contract' import { ContractDetails, ExtraMobileContractDetails } from './contract-details' import { NumericGraph } from './numeric-graph' -import { ExtraContractActionsRow } from 'web/components/contract/extra-contract-actions-row' + +const OverviewQuestion = (props: { text: string }) => ( + +) + +const BetWidget = (props: { contract: CPMMContract }) => { + const user = useUser() + return ( + + + {!user && ( +
+ (with play money!) +
+ )} + + ) +} + +const NumericOverview = (props: { contract: NumericContract }) => { + const { contract } = props + return ( + + + + + + + + + + + + ) +} + +const BinaryOverview = (props: { contract: BinaryContract; bets: Bet[] }) => { + const { contract, bets } = props + return ( + + + + + + + + + + + {tradingAllowed(contract) && ( + + )} + + + + + ) +} + +const ChoiceOverview = (props: { + contract: FreeResponseContract | MultipleChoiceContract + bets: Bet[] +}) => { + const { contract, bets } = props + const { question, resolution } = contract + return ( + + + + + {resolution && ( + + )} + + + + + + + ) +} + +const PseudoNumericOverview = (props: { + contract: PseudoNumericContract + bets: Bet[] +}) => { + const { contract, bets } = props + return ( + + + + + + + + + + + {tradingAllowed(contract) && } + + + + + ) +} export const ContractOverview = (props: { contract: Contract bets: Bet[] - className?: string }) => { - const { contract, bets, className } = props - const { question, creatorId, outcomeType, resolution } = contract - - const user = useUser() - const isCreator = user?.id === creatorId - - const isBinary = outcomeType === 'BINARY' - const isPseudoNumeric = outcomeType === 'PSEUDO_NUMERIC' - - return ( - - - - -
- -
- - {isBinary && ( - - )} - - {isPseudoNumeric && ( - - )} - - {outcomeType === 'NUMERIC' && ( - - )} - -
- - {isBinary ? ( - - - - {tradingAllowed(contract) && ( - - - - {!user && ( -
- (with play money!) -
- )} - -
- )} -
- ) : isPseudoNumeric ? ( - - - - {tradingAllowed(contract) && ( - - - - {!user && ( -
- (with play money!) -
- )} - -
- )} -
- ) : ( - (outcomeType === 'FREE_RESPONSE' || - outcomeType === 'MULTIPLE_CHOICE') && - resolution && ( - - ) - )} - - {outcomeType === 'NUMERIC' && ( - - - - )} - -
- {(isBinary || isPseudoNumeric) && ( - - )}{' '} - {(outcomeType === 'FREE_RESPONSE' || - outcomeType === 'MULTIPLE_CHOICE') && ( - - - - - )} - {outcomeType === 'NUMERIC' && } - - - - ) + const { contract, bets } = props + switch (contract.outcomeType) { + case 'BINARY': + return + case 'NUMERIC': + return + case 'PSEUDO_NUMERIC': + return + case 'FREE_RESPONSE': + case 'MULTIPLE_CHOICE': + return + } } diff --git a/web/components/contract/extra-contract-actions-row.tsx b/web/components/contract/extra-contract-actions-row.tsx index 2ae370b1..f84655ec 100644 --- a/web/components/contract/extra-contract-actions-row.tsx +++ b/web/components/contract/extra-contract-actions-row.tsx @@ -5,7 +5,7 @@ import { Row } from '../layout/row' import { Contract } from 'web/lib/firebase/contracts' import React, { useState } from 'react' import { Button } from 'web/components/button' -import { User } from 'common/user' +import { useUser } from 'web/hooks/use-user' import { ShareModal } from './share-modal' import { FollowMarketButton } from 'web/components/follow-market-button' import { LikeMarketButton } from 'web/components/contract/like-market-button' @@ -15,12 +15,10 @@ import { withTracking } from 'web/lib/service/analytics' import { CreateChallengeModal } from 'web/components/challenges/create-challenge-modal' import { CHALLENGES_ENABLED } from 'common/challenge' -export function ExtraContractActionsRow(props: { - contract: Contract - user: User | undefined | null -}) { - const { user, contract } = props +export function ExtraContractActionsRow(props: { contract: Contract }) { + const { contract } = props const { outcomeType, resolution } = contract + const user = useUser() const [isShareOpen, setShareOpen] = useState(false) const [openCreateChallengeModal, setOpenCreateChallengeModal] = useState(false) diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx index f3c48a68..aeb50488 100644 --- a/web/pages/[username]/[contractSlug].tsx +++ b/web/pages/[username]/[contractSlug].tsx @@ -36,6 +36,8 @@ import { useSaveReferral } from 'web/hooks/use-save-referral' import { User } from 'common/user' import { ContractComment } from 'common/comment' import { getOpenGraphProps } from 'common/contract-details' +import { ContractDescription } from 'web/components/contract/contract-description' +import { ExtraContractActionsRow } from 'web/components/contract/extra-contract-actions-row' import { ContractLeaderboard, ContractTopTrades, @@ -232,6 +234,8 @@ export function ContractPageContent( )} + + {outcomeType === 'NUMERIC' && ( - + {(isBinary || isPseudoNumeric) && tradingAllowed(contract) &&