Merge branch 'manifoldmarkets:main' into main
This commit is contained in:
		
						commit
						eea173a016
					
				| 
						 | 
					@ -4,8 +4,14 @@ import * as utc from 'dayjs/plugin/utc'
 | 
				
			||||||
dayjs.extend(utc)
 | 
					dayjs.extend(utc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { getPrivateUser } from './utils'
 | 
					import { getPrivateUser } from './utils'
 | 
				
			||||||
import { User } from '../../common/user'
 | 
					import { User } from 'common/user'
 | 
				
			||||||
import { sendPersonalFollowupEmail, sendWelcomeEmail } from './emails'
 | 
					import {
 | 
				
			||||||
 | 
					  sendCreatorGuideEmail,
 | 
				
			||||||
 | 
					  sendInterestingMarketsEmail,
 | 
				
			||||||
 | 
					  sendPersonalFollowupEmail,
 | 
				
			||||||
 | 
					  sendWelcomeEmail,
 | 
				
			||||||
 | 
					} from './emails'
 | 
				
			||||||
 | 
					import { getTrendingContracts } from './weekly-markets-emails'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const onCreateUser = functions
 | 
					export const onCreateUser = functions
 | 
				
			||||||
  .runWith({ secrets: ['MAILGUN_KEY'] })
 | 
					  .runWith({ secrets: ['MAILGUN_KEY'] })
 | 
				
			||||||
| 
						 | 
					@ -19,4 +25,21 @@ export const onCreateUser = functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const followupSendTime = dayjs().add(48, 'hours').toString()
 | 
					    const followupSendTime = dayjs().add(48, 'hours').toString()
 | 
				
			||||||
    await sendPersonalFollowupEmail(user, privateUser, followupSendTime)
 | 
					    await sendPersonalFollowupEmail(user, privateUser, followupSendTime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const guideSendTime = dayjs().add(96, 'hours').toString()
 | 
				
			||||||
 | 
					    await sendCreatorGuideEmail(user, privateUser, guideSendTime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // skip email if weekly email is about to go out
 | 
				
			||||||
 | 
					    const day = dayjs().utc().day()
 | 
				
			||||||
 | 
					    if (day === 0 || (day === 1 && dayjs().utc().hour() <= 19)) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const contracts = await getTrendingContracts()
 | 
				
			||||||
 | 
					    const marketsSendTime = dayjs().add(24, 'hours').toString()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await sendInterestingMarketsEmail(
 | 
				
			||||||
 | 
					      user,
 | 
				
			||||||
 | 
					      privateUser,
 | 
				
			||||||
 | 
					      contracts,
 | 
				
			||||||
 | 
					      marketsSendTime
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
import { Bet } from 'common/bet'
 | 
					import { Bet } from 'common/bet'
 | 
				
			||||||
import { Contract, CPMMBinaryContract } from 'common/contract'
 | 
					import { Contract } from 'common/contract'
 | 
				
			||||||
import { ContractComment } from 'common/comment'
 | 
					import { ContractComment } from 'common/comment'
 | 
				
			||||||
import { PAST_BETS, User } from 'common/user'
 | 
					import { PAST_BETS, User } from 'common/user'
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
| 
						 | 
					@ -11,13 +11,9 @@ import { ContractBetsTable, BetsSummary } from '../bets-list'
 | 
				
			||||||
import { Spacer } from '../layout/spacer'
 | 
					import { Spacer } from '../layout/spacer'
 | 
				
			||||||
import { Tabs } from '../layout/tabs'
 | 
					import { Tabs } from '../layout/tabs'
 | 
				
			||||||
import { Col } from '../layout/col'
 | 
					import { Col } from '../layout/col'
 | 
				
			||||||
import { tradingAllowed } from 'web/lib/firebase/contracts'
 | 
					 | 
				
			||||||
import { CommentTipMap } from 'web/hooks/use-tip-txns'
 | 
					import { CommentTipMap } from 'web/hooks/use-tip-txns'
 | 
				
			||||||
import { useComments } from 'web/hooks/use-comments'
 | 
					import { useComments } from 'web/hooks/use-comments'
 | 
				
			||||||
import { useLiquidity } from 'web/hooks/use-liquidity'
 | 
					import { useLiquidity } from 'web/hooks/use-liquidity'
 | 
				
			||||||
import { BetSignUpPrompt } from '../sign-up-prompt'
 | 
					 | 
				
			||||||
import { PlayMoneyDisclaimer } from '../play-money-disclaimer'
 | 
					 | 
				
			||||||
import BetButton from '../bet-button'
 | 
					 | 
				
			||||||
import { capitalize } from 'lodash'
 | 
					import { capitalize } from 'lodash'
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  DEV_HOUSE_LIQUIDITY_PROVIDER_ID,
 | 
					  DEV_HOUSE_LIQUIDITY_PROVIDER_ID,
 | 
				
			||||||
| 
						 | 
					@ -123,7 +119,6 @@ export function ContractTabs(props: {
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
    <Tabs
 | 
					    <Tabs
 | 
				
			||||||
      currentPageForAnalytics={'contract'}
 | 
					      currentPageForAnalytics={'contract'}
 | 
				
			||||||
      tabs={[
 | 
					      tabs={[
 | 
				
			||||||
| 
						 | 
					@ -147,20 +142,5 @@ export function ContractTabs(props: {
 | 
				
			||||||
            ]),
 | 
					            ]),
 | 
				
			||||||
      ]}
 | 
					      ]}
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
      {!user ? (
 | 
					 | 
				
			||||||
        <Col className="mt-4 max-w-sm items-center xl:hidden">
 | 
					 | 
				
			||||||
          <BetSignUpPrompt />
 | 
					 | 
				
			||||||
          <PlayMoneyDisclaimer />
 | 
					 | 
				
			||||||
        </Col>
 | 
					 | 
				
			||||||
      ) : (
 | 
					 | 
				
			||||||
        outcomeType === 'BINARY' &&
 | 
					 | 
				
			||||||
        tradingAllowed(contract) && (
 | 
					 | 
				
			||||||
          <BetButton
 | 
					 | 
				
			||||||
            contract={contract as CPMMBinaryContract}
 | 
					 | 
				
			||||||
            className="mb-2 !mt-0 xl:hidden"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,6 @@ import clsx from 'clsx'
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  ContractCommentInput,
 | 
					  ContractCommentInput,
 | 
				
			||||||
  FeedComment,
 | 
					  FeedComment,
 | 
				
			||||||
  getMostRecentCommentableBet,
 | 
					 | 
				
			||||||
} from 'web/components/feed/feed-comments'
 | 
					} from 'web/components/feed/feed-comments'
 | 
				
			||||||
import { CopyLinkDateTimeComponent } from 'web/components/feed/copy-link-date-time'
 | 
					import { CopyLinkDateTimeComponent } from 'web/components/feed/copy-link-date-time'
 | 
				
			||||||
import { useRouter } from 'next/router'
 | 
					import { useRouter } from 'next/router'
 | 
				
			||||||
| 
						 | 
					@ -49,28 +48,6 @@ export function FeedAnswerCommentGroup(props: {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const answerElementId = `answer-${answer.id}`
 | 
					  const answerElementId = `answer-${answer.id}`
 | 
				
			||||||
  const commentsByCurrentUser = (user && commentsByUserId[user.id]) ?? []
 | 
					  const commentsByCurrentUser = (user && commentsByUserId[user.id]) ?? []
 | 
				
			||||||
  const isFreeResponseContractPage = !!commentsByCurrentUser
 | 
					 | 
				
			||||||
  const mostRecentCommentableBet = getMostRecentCommentableBet(
 | 
					 | 
				
			||||||
    betsByCurrentUser,
 | 
					 | 
				
			||||||
    commentsByCurrentUser,
 | 
					 | 
				
			||||||
    user,
 | 
					 | 
				
			||||||
    answer.number.toString()
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  const [usersMostRecentBetTimeAtLoad, setUsersMostRecentBetTimeAtLoad] =
 | 
					 | 
				
			||||||
    useState<number | undefined>(
 | 
					 | 
				
			||||||
      !user ? undefined : mostRecentCommentableBet?.createdTime ?? 0
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (user && usersMostRecentBetTimeAtLoad === undefined)
 | 
					 | 
				
			||||||
      setUsersMostRecentBetTimeAtLoad(
 | 
					 | 
				
			||||||
        mostRecentCommentableBet?.createdTime ?? 0
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
  }, [
 | 
					 | 
				
			||||||
    mostRecentCommentableBet?.createdTime,
 | 
					 | 
				
			||||||
    user,
 | 
					 | 
				
			||||||
    usersMostRecentBetTimeAtLoad,
 | 
					 | 
				
			||||||
  ])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const scrollAndOpenReplyInput = useEvent(
 | 
					  const scrollAndOpenReplyInput = useEvent(
 | 
				
			||||||
    (comment?: ContractComment, answer?: Answer) => {
 | 
					    (comment?: ContractComment, answer?: Answer) => {
 | 
				
			||||||
| 
						 | 
					@ -85,19 +62,6 @@ export function FeedAnswerCommentGroup(props: {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    // Only show one comment input for a bet at a time
 | 
					 | 
				
			||||||
    if (
 | 
					 | 
				
			||||||
      betsByCurrentUser.length > 1 &&
 | 
					 | 
				
			||||||
      // inputRef?.textContent?.length === 0 && //TODO: editor.isEmpty
 | 
					 | 
				
			||||||
      betsByCurrentUser.sort((a, b) => b.createdTime - a.createdTime)[0]
 | 
					 | 
				
			||||||
        ?.outcome !== answer.number.toString()
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
      setShowReply(false)
 | 
					 | 
				
			||||||
    // Even if we pass memoized bets this still runs on every render, which we don't want
 | 
					 | 
				
			||||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
					 | 
				
			||||||
  }, [betsByCurrentUser.length, user, answer.number])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (router.asPath.endsWith(`#${answerElementId}`)) {
 | 
					    if (router.asPath.endsWith(`#${answerElementId}`)) {
 | 
				
			||||||
      setHighlighted(true)
 | 
					      setHighlighted(true)
 | 
				
			||||||
| 
						 | 
					@ -105,10 +69,7 @@ export function FeedAnswerCommentGroup(props: {
 | 
				
			||||||
  }, [answerElementId, router.asPath])
 | 
					  }, [answerElementId, router.asPath])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Col
 | 
					    <Col className="relative flex-1 items-stretch gap-3">
 | 
				
			||||||
      className={'relative flex-1 items-stretch gap-3'}
 | 
					 | 
				
			||||||
      key={answer.id + 'comment'}
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <Row
 | 
					      <Row
 | 
				
			||||||
        className={clsx(
 | 
					        className={clsx(
 | 
				
			||||||
          'gap-3 space-x-3 pt-4 transition-all duration-1000',
 | 
					          'gap-3 space-x-3 pt-4 transition-all duration-1000',
 | 
				
			||||||
| 
						 | 
					@ -133,28 +94,23 @@ export function FeedAnswerCommentGroup(props: {
 | 
				
			||||||
            <span className="whitespace-pre-line text-lg">
 | 
					            <span className="whitespace-pre-line text-lg">
 | 
				
			||||||
              <Linkify text={text} />
 | 
					              <Linkify text={text} />
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
 | 
					            <div className="sm:hidden">
 | 
				
			||||||
            {isFreeResponseContractPage && (
 | 
					 | 
				
			||||||
              <div className={'sm:hidden'}>
 | 
					 | 
				
			||||||
              <button
 | 
					              <button
 | 
				
			||||||
                  className={'text-xs font-bold text-gray-500 hover:underline'}
 | 
					                className="text-xs font-bold text-gray-500 hover:underline"
 | 
				
			||||||
                onClick={() => scrollAndOpenReplyInput(undefined, answer)}
 | 
					                onClick={() => scrollAndOpenReplyInput(undefined, answer)}
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                Reply
 | 
					                Reply
 | 
				
			||||||
              </button>
 | 
					              </button>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </Col>
 | 
					          </Col>
 | 
				
			||||||
          {isFreeResponseContractPage && (
 | 
					          <div className="justify-initial hidden sm:block">
 | 
				
			||||||
            <div className={'justify-initial hidden sm:block'}>
 | 
					 | 
				
			||||||
            <button
 | 
					            <button
 | 
				
			||||||
                className={'text-xs font-bold text-gray-500 hover:underline'}
 | 
					              className="text-xs font-bold text-gray-500 hover:underline"
 | 
				
			||||||
              onClick={() => scrollAndOpenReplyInput(undefined, answer)}
 | 
					              onClick={() => scrollAndOpenReplyInput(undefined, answer)}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              Reply
 | 
					              Reply
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </Col>
 | 
					        </Col>
 | 
				
			||||||
      </Row>
 | 
					      </Row>
 | 
				
			||||||
      <Col className="gap-3 pl-1">
 | 
					      <Col className="gap-3 pl-1">
 | 
				
			||||||
| 
						 | 
					@ -170,7 +126,7 @@ export function FeedAnswerCommentGroup(props: {
 | 
				
			||||||
        ))}
 | 
					        ))}
 | 
				
			||||||
      </Col>
 | 
					      </Col>
 | 
				
			||||||
      {showReply && (
 | 
					      {showReply && (
 | 
				
			||||||
        <div className={'relative ml-7'}>
 | 
					        <div className="relative ml-7">
 | 
				
			||||||
          <span
 | 
					          <span
 | 
				
			||||||
            className="absolute -left-1 -ml-[1px] mt-[1.25rem] h-2 w-0.5 rotate-90 bg-gray-200"
 | 
					            className="absolute -left-1 -ml-[1px] mt-[1.25rem] h-2 w-0.5 rotate-90 bg-gray-200"
 | 
				
			||||||
            aria-hidden="true"
 | 
					            aria-hidden="true"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,8 @@ import { Col } from './layout/col'
 | 
				
			||||||
import { track } from 'web/lib/service/analytics'
 | 
					import { track } from 'web/lib/service/analytics'
 | 
				
			||||||
import { InfoTooltip } from './info-tooltip'
 | 
					import { InfoTooltip } from './info-tooltip'
 | 
				
			||||||
import { BETTORS, PRESENT_BET } from 'common/user'
 | 
					import { BETTORS, PRESENT_BET } from 'common/user'
 | 
				
			||||||
 | 
					import { buildArray } from 'common/util/array'
 | 
				
			||||||
 | 
					import { useAdmin } from 'web/hooks/use-admin'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function LiquidityPanel(props: { contract: CPMMContract }) {
 | 
					export function LiquidityPanel(props: { contract: CPMMContract }) {
 | 
				
			||||||
  const { contract } = props
 | 
					  const { contract } = props
 | 
				
			||||||
| 
						 | 
					@ -28,16 +30,19 @@ export function LiquidityPanel(props: { contract: CPMMContract }) {
 | 
				
			||||||
      setShowWithdrawal(true)
 | 
					      setShowWithdrawal(true)
 | 
				
			||||||
  }, [showWithdrawal, lpShares])
 | 
					  }, [showWithdrawal, lpShares])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const isCreator = user?.id === contract.creatorId
 | 
				
			||||||
 | 
					  const isAdmin = useAdmin()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!showWithdrawal && !isAdmin && !isCreator) return <></>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Tabs
 | 
					    <Tabs
 | 
				
			||||||
      tabs={[
 | 
					      tabs={buildArray(
 | 
				
			||||||
        {
 | 
					        (isCreator || isAdmin) && {
 | 
				
			||||||
          title: 'Subsidize',
 | 
					          title: (isAdmin ? '[Admin] ' : '') + 'Subsidize',
 | 
				
			||||||
          content: <AddLiquidityPanel contract={contract} />,
 | 
					          content: <AddLiquidityPanel contract={contract} />,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        ...(showWithdrawal
 | 
					        showWithdrawal && {
 | 
				
			||||||
          ? [
 | 
					 | 
				
			||||||
              {
 | 
					 | 
				
			||||||
          title: 'Withdraw',
 | 
					          title: 'Withdraw',
 | 
				
			||||||
          content: (
 | 
					          content: (
 | 
				
			||||||
            <WithdrawLiquidityPanel
 | 
					            <WithdrawLiquidityPanel
 | 
				
			||||||
| 
						 | 
					@ -46,13 +51,11 @@ export function LiquidityPanel(props: { contract: CPMMContract }) {
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
          : []),
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          title: 'Pool',
 | 
					          title: 'Pool',
 | 
				
			||||||
          content: <ViewLiquidityPanel contract={contract} />,
 | 
					          content: <ViewLiquidityPanel contract={contract} />,
 | 
				
			||||||
        },
 | 
					        }
 | 
				
			||||||
      ]}
 | 
					      )}
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,10 @@ import { ContractsGrid } from 'web/components/contract/contracts-grid'
 | 
				
			||||||
import { Title } from 'web/components/title'
 | 
					import { Title } from 'web/components/title'
 | 
				
			||||||
import { usePrefetch } from 'web/hooks/use-prefetch'
 | 
					import { usePrefetch } from 'web/hooks/use-prefetch'
 | 
				
			||||||
import { useAdmin } from 'web/hooks/use-admin'
 | 
					import { useAdmin } from 'web/hooks/use-admin'
 | 
				
			||||||
 | 
					import { BetSignUpPrompt } from 'web/components/sign-up-prompt'
 | 
				
			||||||
 | 
					import { PlayMoneyDisclaimer } from 'web/components/play-money-disclaimer'
 | 
				
			||||||
 | 
					import BetButton from 'web/components/bet-button'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dayjs from 'dayjs'
 | 
					import dayjs from 'dayjs'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getStaticProps = fromPropz(getStaticPropz)
 | 
					export const getStaticProps = fromPropz(getStaticPropz)
 | 
				
			||||||
| 
						 | 
					@ -205,18 +209,6 @@ export function ContractPageContent(
 | 
				
			||||||
    setShowConfetti(shouldSeeConfetti)
 | 
					    setShowConfetti(shouldSeeConfetti)
 | 
				
			||||||
  }, [contract, user])
 | 
					  }, [contract, user])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [recommendedContracts, setRecommendedContracts] = useState<Contract[]>(
 | 
					 | 
				
			||||||
    []
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (contract && user) {
 | 
					 | 
				
			||||||
      getRecommendedContracts(contract, user.id, 6).then(
 | 
					 | 
				
			||||||
        setRecommendedContracts
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
					 | 
				
			||||||
  }, [contract.id, user?.id])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const { isResolved, question, outcomeType } = contract
 | 
					  const { isResolved, question, outcomeType } = contract
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const allowTrade = tradingAllowed(contract)
 | 
					  const allowTrade = tradingAllowed(contract)
 | 
				
			||||||
| 
						 | 
					@ -300,17 +292,46 @@ export function ContractPageContent(
 | 
				
			||||||
          tips={tips}
 | 
					          tips={tips}
 | 
				
			||||||
          comments={comments}
 | 
					          comments={comments}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					        {!user ? (
 | 
				
			||||||
 | 
					          <Col className="mt-4 max-w-sm items-center xl:hidden">
 | 
				
			||||||
 | 
					            <BetSignUpPrompt />
 | 
				
			||||||
 | 
					            <PlayMoneyDisclaimer />
 | 
				
			||||||
          </Col>
 | 
					          </Col>
 | 
				
			||||||
 | 
					        ) : (
 | 
				
			||||||
      {recommendedContracts.length > 0 && (
 | 
					          outcomeType === 'BINARY' &&
 | 
				
			||||||
        <Col className="mt-2 gap-2 px-2 sm:px-0">
 | 
					          allowTrade && (
 | 
				
			||||||
          <Title className="text-gray-700" text="Recommended" />
 | 
					            <BetButton
 | 
				
			||||||
          <ContractsGrid
 | 
					              contract={contract as CPMMBinaryContract}
 | 
				
			||||||
            contracts={recommendedContracts}
 | 
					              className="mb-2 !mt-0 xl:hidden"
 | 
				
			||||||
            trackingPostfix=" recommended"
 | 
					 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
        </Col>
 | 
					          )
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
 | 
					      </Col>
 | 
				
			||||||
 | 
					      <RecommendedContractsWidget contract={contract} />
 | 
				
			||||||
    </Page>
 | 
					    </Page>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function RecommendedContractsWidget(props: { contract: Contract }) {
 | 
				
			||||||
 | 
					  const { contract } = props
 | 
				
			||||||
 | 
					  const user = useUser()
 | 
				
			||||||
 | 
					  const [recommendations, setRecommendations] = useState<Contract[]>([])
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (user) {
 | 
				
			||||||
 | 
					      getRecommendedContracts(contract, user.id, 6).then(setRecommendations)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
				
			||||||
 | 
					  }, [contract.id, user?.id])
 | 
				
			||||||
 | 
					  if (recommendations.length === 0) {
 | 
				
			||||||
 | 
					    return null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Col className="mt-2 gap-2 px-2 sm:px-0">
 | 
				
			||||||
 | 
					      <Title className="text-gray-700" text="Recommended" />
 | 
				
			||||||
 | 
					      <ContractsGrid
 | 
				
			||||||
 | 
					        contracts={recommendations}
 | 
				
			||||||
 | 
					        trackingPostfix=" recommended"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </Col>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user