Add market liquidity addition events to bets feed (#578)
* Add liquidity events to bets feed * Use larger avatar for liquidity feed items
This commit is contained in:
parent
0067bee94b
commit
3b6ba76db6
|
@ -8,15 +8,17 @@ import { Spacer } from '../layout/spacer'
|
||||||
import { Tabs } from '../layout/tabs'
|
import { Tabs } from '../layout/tabs'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
import { CommentTipMap } from 'web/hooks/use-tip-txns'
|
import { CommentTipMap } from 'web/hooks/use-tip-txns'
|
||||||
|
import { LiquidityProvision } from 'common/liquidity-provision'
|
||||||
|
|
||||||
export function ContractTabs(props: {
|
export function ContractTabs(props: {
|
||||||
contract: Contract
|
contract: Contract
|
||||||
user: User | null | undefined
|
user: User | null | undefined
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
|
liquidityProvisions: LiquidityProvision[]
|
||||||
comments: Comment[]
|
comments: Comment[]
|
||||||
tips: CommentTipMap
|
tips: CommentTipMap
|
||||||
}) {
|
}) {
|
||||||
const { contract, user, bets, comments, tips } = props
|
const { contract, user, bets, comments, tips, liquidityProvisions } = props
|
||||||
const { outcomeType } = contract
|
const { outcomeType } = contract
|
||||||
|
|
||||||
const userBets = user && bets.filter((bet) => bet.userId === user.id)
|
const userBets = user && bets.filter((bet) => bet.userId === user.id)
|
||||||
|
@ -25,6 +27,7 @@ export function ContractTabs(props: {
|
||||||
<ContractActivity
|
<ContractActivity
|
||||||
contract={contract}
|
contract={contract}
|
||||||
bets={bets}
|
bets={bets}
|
||||||
|
liquidityProvisions={liquidityProvisions}
|
||||||
comments={comments}
|
comments={comments}
|
||||||
tips={tips}
|
tips={tips}
|
||||||
user={user}
|
user={user}
|
||||||
|
@ -38,6 +41,7 @@ export function ContractTabs(props: {
|
||||||
<ContractActivity
|
<ContractActivity
|
||||||
contract={contract}
|
contract={contract}
|
||||||
bets={bets}
|
bets={bets}
|
||||||
|
liquidityProvisions={liquidityProvisions}
|
||||||
comments={comments}
|
comments={comments}
|
||||||
tips={tips}
|
tips={tips}
|
||||||
user={user}
|
user={user}
|
||||||
|
@ -55,6 +59,7 @@ export function ContractTabs(props: {
|
||||||
<ContractActivity
|
<ContractActivity
|
||||||
contract={contract}
|
contract={contract}
|
||||||
bets={bets}
|
bets={bets}
|
||||||
|
liquidityProvisions={liquidityProvisions}
|
||||||
comments={comments}
|
comments={comments}
|
||||||
tips={tips}
|
tips={tips}
|
||||||
user={user}
|
user={user}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Comment } from 'common/comment'
|
||||||
import { Contract, FreeResponseContract } from 'common/contract'
|
import { Contract, FreeResponseContract } from 'common/contract'
|
||||||
import { User } from 'common/user'
|
import { User } from 'common/user'
|
||||||
import { CommentTipMap } from 'web/hooks/use-tip-txns'
|
import { CommentTipMap } from 'web/hooks/use-tip-txns'
|
||||||
|
import { LiquidityProvision } from 'common/liquidity-provision'
|
||||||
|
|
||||||
export type ActivityItem =
|
export type ActivityItem =
|
||||||
| DescriptionItem
|
| DescriptionItem
|
||||||
|
@ -17,6 +18,7 @@ export type ActivityItem =
|
||||||
| ResolveItem
|
| ResolveItem
|
||||||
| CommentInputItem
|
| CommentInputItem
|
||||||
| CommentThreadItem
|
| CommentThreadItem
|
||||||
|
| LiquidityItem
|
||||||
|
|
||||||
type BaseActivityItem = {
|
type BaseActivityItem = {
|
||||||
id: string
|
id: string
|
||||||
|
@ -72,6 +74,14 @@ export type ResolveItem = BaseActivityItem & {
|
||||||
type: 'resolve'
|
type: 'resolve'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type LiquidityItem = BaseActivityItem & {
|
||||||
|
type: 'liquidity'
|
||||||
|
liquidity: LiquidityProvision
|
||||||
|
hideOutcome: boolean
|
||||||
|
smallAvatar: boolean
|
||||||
|
hideComment?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
function getAnswerAndCommentInputGroups(
|
function getAnswerAndCommentInputGroups(
|
||||||
contract: FreeResponseContract,
|
contract: FreeResponseContract,
|
||||||
bets: Bet[],
|
bets: Bet[],
|
||||||
|
@ -139,6 +149,7 @@ export function getSpecificContractActivityItems(
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
bets: Bet[],
|
bets: Bet[],
|
||||||
comments: Comment[],
|
comments: Comment[],
|
||||||
|
liquidityProvisions: LiquidityProvision[],
|
||||||
tips: CommentTipMap,
|
tips: CommentTipMap,
|
||||||
user: User | null | undefined,
|
user: User | null | undefined,
|
||||||
options: {
|
options: {
|
||||||
|
@ -146,7 +157,7 @@ export function getSpecificContractActivityItems(
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const { mode } = options
|
const { mode } = options
|
||||||
const items = [] as ActivityItem[]
|
let items = [] as ActivityItem[]
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 'bets':
|
case 'bets':
|
||||||
|
@ -163,6 +174,23 @@ export function getSpecificContractActivityItems(
|
||||||
hideComment: true,
|
hideComment: true,
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
items.push(
|
||||||
|
...liquidityProvisions.map((liquidity) => ({
|
||||||
|
type: 'liquidity' as const,
|
||||||
|
id: liquidity.id,
|
||||||
|
contract,
|
||||||
|
liquidity,
|
||||||
|
hideOutcome: false,
|
||||||
|
smallAvatar: false,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
items = sortBy(items, (item) =>
|
||||||
|
item.type === 'bet'
|
||||||
|
? item.bet.createdTime
|
||||||
|
: item.type === 'liquidity'
|
||||||
|
? item.liquidity.createdTime
|
||||||
|
: undefined
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'comments': {
|
case 'comments': {
|
||||||
|
|
|
@ -8,11 +8,13 @@ import { FeedItems } from './feed-items'
|
||||||
import { User } from 'common/user'
|
import { User } from 'common/user'
|
||||||
import { useContractWithPreload } from 'web/hooks/use-contract'
|
import { useContractWithPreload } from 'web/hooks/use-contract'
|
||||||
import { CommentTipMap } from 'web/hooks/use-tip-txns'
|
import { CommentTipMap } from 'web/hooks/use-tip-txns'
|
||||||
|
import { LiquidityProvision } from 'common/liquidity-provision'
|
||||||
|
|
||||||
export function ContractActivity(props: {
|
export function ContractActivity(props: {
|
||||||
contract: Contract
|
contract: Contract
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
comments: Comment[]
|
comments: Comment[]
|
||||||
|
liquidityProvisions: LiquidityProvision[]
|
||||||
tips: CommentTipMap
|
tips: CommentTipMap
|
||||||
user: User | null | undefined
|
user: User | null | undefined
|
||||||
mode: 'comments' | 'bets' | 'free-response-comment-answer-groups'
|
mode: 'comments' | 'bets' | 'free-response-comment-answer-groups'
|
||||||
|
@ -20,7 +22,8 @@ export function ContractActivity(props: {
|
||||||
className?: string
|
className?: string
|
||||||
betRowClassName?: string
|
betRowClassName?: string
|
||||||
}) {
|
}) {
|
||||||
const { user, mode, tips, className, betRowClassName } = props
|
const { user, mode, tips, className, betRowClassName, liquidityProvisions } =
|
||||||
|
props
|
||||||
|
|
||||||
const contract = useContractWithPreload(props.contract) ?? props.contract
|
const contract = useContractWithPreload(props.contract) ?? props.contract
|
||||||
|
|
||||||
|
@ -33,6 +36,7 @@ export function ContractActivity(props: {
|
||||||
contract,
|
contract,
|
||||||
bets,
|
bets,
|
||||||
comments,
|
comments,
|
||||||
|
liquidityProvisions,
|
||||||
tips,
|
tips,
|
||||||
user,
|
user,
|
||||||
{ mode }
|
{ mode }
|
||||||
|
|
|
@ -35,6 +35,7 @@ import {
|
||||||
} from 'web/components/feed/feed-comments'
|
} from 'web/components/feed/feed-comments'
|
||||||
import { FeedBet } from 'web/components/feed/feed-bets'
|
import { FeedBet } from 'web/components/feed/feed-bets'
|
||||||
import { NumericContract } from 'common/contract'
|
import { NumericContract } from 'common/contract'
|
||||||
|
import { FeedLiquidity } from './feed-liquidity'
|
||||||
|
|
||||||
export function FeedItems(props: {
|
export function FeedItems(props: {
|
||||||
contract: Contract
|
contract: Contract
|
||||||
|
@ -83,6 +84,8 @@ export function FeedItem(props: { item: ActivityItem }) {
|
||||||
return <FeedDescription {...item} />
|
return <FeedDescription {...item} />
|
||||||
case 'bet':
|
case 'bet':
|
||||||
return <FeedBet {...item} />
|
return <FeedBet {...item} />
|
||||||
|
case 'liquidity':
|
||||||
|
return <FeedLiquidity {...item} />
|
||||||
case 'answergroup':
|
case 'answergroup':
|
||||||
return <FeedAnswerCommentGroup {...item} />
|
return <FeedAnswerCommentGroup {...item} />
|
||||||
case 'close':
|
case 'close':
|
||||||
|
|
85
web/components/feed/feed-liquidity.tsx
Normal file
85
web/components/feed/feed-liquidity.tsx
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { User } from 'common/user'
|
||||||
|
import { useUser, useUserById } from 'web/hooks/use-user'
|
||||||
|
import { Row } from 'web/components/layout/row'
|
||||||
|
import { Avatar, EmptyAvatar } from 'web/components/avatar'
|
||||||
|
import clsx from 'clsx'
|
||||||
|
import { formatMoney } from 'common/util/format'
|
||||||
|
import { RelativeTimestamp } from 'web/components/relative-timestamp'
|
||||||
|
import React from 'react'
|
||||||
|
import { UserLink } from '../user-page'
|
||||||
|
import { LiquidityProvision } from 'common/liquidity-provision'
|
||||||
|
|
||||||
|
export function FeedLiquidity(props: {
|
||||||
|
liquidity: LiquidityProvision
|
||||||
|
smallAvatar: boolean
|
||||||
|
}) {
|
||||||
|
const { liquidity, smallAvatar } = props
|
||||||
|
const { userId, createdTime } = liquidity
|
||||||
|
|
||||||
|
const isBeforeJune2022 = dayjs(createdTime).isBefore('2022-06-01')
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
const bettor = isBeforeJune2022 ? undefined : useUserById(userId)
|
||||||
|
|
||||||
|
const user = useUser()
|
||||||
|
const isSelf = user?.id === userId
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Row className={'flex w-full gap-2 pt-3'}>
|
||||||
|
{isSelf ? (
|
||||||
|
<Avatar
|
||||||
|
className={clsx(smallAvatar && 'ml-1')}
|
||||||
|
size={smallAvatar ? 'sm' : undefined}
|
||||||
|
avatarUrl={user.avatarUrl}
|
||||||
|
username={user.username}
|
||||||
|
/>
|
||||||
|
) : bettor ? (
|
||||||
|
<Avatar
|
||||||
|
className={clsx(smallAvatar && 'ml-1')}
|
||||||
|
size={smallAvatar ? 'sm' : undefined}
|
||||||
|
avatarUrl={bettor.avatarUrl}
|
||||||
|
username={bettor.username}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="relative px-1">
|
||||||
|
<EmptyAvatar />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={'min-w-0 flex-1 py-1.5'}>
|
||||||
|
<LiquidityStatusText
|
||||||
|
liquidity={liquidity}
|
||||||
|
isSelf={isSelf}
|
||||||
|
bettor={bettor}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LiquidityStatusText(props: {
|
||||||
|
liquidity: LiquidityProvision
|
||||||
|
isSelf: boolean
|
||||||
|
bettor?: User
|
||||||
|
}) {
|
||||||
|
const { liquidity, bettor, isSelf } = props
|
||||||
|
const { amount, createdTime } = liquidity
|
||||||
|
|
||||||
|
// TODO: Withdrawn liquidity will never be shown, since liquidity amounts currently are zeroed out upon withdrawal.
|
||||||
|
const bought = amount >= 0 ? 'added' : 'withdrew'
|
||||||
|
const money = formatMoney(Math.abs(amount))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="text-sm text-gray-500">
|
||||||
|
{bettor ? (
|
||||||
|
<UserLink name={bettor.name} username={bettor.username} />
|
||||||
|
) : (
|
||||||
|
<span>{isSelf ? 'You' : 'A trader'}</span>
|
||||||
|
)}{' '}
|
||||||
|
{bought} {money}
|
||||||
|
{' of liquidity'}
|
||||||
|
<RelativeTimestamp time={createdTime} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -42,6 +42,7 @@ import { useBets } from 'web/hooks/use-bets'
|
||||||
import { AlertBox } from 'web/components/alert-box'
|
import { AlertBox } from 'web/components/alert-box'
|
||||||
import { useTracking } from 'web/hooks/use-tracking'
|
import { useTracking } from 'web/hooks/use-tracking'
|
||||||
import { CommentTipMap, useTipTxns } from 'web/hooks/use-tip-txns'
|
import { CommentTipMap, useTipTxns } from 'web/hooks/use-tip-txns'
|
||||||
|
import { useLiquidity } from 'web/hooks/use-liquidity'
|
||||||
|
|
||||||
export const getStaticProps = fromPropz(getStaticPropz)
|
export const getStaticProps = fromPropz(getStaticPropz)
|
||||||
export async function getStaticPropz(props: {
|
export async function getStaticPropz(props: {
|
||||||
|
@ -117,6 +118,8 @@ export function ContractPageContent(
|
||||||
})
|
})
|
||||||
|
|
||||||
const bets = useBets(contract.id) ?? props.bets
|
const bets = useBets(contract.id) ?? props.bets
|
||||||
|
const liquidityProvisions =
|
||||||
|
useLiquidity(contract.id)?.filter((l) => !l.isAnte && l.amount > 0) ?? []
|
||||||
// Sort for now to see if bug is fixed.
|
// Sort for now to see if bug is fixed.
|
||||||
comments.sort((c1, c2) => c1.createdTime - c2.createdTime)
|
comments.sort((c1, c2) => c1.createdTime - c2.createdTime)
|
||||||
|
|
||||||
|
@ -233,6 +236,7 @@ export function ContractPageContent(
|
||||||
<ContractTabs
|
<ContractTabs
|
||||||
contract={contract}
|
contract={contract}
|
||||||
user={user}
|
user={user}
|
||||||
|
liquidityProvisions={liquidityProvisions}
|
||||||
bets={bets}
|
bets={bets}
|
||||||
tips={tips}
|
tips={tips}
|
||||||
comments={comments}
|
comments={comments}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user