new market view (#819)

* Show old details on lg, don't unfill heart

* Hide tip market if creator

* Small ui tweaks

* Remove contract. calls

* Update high-medium-low

* Remove unused bets prop

* Show uniques

* Remove unused bets prop
This commit is contained in:
Ian Philips 2022-08-30 17:13:25 -06:00 committed by GitHub
parent 3e1e84ee5e
commit aad5f6528b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 245 additions and 176 deletions

View File

@ -3,6 +3,6 @@ export type Like = {
userId: string
type: 'contract'
createdTime: number
tipTxnId?: string
tipTxnId?: string // only holds most recent tip txn id
}
export const LIKE_TIP_AMOUNT = 5

View File

@ -31,8 +31,7 @@ export * from './weekly-markets-emails'
export * from './reset-betting-streaks'
export * from './reset-weekly-emails-flag'
export * from './on-update-contract-follow'
export * from './on-create-like'
export * from './on-delete-like'
export * from './on-update-like'
// v2
export * from './health'

View File

@ -1,32 +0,0 @@
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
import { Like } from '../../common/like'
import { getContract, log } from './utils'
import { uniq } from 'lodash'
const firestore = admin.firestore()
export const onDeleteLike = functions.firestore
.document('users/{userId}/likes/{likeId}')
.onDelete(async (change) => {
const like = change.data() as Like
if (like.type === 'contract') {
await removeContractLike(like)
}
})
const removeContractLike = async (like: Like) => {
const contract = await getContract(like.id)
if (!contract) {
log('Could not find contract')
return
}
const likedByUserIds = uniq(contract.likedByUserIds ?? [])
const newLikedByUserIds = likedByUserIds.filter(
(userId) => userId !== like.userId
)
await firestore.collection('contracts').doc(like.id).update({
likedByUserIds: newLikedByUserIds,
likedByUserCount: newLikedByUserIds.length,
})
}

View File

@ -19,14 +19,36 @@ export const onCreateLike = functions.firestore
}
})
export const onUpdateLike = functions.firestore
.document('users/{userId}/likes/{likeId}')
.onUpdate(async (change, context) => {
const like = change.after.data() as Like
const prevLike = change.before.data() as Like
const { eventId } = context
if (like.type === 'contract' && like.tipTxnId !== prevLike.tipTxnId) {
await handleCreateLikeNotification(like, eventId)
await updateContractLikes(like)
}
})
export const onDeleteLike = functions.firestore
.document('users/{userId}/likes/{likeId}')
.onDelete(async (change) => {
const like = change.data() as Like
if (like.type === 'contract') {
await removeContractLike(like)
}
})
const updateContractLikes = async (like: Like) => {
const contract = await getContract(like.id)
if (!contract) {
log('Could not find contract')
return
}
const likedByUserIds = uniq(contract.likedByUserIds ?? [])
likedByUserIds.push(like.userId)
const likedByUserIds = uniq(
(contract.likedByUserIds ?? []).concat(like.userId)
)
await firestore
.collection('contracts')
.doc(like.id)
@ -69,3 +91,19 @@ const handleCreateLikeNotification = async (like: Like, eventId: string) => {
tipTxnData
)
}
const removeContractLike = async (like: Like) => {
const contract = await getContract(like.id)
if (!contract) {
log('Could not find contract')
return
}
const likedByUserIds = uniq(contract.likedByUserIds ?? [])
const newLikedByUserIds = likedByUserIds.filter(
(userId) => userId !== like.userId
)
await firestore.collection('contracts').doc(like.id).update({
likedByUserIds: newLikedByUserIds,
likedByUserCount: newLikedByUserIds.length,
})
}

View File

@ -18,7 +18,6 @@ import { fromNow } from 'web/lib/util/time'
import { Avatar } from '../avatar'
import { useState } from 'react'
import { ContractInfoDialog } from './contract-info-dialog'
import { Bet } from 'common/bet'
import NewContractBadge from '../new-contract-badge'
import { UserFollowButton } from '../follow-button'
import { DAY_MS } from 'common/util/time'
@ -35,6 +34,8 @@ 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'
import { useWindowSize } from 'web/hooks/use-window-size'
export type ShowTime = 'resolve-date' | 'close-date'
@ -78,7 +79,7 @@ export function MiscDetails(props: {
) : (contract?.featuredOnHomeRank ?? 0) > 0 ? (
<FeaturedContractBadge />
) : volume > 0 || !isNew ? (
<Row className={'shrink-0'}>{formatMoney(contract.volume)} bet</Row>
<Row className={'shrink-0'}>{formatMoney(volume)} bet</Row>
) : (
<NewContractBadge />
)}
@ -101,7 +102,7 @@ export function AvatarDetails(props: {
short?: boolean
}) {
const { contract, short, className } = props
const { creatorName, creatorUsername } = contract
const { creatorName, creatorUsername, creatorAvatarUrl } = contract
return (
<Row
@ -109,7 +110,7 @@ export function AvatarDetails(props: {
>
<Avatar
username={creatorUsername}
avatarUrl={contract.creatorAvatarUrl}
avatarUrl={creatorAvatarUrl}
size={6}
/>
<UserLink name={creatorName} username={creatorUsername} short={short} />
@ -138,20 +139,28 @@ export function AbbrContractDetails(props: {
export function ContractDetails(props: {
contract: Contract
bets: Bet[]
user: User | null | undefined
isCreator?: boolean
disabled?: boolean
}) {
const { contract, bets, isCreator, disabled } = props
const { closeTime, creatorName, creatorUsername, creatorId, groupLinks } =
contract
const { contract, isCreator, disabled } = props
const {
closeTime,
creatorName,
creatorUsername,
creatorId,
groupLinks,
creatorAvatarUrl,
resolutionTime,
} = contract
const { volumeLabel, resolvedDate } = contractMetrics(contract)
const groupToDisplay =
groupLinks?.sort((a, b) => a.createdTime - b.createdTime)[0] ?? null
const user = useUser()
const [open, setOpen] = useState(false)
const { width } = useWindowSize()
const isMobile = (width ?? 0) < 600
const groupInfo = (
<Row>
@ -167,7 +176,7 @@ export function ContractDetails(props: {
<Row className="items-center gap-2">
<Avatar
username={creatorUsername}
avatarUrl={contract.creatorAvatarUrl}
avatarUrl={creatorAvatarUrl}
noLink={disabled}
size={6}
/>
@ -178,6 +187,7 @@ export function ContractDetails(props: {
className="whitespace-nowrap"
name={creatorName}
username={creatorUsername}
short={isMobile}
/>
)}
{!disabled && <UserFollowButton userId={creatorId} small />}
@ -228,14 +238,11 @@ export function ContractDetails(props: {
</Modal>
{(!!closeTime || !!resolvedDate) && (
<Row className="items-center gap-1">
{resolvedDate && contract.resolutionTime ? (
<Row className="hidden items-center gap-1 md:inline-flex">
{resolvedDate && resolutionTime ? (
<>
<ClockIcon className="h-5 w-5" />
<DateTimeTooltip
text="Market resolved:"
time={contract.resolutionTime}
>
<DateTimeTooltip text="Market resolved:" time={resolutionTime}>
{resolvedDate}
</DateTimeTooltip>
</>
@ -255,17 +262,84 @@ export function ContractDetails(props: {
)}
{user && (
<>
<Row className="items-center gap-1">
<Row className="hidden items-center gap-1 md:inline-flex">
<DatabaseIcon className="h-5 w-5" />
<div className="whitespace-nowrap">{volumeLabel}</div>
</Row>
{!disabled && <ContractInfoDialog contract={contract} bets={bets} />}
{!disabled && (
<ContractInfoDialog
contract={contract}
className={'hidden md:inline-flex'}
/>
)}
</>
)}
</Row>
)
}
export function ExtraMobileContractDetails(props: {
contract: Contract
user: User | null | undefined
forceShowVolume?: boolean
}) {
const { contract, user, forceShowVolume } = props
const { volume, resolutionTime, closeTime, creatorId, uniqueBettorCount } =
contract
const uniqueBettors = uniqueBettorCount ?? 0
const { resolvedDate } = contractMetrics(contract)
const volumeTranslation =
volume > 800 || uniqueBettors > 20
? 'High'
: volume > 300 || uniqueBettors > 10
? 'Medium'
: 'Low'
return (
<Row
className={clsx(
'items-center justify-around md:hidden',
user ? 'w-full' : ''
)}
>
{resolvedDate && resolutionTime ? (
<Col className={'items-center text-sm'}>
<Row className={'text-gray-500'}>
<DateTimeTooltip text="Market resolved:" time={resolutionTime}>
{resolvedDate}
</DateTimeTooltip>
</Row>
<Row className={'text-gray-400'}>Ended</Row>
</Col>
) : (
!resolvedDate &&
closeTime && (
<Col className={'items-center text-sm text-gray-500'}>
<EditableCloseDate
closeTime={closeTime}
contract={contract}
isCreator={creatorId === user?.id}
/>
<Row className={'text-gray-400'}>Ends</Row>
</Col>
)
)}
{(user || forceShowVolume) && (
<Col className={'items-center text-sm text-gray-500'}>
<Tooltip
text={`${formatMoney(
volume
)} bet - ${uniqueBettors} unique bettors`}
>
{volumeTranslation}
</Tooltip>
<Row className={'text-gray-400'}>Activity</Row>
</Col>
)}
</Row>
)
}
function EditableCloseDate(props: {
closeTime: number
contract: Contract
@ -318,10 +392,10 @@ function EditableCloseDate(props: {
return (
<>
{isEditingCloseTime ? (
<Row className="mr-1 items-start">
<Row className="z-10 mr-2 w-full shrink-0 items-start items-center gap-1">
<input
type="date"
className="input input-bordered"
className="input input-bordered shrink-0"
onClick={(e) => e.stopPropagation()}
onChange={(e) => setCloseDate(e.target.value)}
min={Date.now()}
@ -329,39 +403,32 @@ function EditableCloseDate(props: {
/>
<input
type="time"
className="input input-bordered ml-2"
className="input input-bordered shrink-0"
onClick={(e) => e.stopPropagation()}
onChange={(e) => setCloseHoursMinutes(e.target.value)}
min="00:00"
value={closeHoursMinutes}
/>
<Button size={'xs'} color={'blue'} onClick={onSave}>
Done
</Button>
</Row>
) : (
<DateTimeTooltip
text={closeTime > Date.now() ? 'Trading ends:' : 'Trading ended:'}
time={closeTime}
>
{isSameYear
? dayJsCloseTime.format('MMM D')
: dayJsCloseTime.format('MMM D, YYYY')}
{isSameDay && <> ({fromNow(closeTime)})</>}
<span
className={isCreator ? 'cursor-pointer' : ''}
onClick={() => isCreator && setIsEditingCloseTime(true)}
>
{isSameYear
? dayJsCloseTime.format('MMM D')
: dayJsCloseTime.format('MMM D, YYYY')}
{isSameDay && <> ({fromNow(closeTime)})</>}
</span>
</DateTimeTooltip>
)}
{isCreator &&
(isEditingCloseTime ? (
<button className="btn btn-xs" onClick={onSave}>
Done
</button>
) : (
<Button
size={'xs'}
color={'gray-white'}
onClick={() => setIsEditingCloseTime(true)}
>
<PencilIcon className="!container mr-0.5 mb-0.5 inline h-4 w-4" />
</Button>
))}
</>
)
}

View File

@ -1,9 +1,7 @@
import { DotsHorizontalIcon } from '@heroicons/react/outline'
import clsx from 'clsx'
import dayjs from 'dayjs'
import { uniqBy } from 'lodash'
import { useState } from 'react'
import { Bet } from 'common/bet'
import { Contract } from 'common/contract'
import { formatMoney } from 'common/util/format'
@ -22,8 +20,11 @@ import ShortToggle from '../widgets/short-toggle'
export const contractDetailsButtonClassName =
'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500'
export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
const { contract, bets } = props
export function ContractInfoDialog(props: {
contract: Contract
className?: string
}) {
const { contract, className } = props
const [open, setOpen] = useState(false)
const [featured, setFeatured] = useState(
@ -37,11 +38,7 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
const { createdTime, closeTime, resolutionTime, mechanism, outcomeType, id } =
contract
const tradersCount = uniqBy(
bets.filter((bet) => !bet.isAnte),
'userId'
).length
const bettorsCount = contract.uniqueBettorCount ?? 'Unknown'
const typeDisplay =
outcomeType === 'BINARY'
? 'YES / NO'
@ -69,7 +66,7 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
return (
<>
<button
className={contractDetailsButtonClassName}
className={clsx(contractDetailsButtonClassName, className)}
onClick={() => setOpen(true)}
>
<DotsHorizontalIcon
@ -136,8 +133,8 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
</tr> */}
<tr>
<td>Traders</td>
<td>{tradersCount}</td>
<td>Bettors</td>
<td>{bettorsCount}</td>
</tr>
<tr>

View File

@ -18,10 +18,9 @@ import BetButton from '../bet-button'
import { AnswersGraph } from '../answers/answers-graph'
import { Contract, CPMMBinaryContract } from 'common/contract'
import { ContractDescription } from './contract-description'
import { ContractDetails } from './contract-details'
import { ContractDetails, ExtraMobileContractDetails } from './contract-details'
import { NumericGraph } from './numeric-graph'
import { ShareRow } from './share-row'
import { LikeMarketButton } from 'web/components/contract/like-market-button'
import { ExtraContractActionsRow } from 'web/components/contract/extra-contract-actions-row'
export const ContractOverview = (props: {
contract: Contract
@ -40,17 +39,15 @@ export const ContractOverview = (props: {
return (
<Col className={clsx('mb-6', className)}>
<Col className="gap-3 px-2 sm:gap-4">
<ContractDetails
contract={contract}
user={user}
isCreator={isCreator}
/>
<Row className="justify-between gap-4">
<div className="text-2xl text-indigo-700 md:text-3xl">
<Linkify text={question} />
</div>
{(outcomeType === 'FREE_RESPONSE' ||
outcomeType === 'MULTIPLE_CHOICE') &&
!resolution && (
<div className={'sm:hidden'}>
<LikeMarketButton contract={contract} user={user} />
</div>
)}
<Row className={'hidden gap-3 xl:flex'}>
{isBinary && (
<BinaryResolutionOrChance
@ -79,11 +76,9 @@ export const ContractOverview = (props: {
{isBinary ? (
<Row className="items-center justify-between gap-4 xl:hidden">
<BinaryResolutionOrChance contract={contract} />
<ExtraMobileContractDetails contract={contract} user={user} />
{tradingAllowed(contract) && (
<Row>
<div className={'sm:hidden'}>
<LikeMarketButton contract={contract} user={user} />
</div>
<Col>
<BetButton contract={contract as CPMMBinaryContract} />
{!user && (
@ -98,11 +93,9 @@ export const ContractOverview = (props: {
) : isPseudoNumeric ? (
<Row className="items-center justify-between gap-4 xl:hidden">
<PseudoNumericResolutionOrExpectation contract={contract} />
<ExtraMobileContractDetails contract={contract} user={user} />
{tradingAllowed(contract) && (
<Row>
<div className={'sm:hidden'}>
<LikeMarketButton contract={contract} user={user} />
</div>
<Col>
<BetButton contract={contract} />
{!user && (
@ -130,13 +123,6 @@ export const ContractOverview = (props: {
<NumericResolutionOrExpectation contract={contract} />
</Row>
)}
<ContractDetails
contract={contract}
bets={bets}
isCreator={isCreator}
user={user}
/>
</Col>
<div className={'my-1 md:my-2'}></div>
{(isBinary || isPseudoNumeric) && (
@ -144,10 +130,17 @@ export const ContractOverview = (props: {
)}{' '}
{(outcomeType === 'FREE_RESPONSE' ||
outcomeType === 'MULTIPLE_CHOICE') && (
<AnswersGraph contract={contract} bets={bets} />
<Col className={'mb-1 gap-y-2'}>
<AnswersGraph contract={contract} bets={bets} />
<ExtraMobileContractDetails
contract={contract}
user={user}
forceShowVolume={true}
/>
</Col>
)}
{outcomeType === 'NUMERIC' && <NumericGraph contract={contract} />}
<ShareRow user={user} contract={contract} />
<ExtraContractActionsRow user={user} contract={contract} />
<ContractDescription
className="px-2"
contract={contract}

View File

@ -3,31 +3,25 @@ import { ShareIcon } from '@heroicons/react/outline'
import { Row } from '../layout/row'
import { Contract } from 'web/lib/firebase/contracts'
import { useState } from 'react'
import React, { useState } from 'react'
import { Button } from 'web/components/button'
import { CreateChallengeModal } from '../challenges/create-challenge-modal'
import { User } from 'common/user'
import { CHALLENGES_ENABLED } from 'common/challenge'
import { ShareModal } from './share-modal'
import { withTracking } from 'web/lib/service/analytics'
import { FollowMarketButton } from 'web/components/follow-market-button'
import { LikeMarketButton } from 'web/components/contract/like-market-button'
import { ContractInfoDialog } from 'web/components/contract/contract-info-dialog'
import { Col } from 'web/components/layout/col'
export function ShareRow(props: {
export function ExtraContractActionsRow(props: {
contract: Contract
user: User | undefined | null
}) {
const { user, contract } = props
const { outcomeType, resolution } = contract
const showChallenge =
user && outcomeType === 'BINARY' && !resolution && CHALLENGES_ENABLED
const [isOpen, setIsOpen] = useState(false)
const [isShareOpen, setShareOpen] = useState(false)
return (
<Row className="mt-0.5 sm:mt-2">
<Row className={'mt-0.5 justify-around sm:mt-2 lg:justify-start'}>
<Button
size="lg"
color="gray-white"
@ -36,8 +30,14 @@ export function ShareRow(props: {
setShareOpen(true)
}}
>
<ShareIcon className={clsx('mr-2 h-[24px] w-5')} aria-hidden="true" />
Share
<Col className={'items-center sm:flex-row'}>
<ShareIcon
className={clsx('h-[24px] w-5 sm:mr-2')}
aria-hidden="true"
/>
<span>Share</span>
</Col>
<ShareModal
isOpen={isShareOpen}
setOpen={setShareOpen}
@ -46,28 +46,13 @@ export function ShareRow(props: {
/>
</Button>
{showChallenge && (
<Button
size="lg"
color="gray-white"
onClick={withTracking(
() => setIsOpen(true),
'click challenge button'
)}
>
Challenge
<CreateChallengeModal
isOpen={isOpen}
setOpen={setIsOpen}
user={user}
contract={contract}
/>
</Button>
)}
<FollowMarketButton contract={contract} user={user} />
<div className={'hidden sm:block'}>
{user?.id !== contract.creatorId && (
<LikeMarketButton contract={contract} user={user} />
</div>
)}
<Col className={'justify-center md:hidden'}>
<ContractInfoDialog contract={contract} />
</Col>
</Row>
)
}

View File

@ -6,10 +6,11 @@ import { User } from 'common/user'
import { useUserLikes } from 'web/hooks/use-likes'
import toast from 'react-hot-toast'
import { formatMoney } from 'common/util/format'
import { likeContract, unLikeContract } from 'web/lib/firebase/likes'
import { likeContract } from 'web/lib/firebase/likes'
import { LIKE_TIP_AMOUNT } from 'common/like'
import clsx from 'clsx'
import { Row } from 'web/components/layout/row'
import { Col } from 'web/components/layout/col'
import { firebaseLogin } from 'web/lib/firebase/users'
export function LikeMarketButton(props: {
contract: Contract
@ -18,16 +19,12 @@ export function LikeMarketButton(props: {
const { contract, user } = props
const likes = useUserLikes(user?.id)
const likedContractIds = likes
const userLikedContractIds = likes
?.filter((l) => l.type === 'contract')
.map((l) => l.id)
if (!user) return <div />
const onLike = async () => {
if (likedContractIds?.includes(contract.id)) {
await unLikeContract(user.id, contract.id)
return
}
if (!user) return firebaseLogin()
await likeContract(user, contract)
toast(`You tipped ${contract.creatorName} ${formatMoney(LIKE_TIP_AMOUNT)}!`)
}
@ -39,18 +36,19 @@ export function LikeMarketButton(props: {
color={'gray-white'}
onClick={onLike}
>
<Row className={'gap-0 sm:gap-2'}>
<Col className={'sm:flex-row sm:gap-x-2'}>
<HeartIcon
className={clsx(
'h-6 w-6',
likedContractIds?.includes(contract.id) ||
(!likes && contract.likedByUserIds?.includes(user.id))
user &&
(userLikedContractIds?.includes(contract.id) ||
(!likes && contract.likedByUserIds?.includes(user.id)))
? 'fill-red-500 text-red-500'
: ''
)}
/>
<span className={'hidden sm:block'}>Tip</span>
</Row>
Tip
</Col>
</Button>
)
}

View File

@ -12,12 +12,15 @@ import { TweetButton } from '../tweet-button'
import { DuplicateContractButton } from '../copy-contract-button'
import { Button } from '../button'
import { copyToClipboard } from 'web/lib/util/copy'
import { track } from 'web/lib/service/analytics'
import { track, withTracking } from 'web/lib/service/analytics'
import { ENV_CONFIG } from 'common/envs/constants'
import { User } from 'common/user'
import { SiteLink } from '../site-link'
import { formatMoney } from 'common/util/format'
import { REFERRAL_AMOUNT } from 'common/economy'
import { CreateChallengeModal } from 'web/components/challenges/create-challenge-modal'
import { useState } from 'react'
import { CHALLENGES_ENABLED } from 'common/challenge'
export function ShareModal(props: {
contract: Contract
@ -26,8 +29,13 @@ export function ShareModal(props: {
setOpen: (open: boolean) => void
}) {
const { contract, user, isOpen, setOpen } = props
const { outcomeType, resolution } = contract
const [openCreateChallengeModal, setOpenCreateChallengeModal] =
useState(false)
const linkIcon = <LinkIcon className="mr-2 h-6 w-6" aria-hidden="true" />
const showChallenge =
user && outcomeType === 'BINARY' && !resolution && CHALLENGES_ENABLED
const shareUrl = `https://${ENV_CONFIG.domain}${contractPath(contract)}${
user?.username && contract.creatorUsername !== user?.username
@ -46,7 +54,6 @@ export function ShareModal(props: {
</SiteLink>{' '}
if a new user signs up using the link!
</p>
<Button
size="2xl"
color="gradient"
@ -61,8 +68,31 @@ export function ShareModal(props: {
>
{linkIcon} Copy link
</Button>
<Row className="z-0 justify-start gap-4 self-center">
{showChallenge && (
<Button
size="lg"
color="gray-white"
className={'mb-2 flex max-w-xs self-center'}
onClick={withTracking(
() => setOpenCreateChallengeModal(true),
'click challenge button'
)}
>
<span> Challenge a friend</span>
<CreateChallengeModal
isOpen={openCreateChallengeModal}
setOpen={(open) => {
if (!open) {
setOpenCreateChallengeModal(false)
setOpen(false)
} else setOpenCreateChallengeModal(open)
}}
user={user}
contract={contract}
/>
</Button>
)}
<Row className="z-0 flex-wrap justify-center gap-4 self-center">
<TweetButton
className="self-start"
tweetText={getTweetText(contract, shareUrl)}

View File

@ -13,7 +13,7 @@ import { firebaseLogin, updateUser } from 'web/lib/firebase/users'
import { track } from 'web/lib/service/analytics'
import { FollowMarketModal } from 'web/components/contract/follow-market-modal'
import { useState } from 'react'
import { Row } from 'web/components/layout/row'
import { Col } from 'web/components/layout/col'
export const FollowMarketButton = (props: {
contract: Contract
@ -55,15 +55,15 @@ export const FollowMarketButton = (props: {
}}
>
{followers?.includes(user?.id ?? 'nope') ? (
<Row className={'gap-2'}>
<Col className={'items-center gap-x-2 sm:flex-row'}>
<EyeOffIcon className={clsx('h-6 w-6')} aria-hidden="true" />
Unwatch
</Row>
</Col>
) : (
<Row className={'gap-2'}>
<Col className={'items-center gap-x-2 sm:flex-row'}>
<EyeIcon className={clsx('h-6 w-6')} aria-hidden="true" />
Watch
</Row>
</Col>
)}
<FollowMarketModal
open={open}

View File

@ -11,7 +11,7 @@ function shortenName(name: string) {
const firstName = name.split(' ')[0]
const maxLength = 10
const shortName =
firstName.length >= 3
firstName.length >= 4
? firstName.length < maxLength
? firstName
: firstName.substring(0, maxLength - 3) + '...'

View File

@ -105,13 +105,7 @@ export function ContractEmbed(props: { contract: Contract; bets: Bet[] }) {
<Spacer h={3} />
<Row className="items-center justify-between gap-4 px-2">
<ContractDetails
contract={contract}
bets={bets}
isCreator={false}
user={null}
disabled
/>
<ContractDetails contract={contract} user={null} disabled />
{(isBinary || isPseudoNumeric) &&
tradingAllowed(contract) &&