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