Opengraph preview [WIP]

This commit is contained in:
Ian Philips 2022-07-26 12:38:16 -07:00
parent cecf696e1f
commit 8507e4e1e3
5 changed files with 83 additions and 58 deletions

View File

@ -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

View 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,
}
}

View File

@ -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,

View File

@ -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,
}
}

View File

@ -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> </>
) )
} }