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[] }) { | export function TagsList(props: { tags: string[] }) { | ||||||
|   const { tags } = props |   const { tags } = props | ||||||
|   return ( |   return ( | ||||||
|     <Row className="gap-2 flex-wrap"> |     <Row className="gap-2 flex-wrap text-sm text-gray-500"> | ||||||
|       {tags.map((tag) => ( |       {tags.map((tag) => ( | ||||||
|         <div key={tag} className="bg-gray-100 px-1"> |         <div key={tag} className="bg-gray-100 px-1"> | ||||||
|           <Linkify text={tag} gray /> |           <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 _ from 'lodash' | ||||||
| import Image from 'next/image' |  | ||||||
| import { Col } from '../components/layout/col' | import { Col } from '../components/layout/col' | ||||||
| import { Row } from '../components/layout/row' | import { Leaderboard } from '../components/leaderboard' | ||||||
| import { Page } from '../components/page' | 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 { getTopCreators, getTopTraders, User } from '../lib/firebase/users' | ||||||
| import { formatMoney } from '../lib/util/format' | import { formatMoney } from '../lib/util/format' | ||||||
| 
 | 
 | ||||||
|  | @ -57,56 +54,3 @@ export default function Leaderboards(props: { | ||||||
|     </Page> |     </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