Add links to /edit and /leaderboards for fold
This commit is contained in:
parent
9c5463235a
commit
9bac47e9f3
58
web/components/leaderboard.tsx
Normal file
58
web/components/leaderboard.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import Image from 'next/image'
|
||||
import { User } from '../../common/user'
|
||||
import { Row } from './layout/row'
|
||||
import { SiteLink } from './site-link'
|
||||
import { Title } from './title'
|
||||
|
||||
export function Leaderboard(props: {
|
||||
title: string
|
||||
users: User[]
|
||||
columns: {
|
||||
header: string
|
||||
renderCell: (user: User) => any
|
||||
}[]
|
||||
}) {
|
||||
const { title, users, columns } = props
|
||||
return (
|
||||
<div className="max-w-xl w-full px-1">
|
||||
<Title text={title} />
|
||||
<div className="overflow-x-auto">
|
||||
<table className="table table-zebra table-compact text-gray-500 w-full">
|
||||
<thead>
|
||||
<tr className="p-2">
|
||||
<th>#</th>
|
||||
<th>Name</th>
|
||||
{columns.map((column) => (
|
||||
<th key={column.header}>{column.header}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map((user, index) => (
|
||||
<tr key={user.id}>
|
||||
<td>{index + 1}</td>
|
||||
<td>
|
||||
<SiteLink className="relative" href={`/${user.username}`}>
|
||||
<Row className="items-center gap-4">
|
||||
<Image
|
||||
className="rounded-full bg-gray-400 flex-shrink-0 ring-8 ring-gray-50"
|
||||
src={user.avatarUrl || ''}
|
||||
alt=""
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
<div>{user.name}</div>
|
||||
</Row>
|
||||
</SiteLink>
|
||||
</td>
|
||||
{columns.map((column) => (
|
||||
<td key={column.header}>{column.renderCell(user)}</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -4,7 +4,7 @@ import { Linkify } from './linkify'
|
|||
export function TagsList(props: { tags: string[] }) {
|
||||
const { tags } = props
|
||||
return (
|
||||
<Row className="gap-2 flex-wrap">
|
||||
<Row className="gap-2 flex-wrap text-sm text-gray-500">
|
||||
{tags.map((tag) => (
|
||||
<div key={tag} className="bg-gray-100 px-1">
|
||||
<Linkify text={tag} gray />
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
import _ from 'lodash'
|
||||
import { Fold } from '../../../common/fold'
|
||||
import { Comment } from '../../../common/comment'
|
||||
import { Page } from '../../components/page'
|
||||
import { Title } from '../../components/title'
|
||||
import { Bet, listAllBets } from '../../lib/firebase/bets'
|
||||
import { listAllComments } from '../../lib/firebase/comments'
|
||||
import { Contract } from '../../lib/firebase/contracts'
|
||||
import { getFoldBySlug, getFoldContracts } from '../../lib/firebase/folds'
|
||||
import { ActivityFeed, findActiveContracts } from '../activity'
|
||||
import { TagsList } from '../../components/tags-list'
|
||||
|
||||
export async function getStaticProps(props: { params: { foldSlug: string } }) {
|
||||
const { foldSlug } = props.params
|
||||
|
||||
const fold = await getFoldBySlug(foldSlug)
|
||||
const contracts = fold ? await getFoldContracts(fold) : []
|
||||
const contractComments = await Promise.all(
|
||||
contracts.map((contract) => listAllComments(contract.id))
|
||||
)
|
||||
|
||||
const activeContracts = findActiveContracts(
|
||||
contracts,
|
||||
_.flatten(contractComments)
|
||||
)
|
||||
const activeContractBets = await Promise.all(
|
||||
activeContracts.map((contract) => listAllBets(contract.id))
|
||||
)
|
||||
const activeContractComments = activeContracts.map(
|
||||
(contract) =>
|
||||
contractComments[contracts.findIndex((c) => c.id === contract.id)]
|
||||
)
|
||||
|
||||
return {
|
||||
props: {
|
||||
fold,
|
||||
activeContracts,
|
||||
activeContractBets,
|
||||
activeContractComments,
|
||||
},
|
||||
|
||||
revalidate: 60, // regenerate after a minute
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return { paths: [], fallback: 'blocking' }
|
||||
}
|
||||
|
||||
export default function FoldPage(props: {
|
||||
fold: Fold
|
||||
activeContracts: Contract[]
|
||||
activeContractBets: Bet[][]
|
||||
activeContractComments: Comment[][]
|
||||
}) {
|
||||
const { fold, activeContracts, activeContractBets, activeContractComments } =
|
||||
props
|
||||
|
||||
const { tags } = fold
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<Title text={fold.name} />
|
||||
|
||||
<TagsList tags={tags} />
|
||||
|
||||
<ActivityFeed
|
||||
contracts={activeContracts}
|
||||
contractBets={activeContractBets}
|
||||
contractComments={activeContractComments}
|
||||
/>
|
||||
</Page>
|
||||
)
|
||||
}
|
18
web/pages/fold/[foldSlug]/edit.tsx
Normal file
18
web/pages/fold/[foldSlug]/edit.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import _ from 'lodash'
|
||||
import { Page } from '../../../components/page'
|
||||
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: {},
|
||||
|
||||
revalidate: 60, // regenerate after a minute
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return { paths: [], fallback: 'blocking' }
|
||||
}
|
||||
|
||||
export default function Leaderboards(props: {}) {
|
||||
return <Page>Edit fold</Page>
|
||||
}
|
125
web/pages/fold/[foldSlug]/index.tsx
Normal file
125
web/pages/fold/[foldSlug]/index.tsx
Normal file
|
@ -0,0 +1,125 @@
|
|||
import _ from 'lodash'
|
||||
import { Fold } from '../../../../common/fold'
|
||||
import { Comment } from '../../../../common/comment'
|
||||
import { Page } from '../../../components/page'
|
||||
import { Title } from '../../../components/title'
|
||||
import { Bet, listAllBets } from '../../../lib/firebase/bets'
|
||||
import { listAllComments } from '../../../lib/firebase/comments'
|
||||
import { Contract } from '../../../lib/firebase/contracts'
|
||||
import { getFoldBySlug, getFoldContracts } from '../../../lib/firebase/folds'
|
||||
import { ActivityFeed, findActiveContracts } from '../../activity'
|
||||
import { TagsList } from '../../../components/tags-list'
|
||||
import { Row } from '../../../components/layout/row'
|
||||
import { UserLink } from '../../../components/user-page'
|
||||
import { getUser, User } from '../../../lib/firebase/users'
|
||||
import { Spacer } from '../../../components/layout/spacer'
|
||||
import { Col } from '../../../components/layout/col'
|
||||
import { SiteLink } from '../../../components/site-link'
|
||||
import { useUser } from '../../../hooks/use-user'
|
||||
|
||||
export async function getStaticProps(props: { params: { foldSlug: string } }) {
|
||||
const { foldSlug } = props.params
|
||||
|
||||
const fold = await getFoldBySlug(foldSlug)
|
||||
const curatorPromise = fold ? getUser(fold.curatorId) : null
|
||||
|
||||
const contracts = fold ? await getFoldContracts(fold) : []
|
||||
const contractComments = await Promise.all(
|
||||
contracts.map((contract) => listAllComments(contract.id))
|
||||
)
|
||||
|
||||
const activeContracts = findActiveContracts(
|
||||
contracts,
|
||||
_.flatten(contractComments)
|
||||
)
|
||||
const activeContractBets = await Promise.all(
|
||||
activeContracts.map((contract) => listAllBets(contract.id))
|
||||
)
|
||||
const activeContractComments = activeContracts.map(
|
||||
(contract) =>
|
||||
contractComments[contracts.findIndex((c) => c.id === contract.id)]
|
||||
)
|
||||
|
||||
const curator = await curatorPromise
|
||||
|
||||
return {
|
||||
props: {
|
||||
fold,
|
||||
curator,
|
||||
activeContracts,
|
||||
activeContractBets,
|
||||
activeContractComments,
|
||||
},
|
||||
|
||||
revalidate: 60, // regenerate after a minute
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return { paths: [], fallback: 'blocking' }
|
||||
}
|
||||
|
||||
export default function FoldPage(props: {
|
||||
fold: Fold
|
||||
curator: User
|
||||
activeContracts: Contract[]
|
||||
activeContractBets: Bet[][]
|
||||
activeContractComments: Comment[][]
|
||||
}) {
|
||||
const {
|
||||
fold,
|
||||
curator,
|
||||
activeContracts,
|
||||
activeContractBets,
|
||||
activeContractComments,
|
||||
} = props
|
||||
|
||||
const { tags, curatorId } = fold
|
||||
|
||||
const user = useUser()
|
||||
const isCurator = user?.id === curatorId
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<Col className="items-center">
|
||||
<Col className="max-w-3xl w-full">
|
||||
<Title text={fold.name} />
|
||||
|
||||
<Row className="items-center mb-2">
|
||||
{isCurator && (
|
||||
<>
|
||||
<SiteLink className="text-sm " href={`/fold/${fold.slug}/edit`}>
|
||||
Edit
|
||||
</SiteLink>
|
||||
<div className="ml-2 mr-2">•</div>
|
||||
</>
|
||||
)}
|
||||
<SiteLink
|
||||
className="text-sm"
|
||||
href={`/fold/${fold.slug}/leaderboards`}
|
||||
>
|
||||
Leaderboards
|
||||
</SiteLink>
|
||||
<div className="ml-2 mr-2">•</div>
|
||||
<div className="text-sm text-gray-500 mr-1">Curated by</div>
|
||||
<UserLink
|
||||
className="text-sm text-neutral"
|
||||
name={curator.name}
|
||||
username={curator.username}
|
||||
/>
|
||||
<div className="ml-2 mr-2">•</div>
|
||||
<TagsList tags={tags.map((tag) => `#${tag}`)} />
|
||||
</Row>
|
||||
|
||||
<Spacer h={4} />
|
||||
|
||||
<ActivityFeed
|
||||
contracts={activeContracts}
|
||||
contractBets={activeContractBets}
|
||||
contractComments={activeContractComments}
|
||||
/>
|
||||
</Col>
|
||||
</Col>
|
||||
</Page>
|
||||
)
|
||||
}
|
46
web/pages/fold/[foldSlug]/leaderboards.tsx
Normal file
46
web/pages/fold/[foldSlug]/leaderboards.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import _ from 'lodash'
|
||||
import { Col } from '../../../components/layout/col'
|
||||
import { Leaderboard } from '../../../components/leaderboard'
|
||||
import { Page } from '../../../components/page'
|
||||
import { formatMoney } from '../../../lib/util/format'
|
||||
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: {},
|
||||
|
||||
revalidate: 60, // regenerate after a minute
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return { paths: [], fallback: 'blocking' }
|
||||
}
|
||||
|
||||
export default function Leaderboards(props: {}) {
|
||||
return (
|
||||
<Page>
|
||||
<Col className="items-center lg:flex-row gap-10">
|
||||
<Leaderboard
|
||||
title="🏅 Top traders"
|
||||
users={[]}
|
||||
columns={[
|
||||
{
|
||||
header: 'Total profit',
|
||||
renderCell: (user) => formatMoney(user.totalPnLCached),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Leaderboard
|
||||
title="🏅 Top creators"
|
||||
users={[]}
|
||||
columns={[
|
||||
{
|
||||
header: 'Market volume',
|
||||
renderCell: (user) => formatMoney(user.creatorVolumeCached),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Col>
|
||||
</Page>
|
||||
)
|
||||
}
|
|
@ -1,10 +1,7 @@
|
|||
import _ from 'lodash'
|
||||
import Image from 'next/image'
|
||||
import { Col } from '../components/layout/col'
|
||||
import { Row } from '../components/layout/row'
|
||||
import { Leaderboard } from '../components/leaderboard'
|
||||
import { Page } from '../components/page'
|
||||
import { SiteLink } from '../components/site-link'
|
||||
import { Title } from '../components/title'
|
||||
import { getTopCreators, getTopTraders, User } from '../lib/firebase/users'
|
||||
import { formatMoney } from '../lib/util/format'
|
||||
|
||||
|
@ -57,56 +54,3 @@ export default function Leaderboards(props: {
|
|||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
function Leaderboard(props: {
|
||||
title: string
|
||||
users: User[]
|
||||
columns: {
|
||||
header: string
|
||||
renderCell: (user: User) => any
|
||||
}[]
|
||||
}) {
|
||||
const { title, users, columns } = props
|
||||
return (
|
||||
<div className="max-w-xl w-full px-1">
|
||||
<Title text={title} />
|
||||
<div className="overflow-x-auto">
|
||||
<table className="table table-zebra table-compact text-gray-500 w-full">
|
||||
<thead>
|
||||
<tr className="p-2">
|
||||
<th>#</th>
|
||||
<th>Name</th>
|
||||
{columns.map((column) => (
|
||||
<th key={column.header}>{column.header}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map((user, index) => (
|
||||
<tr key={user.id}>
|
||||
<td>{index + 1}</td>
|
||||
<td>
|
||||
<SiteLink className="relative" href={`/${user.username}`}>
|
||||
<Row className="items-center gap-4">
|
||||
<Image
|
||||
className="rounded-full bg-gray-400 flex-shrink-0 ring-8 ring-gray-50"
|
||||
src={user.avatarUrl || ''}
|
||||
alt=""
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
<div>{user.name}</div>
|
||||
</Row>
|
||||
</SiteLink>
|
||||
</td>
|
||||
{columns.map((column) => (
|
||||
<td key={column.header}>{column.renderCell(user)}</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user