wip liked contracts list
This commit is contained in:
parent
559793d23b
commit
2e502a774c
|
@ -76,28 +76,34 @@ export const ContractOverview = (props: {
|
||||||
<Row className="items-center justify-between gap-4 xl:hidden">
|
<Row className="items-center justify-between gap-4 xl:hidden">
|
||||||
<BinaryResolutionOrChance contract={contract} />
|
<BinaryResolutionOrChance contract={contract} />
|
||||||
{tradingAllowed(contract) && (
|
{tradingAllowed(contract) && (
|
||||||
<Col>
|
<Row>
|
||||||
<BetButton contract={contract as CPMMBinaryContract} />
|
<LikeMarketButton contract={contract} user={user} />
|
||||||
{!user && (
|
<Col>
|
||||||
<div className="mt-1 text-center text-sm text-gray-500">
|
<BetButton contract={contract as CPMMBinaryContract} />
|
||||||
(with play money!)
|
{!user && (
|
||||||
</div>
|
<div className="mt-1 text-center text-sm text-gray-500">
|
||||||
)}
|
(with play money!)
|
||||||
</Col>
|
</div>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
) : isPseudoNumeric ? (
|
) : isPseudoNumeric ? (
|
||||||
<Row className="items-center justify-between gap-4 xl:hidden">
|
<Row className="items-center justify-between gap-4 xl:hidden">
|
||||||
<PseudoNumericResolutionOrExpectation contract={contract} />
|
<PseudoNumericResolutionOrExpectation contract={contract} />
|
||||||
{tradingAllowed(contract) && (
|
{tradingAllowed(contract) && (
|
||||||
<Col>
|
<Row>
|
||||||
<BetButton contract={contract} />
|
<LikeMarketButton contract={contract} user={user} />
|
||||||
{!user && (
|
<Col>
|
||||||
<div className="mt-1 text-center text-sm text-gray-500">
|
<BetButton contract={contract} />
|
||||||
(with play money!)
|
{!user && (
|
||||||
</div>
|
<div className="mt-1 text-center text-sm text-gray-500">
|
||||||
)}
|
(with play money!)
|
||||||
</Col>
|
</div>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -3,20 +3,14 @@ import { Button } from 'web/components/button'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Contract } from 'common/contract'
|
import { Contract } from 'common/contract'
|
||||||
import { User } from 'common/user'
|
import { User } from 'common/user'
|
||||||
import { collection, deleteDoc, doc, setDoc } from 'firebase/firestore'
|
|
||||||
import { removeUndefinedProps } from 'common/util/object'
|
|
||||||
import { track } from '@amplitude/analytics-browser'
|
|
||||||
import { db } from 'web/lib/firebase/init'
|
|
||||||
import { Like } from 'common/like'
|
|
||||||
import { useUserLikes } from 'web/hooks/use-likes'
|
import { useUserLikes } from 'web/hooks/use-likes'
|
||||||
import { transact } from 'web/lib/firebase/api'
|
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { formatMoney } from 'common/util/format'
|
import { formatMoney } from 'common/util/format'
|
||||||
|
import {
|
||||||
function getLikesCollection(userId: string) {
|
LIKE_TIP_AMOUNT,
|
||||||
return collection(db, 'users', userId, 'likes')
|
likeContract,
|
||||||
}
|
unLikeContract,
|
||||||
const LIKE_TIP_AMOUNT = 5
|
} from 'web/lib/firebase/likes'
|
||||||
|
|
||||||
export function LikeMarketButton(props: {
|
export function LikeMarketButton(props: {
|
||||||
contract: Contract
|
contract: Contract
|
||||||
|
@ -30,48 +24,11 @@ export function LikeMarketButton(props: {
|
||||||
|
|
||||||
const onLike = async () => {
|
const onLike = async () => {
|
||||||
if (likedContractIds?.includes(contract.id)) {
|
if (likedContractIds?.includes(contract.id)) {
|
||||||
const ref = doc(
|
await unLikeContract(user.id, contract.id)
|
||||||
getLikesCollection(user.id),
|
|
||||||
likes?.find((l) => l.contractId === contract.id)?.id
|
|
||||||
)
|
|
||||||
await deleteDoc(ref)
|
|
||||||
toast(`You removed this market from your likes`)
|
toast(`You removed this market from your likes`)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (user.balance < LIKE_TIP_AMOUNT) {
|
await likeContract(user, contract)
|
||||||
toast('You do not have enough M$ to like this market!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let result: any = {}
|
|
||||||
if (LIKE_TIP_AMOUNT > 0) {
|
|
||||||
result = await transact({
|
|
||||||
amount: LIKE_TIP_AMOUNT,
|
|
||||||
fromId: user.id,
|
|
||||||
fromType: 'USER',
|
|
||||||
toId: contract.creatorId,
|
|
||||||
toType: 'USER',
|
|
||||||
token: 'M$',
|
|
||||||
category: 'TIP',
|
|
||||||
data: { contractId: contract.id },
|
|
||||||
description: `${user.name} liked contract ${contract.id} for M$ ${LIKE_TIP_AMOUNT} to ${contract.creatorId} `,
|
|
||||||
})
|
|
||||||
console.log('result', result)
|
|
||||||
}
|
|
||||||
// create new like in db under users collection
|
|
||||||
const ref = doc(getLikesCollection(user.id))
|
|
||||||
// contract slug and question are set via trigger
|
|
||||||
const like = removeUndefinedProps({
|
|
||||||
id: ref.id,
|
|
||||||
userId: user.id,
|
|
||||||
createdTime: Date.now(),
|
|
||||||
contractId: contract.id,
|
|
||||||
tipTxnId: result.txn.id,
|
|
||||||
} as Like)
|
|
||||||
track('like', {
|
|
||||||
contractId: contract.id,
|
|
||||||
})
|
|
||||||
await setDoc(ref, like)
|
|
||||||
toast(`You tipped ${contract.creatorName} ${formatMoney(LIKE_TIP_AMOUNT)}!`)
|
toast(`You tipped ${contract.creatorName} ${formatMoney(LIKE_TIP_AMOUNT)}!`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
50
web/components/profile/user-likes-button.tsx
Normal file
50
web/components/profile/user-likes-button.tsx
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import { User } from 'common/lib/user'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { TextButton } from 'web/components/text-button'
|
||||||
|
import { Modal } from 'web/components/layout/modal'
|
||||||
|
import { Col } from 'web/components/layout/col'
|
||||||
|
import { useUserLikedContracts } from 'web/hooks/use-likes'
|
||||||
|
import { SiteLink } from 'web/components/site-link'
|
||||||
|
import { Row } from 'web/components/layout/row'
|
||||||
|
import { XIcon } from '@heroicons/react/outline'
|
||||||
|
import { unLikeContract } from 'web/lib/firebase/likes'
|
||||||
|
import { contractPath } from 'web/lib/firebase/contracts'
|
||||||
|
|
||||||
|
export function UserLikesButton(props: { user: User }) {
|
||||||
|
const { user } = props
|
||||||
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
|
||||||
|
const likedContracts = useUserLikedContracts(user.id)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TextButton onClick={() => setIsOpen(true)}>
|
||||||
|
<span className="font-semibold">{likedContracts?.length ?? ''}</span>{' '}
|
||||||
|
Likes
|
||||||
|
</TextButton>
|
||||||
|
<Modal open={isOpen} setOpen={setIsOpen}>
|
||||||
|
<Col className="rounded bg-white p-6">
|
||||||
|
<span className={'mb-4 text-xl'}>Liked Markets</span>
|
||||||
|
<Col className={'gap-4'}>
|
||||||
|
{likedContracts?.map((likedContract) => (
|
||||||
|
<Row key={likedContract.id} className={'justify-between gap-2'}>
|
||||||
|
<SiteLink
|
||||||
|
href={contractPath(likedContract)}
|
||||||
|
className={'truncate text-indigo-700'}
|
||||||
|
>
|
||||||
|
{likedContract.question}
|
||||||
|
</SiteLink>
|
||||||
|
<XIcon
|
||||||
|
className="ml-2 h-5 w-5 cursor-pointer"
|
||||||
|
onClick={() => async () => {
|
||||||
|
await unLikeContract(user.id, likedContract.id)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
))}
|
||||||
|
</Col>
|
||||||
|
</Col>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import { ENV_CONFIG } from 'common/envs/constants'
|
||||||
import { BettingStreakModal } from 'web/components/profile/betting-streak-modal'
|
import { BettingStreakModal } from 'web/components/profile/betting-streak-modal'
|
||||||
import { REFERRAL_AMOUNT } from 'common/economy'
|
import { REFERRAL_AMOUNT } from 'common/economy'
|
||||||
import { LoansModal } from './profile/loans-modal'
|
import { LoansModal } from './profile/loans-modal'
|
||||||
|
import { UserLikesButton } from 'web/components/profile/user-likes-button'
|
||||||
|
|
||||||
export function UserPage(props: { user: User }) {
|
export function UserPage(props: { user: User }) {
|
||||||
const { user } = props
|
const { user } = props
|
||||||
|
@ -273,6 +274,7 @@ export function UserPage(props: { user: User }) {
|
||||||
<FollowersButton user={user} />
|
<FollowersButton user={user} />
|
||||||
<ReferralsButton user={user} />
|
<ReferralsButton user={user} />
|
||||||
<GroupsButton user={user} />
|
<GroupsButton user={user} />
|
||||||
|
<UserLikesButton user={user} />
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { listenForLikes } from 'web/lib/firebase/users'
|
import { listenForLikes } from 'web/lib/firebase/users'
|
||||||
import { Like } from 'common/like'
|
import { Like } from 'common/like'
|
||||||
|
import { Contract } from 'common/lib/contract'
|
||||||
|
import { getContractFromId } from 'web/lib/firebase/contracts'
|
||||||
|
import { filterDefined } from 'common/util/array'
|
||||||
|
|
||||||
export const useUserLikes = (userId: string | undefined) => {
|
export const useUserLikes = (userId: string | undefined) => {
|
||||||
const [contractIds, setContractIds] = useState<Like[] | undefined>()
|
const [contractIds, setContractIds] = useState<Like[] | undefined>()
|
||||||
|
@ -11,3 +14,22 @@ export const useUserLikes = (userId: string | undefined) => {
|
||||||
|
|
||||||
return contractIds
|
return contractIds
|
||||||
}
|
}
|
||||||
|
export const useUserLikedContracts = (userId: string | undefined) => {
|
||||||
|
const [contractIds, setContractIds] = useState<Like[] | undefined>()
|
||||||
|
const [contracts, setContracts] = useState<Contract[] | undefined>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (userId) return listenForLikes(userId, setContractIds)
|
||||||
|
}, [userId])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (contractIds)
|
||||||
|
Promise.all(
|
||||||
|
contractIds.map(async (like) => {
|
||||||
|
return await getContractFromId(like.contractId)
|
||||||
|
})
|
||||||
|
).then((contracts) => setContracts(filterDefined(contracts)))
|
||||||
|
}, [contractIds])
|
||||||
|
|
||||||
|
return contracts
|
||||||
|
}
|
||||||
|
|
67
web/lib/firebase/likes.ts
Normal file
67
web/lib/firebase/likes.ts
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import {
|
||||||
|
collection,
|
||||||
|
deleteDoc,
|
||||||
|
doc,
|
||||||
|
query,
|
||||||
|
setDoc,
|
||||||
|
where,
|
||||||
|
} from 'firebase/firestore'
|
||||||
|
import { db } from 'web/lib/firebase/init'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
import { transact } from 'web/lib/firebase/api'
|
||||||
|
import { removeUndefinedProps } from 'common/lib/util/object'
|
||||||
|
import { Like } from 'common/lib/like'
|
||||||
|
import { track } from '@amplitude/analytics-browser'
|
||||||
|
import { User } from 'common/user'
|
||||||
|
import { Contract } from 'common/lib/contract'
|
||||||
|
|
||||||
|
export const LIKE_TIP_AMOUNT = 5
|
||||||
|
|
||||||
|
function getLikesCollection(userId: string) {
|
||||||
|
return collection(db, 'users', userId, 'likes')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const unLikeContract = async (userId: string, contractId: string) => {
|
||||||
|
const ref = await query(
|
||||||
|
getLikesCollection(userId),
|
||||||
|
where('contractId', '==', contractId)
|
||||||
|
)
|
||||||
|
const snapshot = await ref.get()
|
||||||
|
return await deleteDoc(ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const likeContract = async (user: User, contract: Contract) => {
|
||||||
|
if (user.balance < LIKE_TIP_AMOUNT) {
|
||||||
|
toast('You do not have enough M$ to like this market!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let result: any = {}
|
||||||
|
if (LIKE_TIP_AMOUNT > 0) {
|
||||||
|
result = await transact({
|
||||||
|
amount: LIKE_TIP_AMOUNT,
|
||||||
|
fromId: user.id,
|
||||||
|
fromType: 'USER',
|
||||||
|
toId: contract.creatorId,
|
||||||
|
toType: 'USER',
|
||||||
|
token: 'M$',
|
||||||
|
category: 'TIP',
|
||||||
|
data: { contractId: contract.id },
|
||||||
|
description: `${user.name} liked contract ${contract.id} for M$ ${LIKE_TIP_AMOUNT} to ${contract.creatorId} `,
|
||||||
|
})
|
||||||
|
console.log('result', result)
|
||||||
|
}
|
||||||
|
// create new like in db under users collection
|
||||||
|
const ref = doc(getLikesCollection(user.id))
|
||||||
|
// contract slug and question are set via trigger
|
||||||
|
const like = removeUndefinedProps({
|
||||||
|
id: ref.id,
|
||||||
|
userId: user.id,
|
||||||
|
createdTime: Date.now(),
|
||||||
|
contractId: contract.id,
|
||||||
|
tipTxnId: result.txn.id,
|
||||||
|
} as Like)
|
||||||
|
track('like', {
|
||||||
|
contractId: contract.id,
|
||||||
|
})
|
||||||
|
await setDoc(ref, like)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user