Bets on profile, again (#251)

* Revert "Revert "Show every user's bets on their profile (#170)""

This reverts commit 142206b79a.

* Fix typo

* Delete portfolio page
This commit is contained in:
Austin Chen 2022-05-18 11:52:12 -04:00 committed by GitHub
parent eb3ac802c0
commit 39870dd933
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 50 deletions

View File

@ -19,7 +19,6 @@ export function ContractsGrid(props: {
const isBottomVisible = useIsVisible(elem)
useEffect(() => {
console.log({ isBottomVisible, hasMore })
if (isBottomVisible) {
loadMore()
}

View File

@ -47,7 +47,7 @@ export function BottomNavBar() {
)}
{user !== null && (
<Link href="/portfolio">
<Link href={`${user}/bets`}>
<a className="block w-full py-1 px-3 text-center hover:bg-indigo-200 hover:text-indigo-700">
<PresentationChartLineIcon
className="my-1 mx-auto h-6 w-6"

View File

@ -28,12 +28,18 @@ function IconFromUrl(url: string): React.ComponentType<{ className?: string }> {
}
}
const navigation = [
function getNavigation(username: string) {
return [
{ name: 'Home', href: '/home', icon: HomeIcon },
{ name: 'Activity', href: '/activity', icon: ChatAltIcon },
{ name: 'Portfolio', href: '/portfolio', icon: PresentationChartLineIcon },
{
name: 'Portfolio',
href: `/${username}/bets`,
icon: PresentationChartLineIcon,
},
{ name: 'Charity', href: '/charity', icon: HeartIcon },
]
}
const signedOutNavigation = [
{ name: 'Home', href: '/home', icon: HomeIcon },
@ -119,7 +125,10 @@ export default function Sidebar(props: { className?: string }) {
folds = _.sortBy(folds, 'followCount').reverse()
const deservesDailyFreeMarket = !useHasCreatedContractToday(user)
const navigationOptions = user === null ? signedOutNavigation : navigation
const navigationOptions =
user === null
? signedOutNavigation
: getNavigation(user?.username || 'error')
const mobileNavigationOptions =
user === null ? signedOutMobileNavigation : mobileNavigation

View File

@ -21,6 +21,9 @@ import { getContractFromId, listContracts } from 'web/lib/firebase/contracts'
import { LoadingIndicator } from './loading-indicator'
import { useRouter } from 'next/router'
import _ from 'lodash'
import { BetsList } from './bets-list'
import { Bet } from 'common/bet'
import { getUserBets } from 'web/lib/firebase/bets'
export function UserLink(props: {
name: string
@ -38,12 +41,13 @@ export function UserLink(props: {
)
}
export const TAB_IDS = ['markets', 'comments', 'bets']
export function UserPage(props: {
user: User
currentUser?: User
defaultTabTitle?: string
defaultTabTitle?: 'markets' | 'comments' | 'bets'
}) {
const router = useRouter()
const { user, currentUser, defaultTabTitle } = props
const isCurrentUser = user.id === currentUser?.id
const bannerUrl = user.bannerUrl ?? defaultBannerUrl(user.id)
@ -51,6 +55,7 @@ export function UserPage(props: {
const [usersContracts, setUsersContracts] = useState<Contract[] | 'loading'>(
'loading'
)
const [usersBets, setUsersBets] = useState<Bet[] | 'loading'>('loading')
const [commentsByContract, setCommentsByContract] = useState<
Map<Contract, Comment[]> | 'loading'
>('loading')
@ -59,6 +64,7 @@ export function UserPage(props: {
if (!user) return
getUsersComments(user.id).then(setUsersComments)
listContracts(user.id).then(setUsersContracts)
getUserBets(user.id).then(setUsersBets)
}, [user])
useEffect(() => {
@ -187,17 +193,14 @@ export function UserPage(props: {
{usersContracts !== 'loading' && commentsByContract != 'loading' ? (
<Tabs
className={'pb-2 pt-1 '}
defaultIndex={defaultTabTitle === 'Comments' ? 1 : 0}
onClick={(tabName) =>
router.push(
{
pathname: `/${user.username}`,
query: { tab: tabName },
},
undefined,
{ shallow: true }
)
}
defaultIndex={TAB_IDS.indexOf(defaultTabTitle || 'markets')}
onClick={(tabName) => {
const tabId = tabName.toLowerCase()
const subpath = tabId === 'markets' ? '' : '/' + tabId
// BUG: if you start on `/Bob/bets`, then click on Markets, use-query-and-sort-params
// rewrites the url incorrectly to `/Bob/bets` instead of `/Bob`
window.history.replaceState('', '', `/${user.username}${subpath}`)
}}
tabs={[
{
title: 'Markets',
@ -220,6 +223,24 @@ export function UserPage(props: {
<div className="px-0.5 font-bold">{usersComments.length}</div>
),
},
{
title: 'Bets',
content: (
<div>
<AlertBox
title="Bets are becoming publicly visible on 2022-06-01"
text="Bettor identities have always been traceable through the Manifold API.
However, our interface implied that they were private.
As we develop new features such as leaderboards and bet history, it won't be technically feasible to keep this info private.
For more context, or if you'd like to wipe your bet history, see: https://manifold.markets/Austin/will-all-bets-on-manifold-be-public"
/>
{isCurrentUser && <BetsList user={user} />}
</div>
),
tabIcon: (
<div className="px-0.5 font-bold">{usersBets.length}</div>
),
},
]}
/>
) : (
@ -242,3 +263,27 @@ export function defaultBannerUrl(userId: string) {
]
return defaultBanner[genHash(userId)() % defaultBanner.length]
}
import { ExclamationIcon } from '@heroicons/react/solid'
function AlertBox(props: { title: string; text: string }) {
const { title, text } = props
return (
<div className="rounded-md bg-yellow-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<ExclamationIcon
className="h-5 w-5 text-yellow-400"
aria-hidden="true"
/>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-yellow-800">{title}</h3>
<div className="mt-2 text-sm text-yellow-700">
<Linkify text={text} />
</div>
</div>
</div>
</div>
)
}

View File

@ -47,7 +47,6 @@ export function useInitialQueryAndSort(options?: {
}
setInitialSort(localSort ?? defaultSort)
} else {
console.log('ready setting to ', sort ?? defaultSort)
setInitialSort(sort ?? defaultSort)
}
}

View File

@ -60,6 +60,12 @@ export function listenForBets(
})
}
export async function getUserBets(userId: string) {
return getValues<Bet>(
query(collectionGroup(db, 'bets'), where('userId', '==', userId))
)
}
export function listenForUserBets(
userId: string,
setBets: (bets: Bet[]) => void

View File

@ -0,0 +1,5 @@
import UserProfile from '.'
export default function UserBets() {
return <UserProfile tab="bets" />
}

View File

@ -0,0 +1,5 @@
import UserProfile from '.'
export default function UserBets() {
return <UserProfile tab="comments" />
}

View File

@ -6,10 +6,12 @@ import { UserPage } from 'web/components/user-page'
import { useUser } from 'web/hooks/use-user'
import Custom404 from '../404'
export default function UserProfile() {
export default function UserProfile(props: {
tab?: 'markets' | 'comments' | 'bets'
}) {
const router = useRouter()
const [user, setUser] = useState<User | null | 'loading'>('loading')
const { username, tab } = router.query as { username: string; tab: string }
const { username } = router.query as { username: string }
useEffect(() => {
if (username) {
getUserByUsername(username).then(setUser)
@ -24,7 +26,7 @@ export default function UserProfile() {
<UserPage
user={user}
currentUser={currentUser || undefined}
defaultTabTitle={tab}
defaultTabTitle={props.tab}
/>
) : (
<Custom404 />

View File

@ -1,24 +0,0 @@
import Router from 'next/router'
import { useEffect } from 'react'
import { BetsList } from 'web/components/bets-list'
import { Page } from 'web/components/page'
import { SEO } from 'web/components/SEO'
import { Title } from 'web/components/title'
import { useUser } from 'web/hooks/use-user'
export default function PortfolioPage() {
const user = useUser()
useEffect(() => {
if (user === null) Router.replace('/')
})
return (
<Page>
<SEO title="Portfolio" description="Portfolio" url="/portfolio" />
<Title className="mx-4 md:mx-0" text="Portfolio" />
{user && <BetsList user={user} />}
</Page>
)
}