Opengraph preview [WIP]
This commit is contained in:
parent
cecf696e1f
commit
8507e4e1e3
|
@ -6,6 +6,8 @@ export type Challenge = {
|
||||||
// The user that created the challenge.
|
// The user that created the challenge.
|
||||||
creatorId: string
|
creatorId: string
|
||||||
creatorUsername: string
|
creatorUsername: string
|
||||||
|
creatorName: string
|
||||||
|
creatorAvatarUrl?: string
|
||||||
|
|
||||||
// Displayed to people claiming the challenge
|
// Displayed to people claiming the challenge
|
||||||
message: string
|
message: string
|
||||||
|
|
36
web/components/contract/contract-card-preview.tsx
Normal file
36
web/components/contract/contract-card-preview.tsx
Normal file
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
import {
|
import {
|
||||||
collectionGroup,
|
collectionGroup,
|
||||||
|
doc,
|
||||||
orderBy,
|
orderBy,
|
||||||
query,
|
query,
|
||||||
setDoc,
|
setDoc,
|
||||||
where,
|
where,
|
||||||
} from 'firebase/firestore'
|
} from 'firebase/firestore'
|
||||||
import { doc } from 'firebase/firestore'
|
|
||||||
import { Challenge } from 'common/challenge'
|
import { Challenge } from 'common/challenge'
|
||||||
import { customAlphabet } from 'nanoid'
|
import { customAlphabet } from 'nanoid'
|
||||||
import { coll, listenForValue, listenForValues } from './utils'
|
import { coll, listenForValue, listenForValues } from './utils'
|
||||||
|
@ -46,6 +46,8 @@ export async function createChallenge(data: {
|
||||||
slug,
|
slug,
|
||||||
creatorId: creator.id,
|
creatorId: creator.id,
|
||||||
creatorUsername: creator.username,
|
creatorUsername: creator.username,
|
||||||
|
creatorName: creator.name,
|
||||||
|
creatorAvatarUrl: creator.avatarUrl,
|
||||||
creatorAmount: amount,
|
creatorAmount: amount,
|
||||||
contractSlug: contract.slug,
|
contractSlug: contract.slug,
|
||||||
contractId: contract.id,
|
contractId: contract.id,
|
||||||
|
|
|
@ -13,7 +13,6 @@ import { Spacer } from 'web/components/layout/spacer'
|
||||||
import { listUsers, User } from 'web/lib/firebase/users'
|
import { listUsers, User } from 'web/lib/firebase/users'
|
||||||
import {
|
import {
|
||||||
Contract,
|
Contract,
|
||||||
getBinaryProbPercent,
|
|
||||||
getContractFromSlug,
|
getContractFromSlug,
|
||||||
tradingAllowed,
|
tradingAllowed,
|
||||||
} from 'web/lib/firebase/contracts'
|
} from 'web/lib/firebase/contracts'
|
||||||
|
@ -28,7 +27,6 @@ import { Leaderboard } from 'web/components/leaderboard'
|
||||||
import { resolvedPayout } from 'common/calculate'
|
import { resolvedPayout } from 'common/calculate'
|
||||||
import { formatMoney } from 'common/util/format'
|
import { formatMoney } from 'common/util/format'
|
||||||
import { ContractTabs } from 'web/components/contract/contract-tabs'
|
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 { useWindowSize } from 'web/hooks/use-window-size'
|
||||||
import Confetti from 'react-confetti'
|
import Confetti from 'react-confetti'
|
||||||
import { NumericBetPanel } from '../../components/numeric-bet-panel'
|
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 { useTracking } from 'web/hooks/use-tracking'
|
||||||
import { CommentTipMap, useTipTxns } from 'web/hooks/use-tip-txns'
|
import { CommentTipMap, useTipTxns } from 'web/hooks/use-tip-txns'
|
||||||
import { useLiquidity } from 'web/hooks/use-liquidity'
|
import { useLiquidity } from 'web/hooks/use-liquidity'
|
||||||
import { richTextToString } from 'common/util/parse'
|
|
||||||
import { useSaveReferral } from 'web/hooks/use-save-referral'
|
import { useSaveReferral } from 'web/hooks/use-save-referral'
|
||||||
|
import { getOpenGraphProps } from 'web/components/contract/contract-card-preview'
|
||||||
|
|
||||||
export const getStaticProps = fromPropz(getStaticPropz)
|
export const getStaticProps = fromPropz(getStaticPropz)
|
||||||
export async function getStaticPropz(props: {
|
export async function getStaticPropz(props: {
|
||||||
|
@ -383,35 +381,3 @@ function ContractTopTrades(props: {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { Spacer } from 'web/components/layout/spacer'
|
||||||
import { Row } from 'web/components/layout/row'
|
import { Row } from 'web/components/layout/row'
|
||||||
|
|
||||||
import { Challenge } from 'common/challenge'
|
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 { getPortfolioHistory, getUserByUsername } from 'web/lib/firebase/users'
|
||||||
import { PortfolioMetrics, User } from 'common/user'
|
import { PortfolioMetrics, User } from 'common/user'
|
||||||
import { Page } from 'web/components/page'
|
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 { AcceptChallengeButton } from 'web/components/challenges/accept-challenge-button'
|
||||||
import { Avatar } from 'web/components/avatar'
|
import { Avatar } from 'web/components/avatar'
|
||||||
import { UserLink } from 'web/components/user-page'
|
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 { BinaryOutcomeLabel } from 'web/components/outcome-label'
|
||||||
import { formatMoney } from 'common/util/format'
|
import { formatMoney } from 'common/util/format'
|
||||||
import { last } from 'lodash'
|
import { last } from 'lodash'
|
||||||
|
@ -33,6 +33,9 @@ import {
|
||||||
PseudoNumericResolutionOrExpectation,
|
PseudoNumericResolutionOrExpectation,
|
||||||
} from 'web/components/contract/contract-card'
|
} from 'web/components/contract/contract-card'
|
||||||
import { ContractProbGraph } from 'web/components/contract/contract-prob-graph'
|
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 const getStaticProps = fromPropz(getStaticPropz)
|
||||||
export async function getStaticPropz(props: {
|
export async function getStaticPropz(props: {
|
||||||
params: { username: string; contractSlug: string; challengeSlug: string }
|
params: { username: string; contractSlug: string; challengeSlug: string }
|
||||||
|
@ -88,16 +91,30 @@ export default function ChallengePage(props: {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (challenge.acceptances.length >= challenge.maxUses)
|
const ogCardProps = getOpenGraphProps(contract)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Page>
|
||||||
|
{ogCardProps && (
|
||||||
|
<SEO
|
||||||
|
title={
|
||||||
|
challenge.creatorName.split(' ')[0] +
|
||||||
|
' challenges you to a duel on: ' +
|
||||||
|
contract.question
|
||||||
|
}
|
||||||
|
description={ogCardProps.description}
|
||||||
|
url={getChallengeUrl(challenge)}
|
||||||
|
ogCardProps={ogCardProps}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{challenge.acceptances.length >= challenge.maxUses ? (
|
||||||
<ClosedChallengeContent
|
<ClosedChallengeContent
|
||||||
contract={contract}
|
contract={contract}
|
||||||
challenge={challenge}
|
challenge={challenge}
|
||||||
creator={user}
|
creator={user}
|
||||||
bets={bets}
|
bets={bets}
|
||||||
/>
|
/>
|
||||||
)
|
) : (
|
||||||
return (
|
|
||||||
<OpenChallengeContent
|
<OpenChallengeContent
|
||||||
user={currentUser}
|
user={currentUser}
|
||||||
contract={contract}
|
contract={contract}
|
||||||
|
@ -105,6 +122,8 @@ export default function ChallengePage(props: {
|
||||||
creator={user}
|
creator={user}
|
||||||
bets={bets}
|
bets={bets}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</Page>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +223,7 @@ function ClosedChallengeContent(props: {
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Page>
|
<>
|
||||||
{showConfetti && (
|
{showConfetti && (
|
||||||
<Confetti
|
<Confetti
|
||||||
width={width ?? 500}
|
width={width ?? 500}
|
||||||
|
@ -264,7 +283,7 @@ function ClosedChallengeContent(props: {
|
||||||
<Spacer h={3} />
|
<Spacer h={3} />
|
||||||
<ChallengeContract contract={contract} bets={bets} />
|
<ChallengeContract contract={contract} bets={bets} />
|
||||||
</Col>
|
</Col>
|
||||||
</Page>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +409,7 @@ function OpenChallengeContent(props: {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Page>
|
<>
|
||||||
<Col
|
<Col
|
||||||
ref={setContainerRef}
|
ref={setContainerRef}
|
||||||
style={{ height: remainingHeight }}
|
style={{ height: remainingHeight }}
|
||||||
|
@ -437,6 +456,6 @@ function OpenChallengeContent(props: {
|
||||||
/>
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
</Page>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user