Add folds links in market, hide tags behind Show tags toggle.

This commit is contained in:
James Grugett 2022-02-01 12:06:42 -06:00
parent 79c5472c11
commit 565ded1063
6 changed files with 124 additions and 17 deletions

View File

@ -18,16 +18,19 @@ import { ContractFeed } from './contract-feed'
import { TweetButton } from './tweet-button' import { TweetButton } from './tweet-button'
import { Bet } from '../../common/bet' import { Bet } from '../../common/bet'
import { Comment } from '../../common/comment' import { Comment } from '../../common/comment'
import { TagsInput } from './tags-input' import { RevealableTagsInput } from './tags-input'
import BetRow from './bet-row' import BetRow from './bet-row'
import { Fold } from '../../common/fold'
import { FoldTagList } from './tags-list'
export const ContractOverview = (props: { export const ContractOverview = (props: {
contract: Contract contract: Contract
bets: Bet[] bets: Bet[]
comments: Comment[] comments: Comment[]
folds: Fold[]
className?: string className?: string
}) => { }) => {
const { contract, bets, comments, className } = props const { contract, bets, comments, folds, className } = props
const { resolution, creatorId, creatorName } = contract const { resolution, creatorId, creatorName } = contract
const { probPercent, truePool } = contractMetrics(contract) const { probPercent, truePool } = contractMetrics(contract)
@ -85,11 +88,21 @@ export const ContractOverview = (props: {
<ContractProbGraph contract={contract} /> <ContractProbGraph contract={contract} />
<Row className="justify-between mt-6 ml-4 gap-4"> <Row className="hidden sm:flex justify-between items-center mt-6 ml-4 gap-4">
<TagsInput contract={contract} /> <FoldTagList folds={folds} />
<TweetButton tweetText={tweetText} /> <TweetButton tweetText={tweetText} />
</Row> </Row>
<Col className="sm:hidden mt-6 ml-4 gap-4">
<TweetButton className="self-end" tweetText={tweetText} />
<FoldTagList folds={folds} />
</Col>
<RevealableTagsInput
className={clsx('mx-4', folds.length > 0 && 'mt-4')}
contract={contract}
/>
<Spacer h={12} /> <Spacer h={12} />
{/* Show a delete button for contracts without any trading */} {/* Show a delete button for contracts without any trading */}

View File

@ -0,0 +1,17 @@
import clsx from 'clsx'
import { Fold } from '../../common/fold'
export function FoldTag(props: { fold: Fold }) {
const { fold } = props
const { name } = fold
return (
<div
className={clsx(
'bg-white hover:bg-gray-100 px-4 py-2 rounded-full shadow-md',
'cursor-pointer'
)}
>
<span className="text-gray-500">{name}</span>
</div>
)
}

View File

@ -1,11 +1,13 @@
import clsx from 'clsx'
import { useState } from 'react' import { useState } from 'react'
import { parseWordsAsTags } from '../../common/util/parse' import { parseWordsAsTags } from '../../common/util/parse'
import { Contract, updateContract } from '../lib/firebase/contracts' import { Contract, updateContract } from '../lib/firebase/contracts'
import { Col } from './layout/col'
import { Row } from './layout/row' import { Row } from './layout/row'
import { TagsList } from './tags-list' import { CompactTagsList } from './tags-list'
export function TagsInput(props: { contract: Contract }) { export function TagsInput(props: { contract: Contract; className?: string }) {
const { contract } = props const { contract, className } = props
const { tags } = contract const { tags } = contract
const [tagText, setTagText] = useState('') const [tagText, setTagText] = useState('')
@ -24,8 +26,8 @@ export function TagsInput(props: { contract: Contract }) {
} }
return ( return (
<Row className="flex-wrap gap-4"> <Col className={clsx('gap-4', className)}>
<TagsList tags={newTags.map((tag) => `#${tag}`)} /> <CompactTagsList tags={newTags.map((tag) => `#${tag}`)} />
<Row className="items-center gap-4"> <Row className="items-center gap-4">
<input <input
@ -40,6 +42,28 @@ export function TagsInput(props: { contract: Contract }) {
Save tags Save tags
</button> </button>
</Row> </Row>
</Row> </Col>
) )
} }
export function RevealableTagsInput(props: {
contract: Contract
className?: string
}) {
const { contract, className } = props
const [hidden, setHidden] = useState(true)
if (hidden)
return (
<div
className={clsx(
'text-gray-500 cursor-pointer hover:underline hover:decoration-indigo-400 hover:decoration-2',
className
)}
onClick={() => setHidden((hidden) => !hidden)}
>
Show tags
</div>
)
return <TagsInput className={clsx('pt-2', className)} contract={contract} />
}

View File

@ -2,6 +2,7 @@ import clsx from 'clsx'
import { Row } from './layout/row' import { Row } from './layout/row'
import { Linkify } from './linkify' import { Linkify } from './linkify'
import { SiteLink } from './site-link' import { SiteLink } from './site-link'
import { Fold } from '../../common/fold'
export function Hashtag(props: { tag: string; noLink?: boolean }) { export function Hashtag(props: { tag: string; noLink?: boolean }) {
const { tag, noLink } = props const { tag, noLink } = props
@ -51,3 +52,36 @@ export function CompactTagsList(props: { tags: string[] }) {
</Row> </Row>
) )
} }
export function FoldTag(props: { fold: Fold }) {
const { fold } = props
const { name } = fold
return (
<SiteLink href={`/fold/${fold.slug}`} className="flex items-center">
<div
className={clsx(
'bg-indigo-50 px-4 py-2 rounded-full shadow-md',
'cursor-pointer'
)}
>
<span className="text-gray-500 text-sm">{name}</span>
</div>
</SiteLink>
)
}
export function FoldTagList(props: { folds: Fold[]; className?: string }) {
const { folds, className } = props
return (
<Row className={clsx('flex-wrap gap-2 items-center', className)}>
{folds.length > 0 && (
<>
<div className="text-gray-500 mr-1">Communities</div>
{folds.map((fold) => (
<FoldTag key={fold.id} fold={fold} />
))}
</>
)}
</Row>
)
}

View File

@ -131,3 +131,13 @@ export function listenForFollow(
setFollow(!!value) setFollow(!!value)
}) })
} }
export function getFoldsByTags(tags: string[]) {
if (tags.length === 0) return []
const lowercaseTags = tags.map((tag) => tag)
return getValues<Fold>(
// TODO: split into multiple queries if tags.length > 10.
query(foldCollection, where('tags', 'array-contains-any', lowercaseTags))
)
}

View File

@ -23,6 +23,8 @@ import { contractTextDetails } from '../../components/contract-card'
import { Bet, listAllBets } from '../../lib/firebase/bets' import { Bet, listAllBets } from '../../lib/firebase/bets'
import { Comment, listAllComments } from '../../lib/firebase/comments' import { Comment, listAllComments } from '../../lib/firebase/comments'
import Custom404 from '../404' import Custom404 from '../404'
import { getFoldsByTags } from '../../lib/firebase/folds'
import { Fold } from '../../../common/fold'
export async function getStaticProps(props: { export async function getStaticProps(props: {
params: { username: string; contractSlug: string } params: { username: string; contractSlug: string }
@ -31,18 +33,23 @@ export async function getStaticProps(props: {
const contract = (await getContractFromSlug(contractSlug)) || null const contract = (await getContractFromSlug(contractSlug)) || null
const contractId = contract?.id const contractId = contract?.id
const foldsPromise = getFoldsByTags(contract?.tags ?? [])
const [bets, comments] = await Promise.all([ const [bets, comments] = await Promise.all([
contractId ? listAllBets(contractId) : null, contractId ? listAllBets(contractId) : [],
contractId ? listAllComments(contractId) : null, contractId ? listAllComments(contractId) : [],
]) ])
const folds = await foldsPromise
return { return {
props: { props: {
contract,
username, username,
slug: contractSlug, slug: contractSlug,
contract,
bets, bets,
comments, comments,
folds,
}, },
revalidate: 60, // regenerate after a minute revalidate: 60, // regenerate after a minute
@ -55,15 +62,16 @@ export async function getStaticPaths() {
export default function ContractPage(props: { export default function ContractPage(props: {
contract: Contract | null contract: Contract | null
bets: Bet[] | null
comments: Comment[] | null
slug: string
username: string username: string
bets: Bet[]
comments: Comment[]
slug: string
folds: Fold[]
}) { }) {
const user = useUser() const user = useUser()
const contract = useContractWithPreload(props.slug, props.contract) const contract = useContractWithPreload(props.slug, props.contract)
const { bets, comments } = props const { bets, comments, folds } = props
if (!contract) { if (!contract) {
return <Custom404 /> return <Custom404 />
@ -103,6 +111,7 @@ export default function ContractPage(props: {
contract={contract} contract={contract}
bets={bets ?? []} bets={bets ?? []}
comments={comments ?? []} comments={comments ?? []}
folds={folds}
/> />
<BetsSection contract={contract} user={user ?? null} /> <BetsSection contract={contract} user={user ?? null} />
</div> </div>