From 4d214c01b4f474dfca85718e55214e6ca8339fa2 Mon Sep 17 00:00:00 2001 From: FRC Date: Fri, 14 Oct 2022 13:05:07 +0100 Subject: [PATCH] Tipping in posts (#1045) * Tipping in posts * Rm itemType field --- common/contract.ts | 1 + common/like.ts | 2 +- common/post.ts | 3 ++ functions/src/create-post.ts | 1 + .../contract/extra-contract-actions-row.tsx | 4 +- ...market-button.tsx => like-item-button.tsx} | 31 ++++++------ web/components/profile/user-likes-button.tsx | 4 +- web/hooks/use-tip-txns.ts | 6 +-- web/lib/firebase/likes.ts | 23 +++++---- web/pages/post/[...slugs]/index.tsx | 49 ++++++++++--------- 10 files changed, 71 insertions(+), 53 deletions(-) rename web/components/contract/{like-market-button.tsx => like-item-button.tsx} (64%) diff --git a/common/contract.ts b/common/contract.ts index dd2aa70a..8b78a6bc 100644 --- a/common/contract.ts +++ b/common/contract.ts @@ -10,6 +10,7 @@ export type AnyOutcomeType = | PseudoNumeric | FreeResponse | Numeric + export type AnyContractType = | (CPMM & Binary) | (CPMM & PseudoNumeric) diff --git a/common/like.ts b/common/like.ts index 303a3841..651c31aa 100644 --- a/common/like.ts +++ b/common/like.ts @@ -1,7 +1,7 @@ export type Like = { id: string // will be id of the object liked, i.e. contract.id userId: string - type: 'contract' + type: 'contract' | 'post' createdTime: number tipTxnId?: string // only holds most recent tip txn id } diff --git a/common/post.ts b/common/post.ts index 4549b3be..5e4134a2 100644 --- a/common/post.ts +++ b/common/post.ts @@ -13,6 +13,9 @@ export type Post = { creatorName: string creatorUsername: string creatorAvatarUrl?: string + + likedByUserIds?: string[] + likedByUserCount?: number } export type DateDoc = Post & { diff --git a/functions/src/create-post.ts b/functions/src/create-post.ts index 0bdb0894..bfc68824 100644 --- a/functions/src/create-post.ts +++ b/functions/src/create-post.ts @@ -103,6 +103,7 @@ export const createpost = newEndpoint({}, async (req, auth) => { creatorName: creator.name, creatorUsername: creator.username, creatorAvatarUrl: creator.avatarUrl, + itemType: 'post', }) await postRef.create(post) diff --git a/web/components/contract/extra-contract-actions-row.tsx b/web/components/contract/extra-contract-actions-row.tsx index 7353bb6e..68a095f9 100644 --- a/web/components/contract/extra-contract-actions-row.tsx +++ b/web/components/contract/extra-contract-actions-row.tsx @@ -6,7 +6,7 @@ import { IconButton } from 'web/components/button' import { useUser } from 'web/hooks/use-user' import { ShareModal } from './share-modal' import { FollowMarketButton } from 'web/components/follow-market-button' -import { LikeMarketButton } from 'web/components/contract/like-market-button' +import { LikeItemButton } from 'web/components/contract/like-item-button' import { ContractInfoDialog } from 'web/components/contract/contract-info-dialog' import { Tooltip } from '../tooltip' @@ -19,7 +19,7 @@ export function ExtraContractActionsRow(props: { contract: Contract }) { - + { return sum(tips.map((tip) => tip.amount)) @@ -27,21 +29,22 @@ export function LikeMarketButton(props: { const [isLiking, setIsLiking] = useState(false) - const userLikedContractIds = likes - ?.filter((l) => l.type === 'contract') + const userLikedItemIds = likes + ?.filter((l) => l.type === 'contract' || l.type === 'post') .map((l) => l.id) const onLike = async () => { if (!user) return firebaseLogin() setIsLiking(true) + const timeoutId = setTimeout(() => { - likeContract(user, contract).catch(() => setIsLiking(false)) + likeItem(user, item, itemType).catch(() => setIsLiking(false)) }, 3000) toast.custom( () => ( { clearTimeout(timeoutId) }} @@ -59,10 +62,10 @@ export function LikeMarketButton(props: { userTipped={ !!user && (isLiking || - userLikedContractIds?.includes(contract.id) || - (!likes && !!contract.likedByUserIds?.includes(user.id))) + userLikedItemIds?.includes(item.id) || + (!likes && !!item.likedByUserIds?.includes(user.id))) } - disabled={contract.creatorId === user?.id} + disabled={item.creatorId === user?.id} /> ) } diff --git a/web/components/profile/user-likes-button.tsx b/web/components/profile/user-likes-button.tsx index 666036a8..14face5b 100644 --- a/web/components/profile/user-likes-button.tsx +++ b/web/components/profile/user-likes-button.tsx @@ -7,7 +7,7 @@ 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 { unLikeItem } from 'web/lib/firebase/likes' import { contractPath } from 'web/lib/firebase/contracts' export function UserLikesButton(props: { user: User; className?: string }) { @@ -36,7 +36,7 @@ export function UserLikesButton(props: { user: User; className?: string }) { unLikeContract(user.id, likedContract.id)} + onClick={() => unLikeItem(user.id, likedContract.id)} /> ))} diff --git a/web/hooks/use-tip-txns.ts b/web/hooks/use-tip-txns.ts index 8726fd6e..71381d6d 100644 --- a/web/hooks/use-tip-txns.ts +++ b/web/hooks/use-tip-txns.ts @@ -33,14 +33,14 @@ export function useTipTxns(on: { }, [txns]) } -export function useMarketTipTxns(contractId: string): TipTxn[] { +export function useItemTipTxns(itemId: string): TipTxn[] { const [txns, setTxns] = useState([]) useEffect(() => { - return listenForTipTxns(contractId, (txns) => { + return listenForTipTxns(itemId, (txns) => { setTxns(txns.filter((txn) => !txn.data.commentId)) }) - }, [contractId]) + }, [itemId]) return txns } diff --git a/web/lib/firebase/likes.ts b/web/lib/firebase/likes.ts index f16bedb7..89c4864f 100644 --- a/web/lib/firebase/likes.ts +++ b/web/lib/firebase/likes.ts @@ -6,18 +6,23 @@ import { removeUndefinedProps } from 'common/util/object' import { Like, LIKE_TIP_AMOUNT } from 'common/like' import { track } from '@amplitude/analytics-browser' import { User } from 'common/user' +import { Post } from 'common/post' import { Contract } from 'common/contract' function getLikesCollection(userId: string) { return collection(db, 'users', userId, 'likes') } -export const unLikeContract = async (userId: string, contractId: string) => { - const ref = await doc(getLikesCollection(userId), contractId) +export const unLikeItem = async (userId: string, itemId: string) => { + const ref = await doc(getLikesCollection(userId), itemId) return await deleteDoc(ref) } -export const likeContract = async (user: User, contract: Contract) => { +export const likeItem = async ( + user: User, + item: Contract | Post, + itemType: string +) => { if (user.balance < LIKE_TIP_AMOUNT) { toast('You do not have enough M$ to like this market!') return @@ -28,27 +33,27 @@ export const likeContract = async (user: User, contract: Contract) => { amount: LIKE_TIP_AMOUNT, fromId: user.id, fromType: 'USER', - toId: contract.creatorId, + toId: item.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} `, + data: { contractId: item.id }, + description: `${user.name} liked ${itemType}${item.id} for M$ ${LIKE_TIP_AMOUNT} to ${item.creatorId} `, }) console.log('result', result) } // create new like in db under users collection - const ref = doc(getLikesCollection(user.id), contract.id) + const ref = doc(getLikesCollection(user.id), item.id) // contract slug and question are set via trigger const like = removeUndefinedProps({ id: ref.id, userId: user.id, createdTime: Date.now(), - type: 'contract', + type: itemType, tipTxnId: result.txn.id, } as Like) track('like', { - contractId: contract.id, + itemId: item.id, }) await setDoc(ref, like) } diff --git a/web/pages/post/[...slugs]/index.tsx b/web/pages/post/[...slugs]/index.tsx index fdcb76e3..be0876c2 100644 --- a/web/pages/post/[...slugs]/index.tsx +++ b/web/pages/post/[...slugs]/index.tsx @@ -26,6 +26,7 @@ import { useUser } from 'web/hooks/use-user' import { usePost } from 'web/hooks/use-post' import { SEO } from 'web/components/SEO' import { Subtitle } from 'web/components/subtitle' +import { LikeItemButton } from 'web/components/contract/like-item-button' export async function getStaticProps(props: { params: { slugs: string[] } }) { const { slugs } = props.params @@ -81,7 +82,7 @@ export default function PostPage(props: {
- +
Created by
@@ -92,27 +93,31 @@ export default function PostPage(props: { />
- - - + + + + + + +