diff --git a/common/challenge.ts b/common/challenge.ts index 5900743a..561a0a85 100644 --- a/common/challenge.ts +++ b/common/challenge.ts @@ -6,6 +6,8 @@ export type Challenge = { // The user that created the challenge. creatorId: string creatorUsername: string + creatorName: string + creatorAvatarUrl?: string // Displayed to people claiming the challenge message: string diff --git a/web/components/contract/contract-card-preview.tsx b/web/components/contract/contract-card-preview.tsx new file mode 100644 index 00000000..da46a55a --- /dev/null +++ b/web/components/contract/contract-card-preview.tsx @@ -0,0 +1,36 @@ +import { Contract } from 'common/lib/contract' +import { getBinaryProbPercent } from 'web/lib/firebase/contracts' +import { richTextToString } from 'common/lib/util/parse' +import { contractTextDetails } from 'web/components/contract/contract-details' + +export const getOpenGraphProps = (contract: Contract) => { + const { + resolution, + question, + creatorName, + creatorUsername, + outcomeType, + creatorAvatarUrl, + description: desc, + } = contract + const probPercent = + outcomeType === 'BINARY' ? getBinaryProbPercent(contract) : undefined + + const stringDesc = typeof desc === 'string' ? desc : richTextToString(desc) + + const description = resolution + ? `Resolved ${resolution}. ${stringDesc}` + : probPercent + ? `${probPercent} chance. ${stringDesc}` + : stringDesc + + return { + question, + probability: probPercent, + metadata: contractTextDetails(contract), + creatorName, + creatorUsername, + creatorAvatarUrl, + description, + } +} diff --git a/web/lib/firebase/challenges.ts b/web/lib/firebase/challenges.ts index 9a3e1972..c3931173 100644 --- a/web/lib/firebase/challenges.ts +++ b/web/lib/firebase/challenges.ts @@ -1,11 +1,11 @@ import { collectionGroup, + doc, orderBy, query, setDoc, where, } from 'firebase/firestore' -import { doc } from 'firebase/firestore' import { Challenge } from 'common/challenge' import { customAlphabet } from 'nanoid' import { coll, listenForValue, listenForValues } from './utils' @@ -46,6 +46,8 @@ export async function createChallenge(data: { slug, creatorId: creator.id, creatorUsername: creator.username, + creatorName: creator.name, + creatorAvatarUrl: creator.avatarUrl, creatorAmount: amount, contractSlug: contract.slug, contractId: contract.id, diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx index ea3d5529..38877819 100644 --- a/web/pages/[username]/[contractSlug].tsx +++ b/web/pages/[username]/[contractSlug].tsx @@ -13,7 +13,6 @@ import { Spacer } from 'web/components/layout/spacer' import { listUsers, User } from 'web/lib/firebase/users' import { Contract, - getBinaryProbPercent, getContractFromSlug, tradingAllowed, } from 'web/lib/firebase/contracts' @@ -28,7 +27,6 @@ import { Leaderboard } from 'web/components/leaderboard' import { resolvedPayout } from 'common/calculate' import { formatMoney } from 'common/util/format' import { ContractTabs } from 'web/components/contract/contract-tabs' -import { contractTextDetails } from 'web/components/contract/contract-details' import { useWindowSize } from 'web/hooks/use-window-size' import Confetti from 'react-confetti' import { NumericBetPanel } from '../../components/numeric-bet-panel' @@ -43,8 +41,8 @@ import { AlertBox } from 'web/components/alert-box' import { useTracking } from 'web/hooks/use-tracking' import { CommentTipMap, useTipTxns } from 'web/hooks/use-tip-txns' import { useLiquidity } from 'web/hooks/use-liquidity' -import { richTextToString } from 'common/util/parse' import { useSaveReferral } from 'web/hooks/use-save-referral' +import { getOpenGraphProps } from 'web/components/contract/contract-card-preview' export const getStaticProps = fromPropz(getStaticPropz) export async function getStaticPropz(props: { @@ -383,35 +381,3 @@ function ContractTopTrades(props: { ) } - -const getOpenGraphProps = (contract: Contract) => { - const { - resolution, - question, - creatorName, - creatorUsername, - outcomeType, - creatorAvatarUrl, - description: desc, - } = contract - const probPercent = - outcomeType === 'BINARY' ? getBinaryProbPercent(contract) : undefined - - const stringDesc = typeof desc === 'string' ? desc : richTextToString(desc) - - const description = resolution - ? `Resolved ${resolution}. ${stringDesc}` - : probPercent - ? `${probPercent} chance. ${stringDesc}` - : stringDesc - - return { - question, - probability: probPercent, - metadata: contractTextDetails(contract), - creatorName, - creatorUsername, - creatorAvatarUrl, - description, - } -} diff --git a/web/pages/challenges/[username]/[contractSlug]/[challengeSlug].tsx b/web/pages/challenges/[username]/[contractSlug]/[challengeSlug].tsx index 99008b15..1c454b36 100644 --- a/web/pages/challenges/[username]/[contractSlug]/[challengeSlug].tsx +++ b/web/pages/challenges/[username]/[contractSlug]/[challengeSlug].tsx @@ -12,7 +12,7 @@ import { Spacer } from 'web/components/layout/spacer' import { Row } from 'web/components/layout/row' import { Challenge } from 'common/challenge' -import { useChallenge } from 'web/lib/firebase/challenges' +import { getChallengeUrl, useChallenge } from 'web/lib/firebase/challenges' import { getPortfolioHistory, getUserByUsername } from 'web/lib/firebase/users' import { PortfolioMetrics, User } from 'common/user' import { Page } from 'web/components/page' @@ -20,7 +20,7 @@ import { useUser, useUserById } from 'web/hooks/use-user' import { AcceptChallengeButton } from 'web/components/challenges/accept-challenge-button' import { Avatar } from 'web/components/avatar' import { UserLink } from 'web/components/user-page' -import { useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' import { BinaryOutcomeLabel } from 'web/components/outcome-label' import { formatMoney } from 'common/util/format' import { last } from 'lodash' @@ -33,6 +33,9 @@ import { PseudoNumericResolutionOrExpectation, } from 'web/components/contract/contract-card' import { ContractProbGraph } from 'web/components/contract/contract-prob-graph' +import { SEO } from 'web/components/SEO' +import { getOpenGraphProps } from 'web/components/contract/contract-card-preview' + export const getStaticProps = fromPropz(getStaticPropz) export async function getStaticPropz(props: { params: { username: string; contractSlug: string; challengeSlug: string } @@ -88,23 +91,39 @@ export default function ChallengePage(props: { ) } - if (challenge.acceptances.length >= challenge.maxUses) - return ( - - ) + const ogCardProps = getOpenGraphProps(contract) + return ( - + + {ogCardProps && ( + + )} + {challenge.acceptances.length >= challenge.maxUses ? ( + + ) : ( + + )} + ) } @@ -204,7 +223,7 @@ function ClosedChallengeContent(props: { ) return ( - + <> {showConfetti && ( - + ) } @@ -390,7 +409,7 @@ function OpenChallengeContent(props: { ) } return ( - + <> - + ) }