From 83ded17625759cb2d4975ba164e890caf9c223bd Mon Sep 17 00:00:00 2001 From: James Grugett Date: Fri, 17 Jun 2022 16:31:21 -0500 Subject: [PATCH] Revert "Comment tips (#469)" This reverts commit e567782a7da798703d3cd9140bf7d4de74b1b8c4. --- common/txn.ts | 20 +-- functions/src/transact.ts | 21 +-- web/components/charity/feed-items.tsx | 4 +- web/components/contract/contract-overview.tsx | 2 + web/components/contract/contract-tabs.tsx | 7 +- web/components/feed/activity-items.ts | 7 - web/components/feed/contract-activity.tsx | 5 +- .../feed/feed-answer-comment-group.tsx | 5 +- web/components/feed/feed-comments.tsx | 39 ++--- web/components/tipper.tsx | 157 ------------------ web/components/tooltip.tsx | 16 -- web/hooks/use-charity-txns.ts | 4 +- web/hooks/use-tip-txns.ts | 23 --- web/lib/firebase/txns.ts | 25 +-- web/pages/[username]/[contractSlug].tsx | 15 +- 15 files changed, 37 insertions(+), 313 deletions(-) delete mode 100644 web/components/tipper.tsx delete mode 100644 web/components/tooltip.tsx delete mode 100644 web/hooks/use-tip-txns.ts diff --git a/common/txn.ts b/common/txn.ts index 5bd6ca09..8beea234 100644 --- a/common/txn.ts +++ b/common/txn.ts @@ -13,27 +13,9 @@ export type Txn = { amount: number token: 'M$' // | 'USD' | MarketOutcome - category: 'CHARITY' | 'TIP' // | 'BET' - // Any extra data - data?: { [key: string]: any } + category: 'CHARITY' // | 'BET' | 'TIP' // Human-readable description description?: string } export type SourceType = 'USER' | 'CONTRACT' | 'CHARITY' | 'BANK' - -export type DonationTxn = Omit & { - fromType: 'USER' - toType: 'CHARITY' - category: 'CHARITY' -} - -export type TipTxn = Txn & { - fromType: 'USER' - toType: 'USER' - category: 'TIP' - data: { - contractId: string - commentId: string - } -} diff --git a/functions/src/transact.ts b/functions/src/transact.ts index 0c9bd696..79b5ccb8 100644 --- a/functions/src/transact.ts +++ b/functions/src/transact.ts @@ -11,17 +11,7 @@ export const transact = functions const userId = context?.auth?.uid if (!userId) return { status: 'error', message: 'Not authorized' } - const { - amount, - fromType, - fromId, - toId, - toType, - category, - token, - data: innerData, - description, - } = data + const { amount, fromType, fromId, toId, toType, description } = data if (fromType !== 'USER') return { @@ -35,7 +25,7 @@ export const transact = functions message: 'Must be authenticated with userId equal to specified fromId.', } - if (isNaN(amount) || !isFinite(amount)) + if (amount <= 0 || isNaN(amount) || !isFinite(amount)) return { status: 'error', message: 'Invalid amount' } // Run as transaction to prevent race conditions. @@ -79,10 +69,9 @@ export const transact = functions toType, amount, - category, - data: innerData, - token, - + // TODO: Unhardcode once we have non-donation txns + token: 'M$', + category: 'CHARITY', description, }) diff --git a/web/components/charity/feed-items.tsx b/web/components/charity/feed-items.tsx index 6e6def00..9a411e76 100644 --- a/web/components/charity/feed-items.tsx +++ b/web/components/charity/feed-items.tsx @@ -1,11 +1,11 @@ -import { DonationTxn } from 'common/txn' +import { Txn } from 'common/txn' import { Avatar } from '../avatar' import { useUserById } from 'web/hooks/use-users' import { UserLink } from '../user-page' import { manaToUSD } from '../../../common/util/format' import { RelativeTimestamp } from '../relative-timestamp' -export function Donation(props: { txn: DonationTxn }) { +export function Donation(props: { txn: Txn }) { const { txn } = props const user = useUserById(txn.fromId) diff --git a/web/components/contract/contract-overview.tsx b/web/components/contract/contract-overview.tsx index a68f37be..a8608ae6 100644 --- a/web/components/contract/contract-overview.tsx +++ b/web/components/contract/contract-overview.tsx @@ -13,6 +13,7 @@ import { NumericResolutionOrExpectation, } from './contract-card' import { Bet } from 'common/bet' +import { Comment } from 'common/comment' import BetRow from '../bet-row' import { AnswersGraph } from '../answers/answers-graph' import { Contract } from 'common/contract' @@ -24,6 +25,7 @@ import { NumericGraph } from './numeric-graph' export const ContractOverview = (props: { contract: Contract bets: Bet[] + comments: Comment[] className?: string }) => { const { contract, bets, className } = props diff --git a/web/components/contract/contract-tabs.tsx b/web/components/contract/contract-tabs.tsx index cb4a3537..243e62ff 100644 --- a/web/components/contract/contract-tabs.tsx +++ b/web/components/contract/contract-tabs.tsx @@ -7,16 +7,14 @@ import { ContractBetsTable, BetsSummary } from '../bets-list' import { Spacer } from '../layout/spacer' import { Tabs } from '../layout/tabs' import { Col } from '../layout/col' -import { CommentTipMap } from 'web/hooks/use-tip-txns' export function ContractTabs(props: { contract: Contract user: User | null | undefined bets: Bet[] comments: Comment[] - tips: CommentTipMap }) { - const { contract, user, bets, comments, tips } = props + const { contract, user, bets, comments } = props const { outcomeType } = contract const userBets = user && bets.filter((bet) => bet.userId === user.id) @@ -26,7 +24,6 @@ export function ContractTabs(props: { contract={contract} bets={bets} comments={comments} - tips={tips} user={user} mode="bets" betRowClassName="!mt-0 xl:hidden" @@ -39,7 +36,6 @@ export function ContractTabs(props: { contract={contract} bets={bets} comments={comments} - tips={tips} user={user} mode={ contract.outcomeType === 'FREE_RESPONSE' @@ -56,7 +52,6 @@ export function ContractTabs(props: { contract={contract} bets={bets} comments={comments} - tips={tips} user={user} mode={'comments'} betRowClassName="!mt-0 xl:hidden" diff --git a/web/components/feed/activity-items.ts b/web/components/feed/activity-items.ts index 8a71bbc2..ee7239e3 100644 --- a/web/components/feed/activity-items.ts +++ b/web/components/feed/activity-items.ts @@ -6,7 +6,6 @@ import { getOutcomeProbability } from 'common/calculate' import { Comment } from 'common/comment' import { Contract, FreeResponseContract } from 'common/contract' import { User } from 'common/user' -import { CommentTipMap } from 'web/hooks/use-tip-txns' export type ActivityItem = | DescriptionItem @@ -51,7 +50,6 @@ export type CommentThreadItem = BaseActivityItem & { type: 'commentThread' parentComment: Comment comments: Comment[] - tips: CommentTipMap bets: Bet[] } @@ -60,7 +58,6 @@ export type AnswerGroupItem = BaseActivityItem & { user: User | undefined | null answer: Answer comments: Comment[] - tips: CommentTipMap bets: Bet[] } @@ -106,7 +103,6 @@ function getAnswerAndCommentInputGroups( function getCommentThreads( bets: Bet[], comments: Comment[], - tips: CommentTipMap, contract: Contract ) { const parentComments = comments.filter((comment) => !comment.replyToCommentId) @@ -118,7 +114,6 @@ function getCommentThreads( comments: comments, parentComment: comment, bets: bets, - tips, })) return items @@ -137,7 +132,6 @@ export function getSpecificContractActivityItems( contract: Contract, bets: Bet[], comments: Comment[], - tips: CommentTipMap, user: User | null | undefined, options: { mode: 'comments' | 'bets' | 'free-response-comment-answer-groups' @@ -173,7 +167,6 @@ export function getSpecificContractActivityItems( ...getCommentThreads( nonFreeResponseBets, nonFreeResponseComments, - tips, contract ) ) diff --git a/web/components/feed/contract-activity.tsx b/web/components/feed/contract-activity.tsx index 9ffc8717..8c436333 100644 --- a/web/components/feed/contract-activity.tsx +++ b/web/components/feed/contract-activity.tsx @@ -7,20 +7,18 @@ import { getSpecificContractActivityItems } from './activity-items' import { FeedItems } from './feed-items' import { User } from 'common/user' import { useContractWithPreload } from 'web/hooks/use-contract' -import { CommentTipMap } from 'web/hooks/use-tip-txns' export function ContractActivity(props: { contract: Contract bets: Bet[] comments: Comment[] - tips: CommentTipMap user: User | null | undefined mode: 'comments' | 'bets' | 'free-response-comment-answer-groups' contractPath?: string className?: string betRowClassName?: string }) { - const { user, mode, tips, className, betRowClassName } = props + const { user, mode, className, betRowClassName } = props const contract = useContractWithPreload(props.contract) ?? props.contract @@ -33,7 +31,6 @@ export function ContractActivity(props: { contract, bets, comments, - tips, user, { mode } ) diff --git a/web/components/feed/feed-answer-comment-group.tsx b/web/components/feed/feed-answer-comment-group.tsx index e6072c30..7e9e19aa 100644 --- a/web/components/feed/feed-answer-comment-group.tsx +++ b/web/components/feed/feed-answer-comment-group.tsx @@ -24,17 +24,15 @@ import { groupBy } from 'lodash' import { User } from 'common/user' import { useEvent } from 'web/hooks/use-event' import { getDpmOutcomeProbability } from 'common/calculate-dpm' -import { CommentTipMap } from 'web/hooks/use-tip-txns' export function FeedAnswerCommentGroup(props: { contract: any user: User | undefined | null answer: Answer comments: Comment[] - tips: CommentTipMap bets: Bet[] }) { - const { answer, contract, comments, tips, bets, user } = props + const { answer, contract, comments, bets, user } = props const { username, avatarUrl, name, text } = answer const [replyToUsername, setReplyToUsername] = useState('') @@ -216,7 +214,6 @@ export function FeedAnswerCommentGroup(props: { smallAvatar={true} truncate={false} bets={bets} - tips={tips} scrollAndOpenReplyInput={scrollAndOpenReplyInput} treatFirstIndexEqually={true} /> diff --git a/web/components/feed/feed-comments.tsx b/web/components/feed/feed-comments.tsx index 46feca9a..daf8e197 100644 --- a/web/components/feed/feed-comments.tsx +++ b/web/components/feed/feed-comments.tsx @@ -25,27 +25,17 @@ import { getProbability } from 'common/calculate' import { LoadingIndicator } from 'web/components/loading-indicator' import { PaperAirplaneIcon } from '@heroicons/react/outline' import { track } from 'web/lib/service/analytics' -import { Tipper } from '../tipper' -import { CommentTipMap, CommentTips } from 'web/hooks/use-tip-txns' export function FeedCommentThread(props: { contract: Contract comments: Comment[] - tips: CommentTipMap parentComment: Comment bets: Bet[] truncate?: boolean smallAvatar?: boolean }) { - const { - contract, - comments, - bets, - tips, - truncate, - smallAvatar, - parentComment, - } = props + const { contract, comments, bets, truncate, smallAvatar, parentComment } = + props const [showReply, setShowReply] = useState(false) const [replyToUsername, setReplyToUsername] = useState('') const betsByUserId = groupBy(bets, (bet) => bet.userId) @@ -74,7 +64,6 @@ export function FeedCommentThread(props: { contract={contract} commentsList={commentsList} betsByUserId={betsByUserId} - tips={tips} smallAvatar={smallAvatar} truncate={truncate} bets={bets} @@ -108,7 +97,6 @@ export function CommentRepliesList(props: { contract: Contract commentsList: Comment[] betsByUserId: Dictionary - tips: CommentTipMap scrollAndOpenReplyInput: (comment: Comment) => void bets: Bet[] treatFirstIndexEqually?: boolean @@ -119,7 +107,6 @@ export function CommentRepliesList(props: { contract, commentsList, betsByUserId, - tips, truncate, smallAvatar, bets, @@ -147,7 +134,6 @@ export function CommentRepliesList(props: { - - - {onReplyClick && ( - - )} - + {onReplyClick && ( + + )} ) diff --git a/web/components/tipper.tsx b/web/components/tipper.tsx deleted file mode 100644 index 6c5a2555..00000000 --- a/web/components/tipper.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { - ChevronDoubleRightIcon, - ChevronLeftIcon, - ChevronRightIcon, -} from '@heroicons/react/solid' -import clsx from 'clsx' -import { Comment } from 'common/comment' -import { User } from 'common/user' -import { formatMoney } from 'common/util/format' -import { debounce, sumBy } from 'lodash' -import { useEffect, useMemo, useRef, useState } from 'react' -import { CommentTips } from 'web/hooks/use-tip-txns' -import { useUser } from 'web/hooks/use-user' -import { transact } from 'web/lib/firebase/fn-call' -import { Row } from './layout/row' -import { Tooltip } from './tooltip' - -// xth triangle number * 5 = 5 + 10 + 15 + ... + (x * 5) -const quad = (x: number) => (5 / 2) * x * (x + 1) - -// inverse (see https://math.stackexchange.com/questions/2041988/how-to-get-inverse-of-formula-for-sum-of-integers-from-1-to-nsee ) -const invQuad = (y: number) => Math.sqrt((2 / 5) * y + 1 / 4) - 1 / 2 - -export function Tipper(prop: { comment: Comment; tips: CommentTips }) { - const { comment, tips } = prop - - const me = useUser() - const myId = me?.id ?? '' - const savedTip = tips[myId] as number | undefined - - // optimistically increase the tip count, but debounce the update - const [localTip, setLocalTip] = useState(savedTip ?? 0) - const initialized = useRef(false) - useEffect(() => { - if (savedTip && !initialized.current) { - setLocalTip(savedTip) - initialized.current = true - } - }, [savedTip]) - - const score = useMemo(() => { - const tipVals = Object.values({ ...tips, [myId]: localTip }) - return sumBy(tipVals, invQuad) - }, [localTip, tips, myId]) - - // declare debounced function only on first render - const [saveTip] = useState(() => - debounce(async (user: User, change: number) => { - if (change === 0) { - return - } - - await transact({ - amount: change, - fromId: user.id, - fromType: 'USER', - toId: comment.userId, - toType: 'USER', - token: 'M$', - category: 'TIP', - data: { - contractId: comment.contractId, - commentId: comment.id, - }, - description: `${user.name} tipped M$ ${change} to ${comment.userName} for a comment`, - }) - }, 1500) - ) - // instant save on unrender - useEffect(() => () => void saveTip.flush(), [saveTip]) - - const changeTip = (tip: number) => { - setLocalTip(tip) - me && saveTip(me, tip - (savedTip ?? 0)) - } - - return ( - - - {Math.floor(score)} - - {localTip === 0 ? ( - '' - ) : ( - 0 ? 'text-primary' : 'text-red-400' - )} - > - ({formatMoney(localTip)} tip) - - )} - - ) -} - -function DownTip(prop: { - value: number - onChange: (tip: number) => void - disabled?: boolean -}) { - const { onChange, value, disabled } = prop - const marginal = 5 * invQuad(value) - return ( - - - - ) -} - -function UpTip(prop: { - value: number - onChange: (tip: number) => void - disabled?: boolean -}) { - const { onChange, value, disabled } = prop - const marginal = 5 * invQuad(value) + 5 - - return ( - - - - ) -} diff --git a/web/components/tooltip.tsx b/web/components/tooltip.tsx deleted file mode 100644 index 46d51762..00000000 --- a/web/components/tooltip.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import clsx from 'clsx' - -export function Tooltip( - props: { - text: string | false | undefined | null - } & JSX.IntrinsicElements['div'] -) { - const { text, children, className } = props - return text ? ( -
- {children} -
- ) : ( - <>{children} - ) -} diff --git a/web/hooks/use-charity-txns.ts b/web/hooks/use-charity-txns.ts index 25000554..13050fb1 100644 --- a/web/hooks/use-charity-txns.ts +++ b/web/hooks/use-charity-txns.ts @@ -1,9 +1,9 @@ import { useEffect, useState } from 'react' -import { DonationTxn } from 'common/txn' +import { Txn } from 'common/txn' import { listenForCharityTxns } from 'web/lib/firebase/txns' export const useCharityTxns = (charityId: string) => { - const [txns, setTxns] = useState([]) + const [txns, setTxns] = useState([]) useEffect(() => { return listenForCharityTxns(charityId, setTxns) diff --git a/web/hooks/use-tip-txns.ts b/web/hooks/use-tip-txns.ts deleted file mode 100644 index 13ef3d34..00000000 --- a/web/hooks/use-tip-txns.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { TipTxn } from 'common/txn' -import { groupBy, mapValues, sumBy } from 'lodash' -import { useEffect, useMemo, useState } from 'react' -import { listenForTipTxns } from 'web/lib/firebase/txns' - -export type CommentTips = { [userId: string]: number } -export type CommentTipMap = { [commentId: string]: CommentTips } - -export function useTipTxns(contractId: string): CommentTipMap { - const [txns, setTxns] = useState([]) - - useEffect(() => { - return listenForTipTxns(contractId, setTxns) - }, [contractId, setTxns]) - - return useMemo(() => { - const byComment = groupBy(txns, 'data.commentId') - return mapValues(byComment, (txns) => { - const bySender = groupBy(txns, 'fromId') - return mapValues(bySender, (t) => sumBy(t, 'amount')) - }) - }, [txns]) -} diff --git a/web/lib/firebase/txns.ts b/web/lib/firebase/txns.ts index 58ba7bf6..74f210d5 100644 --- a/web/lib/firebase/txns.ts +++ b/web/lib/firebase/txns.ts @@ -1,5 +1,6 @@ -import { DonationTxn, TipTxn } from 'common/txn' -import { collection, orderBy, query, where } from 'firebase/firestore' +import { collection, query, where, orderBy } from 'firebase/firestore' +import { Txn } from 'common/txn' + import { db } from './init' import { getValues, listenForValues } from './utils' @@ -15,27 +16,13 @@ const getCharityQuery = (charityId: string) => export function listenForCharityTxns( charityId: string, - setTxns: (txns: DonationTxn[]) => void + setTxns: (txns: Txn[]) => void ) { - return listenForValues(getCharityQuery(charityId), setTxns) + return listenForValues(getCharityQuery(charityId), setTxns) } const charitiesQuery = query(txnCollection, where('toType', '==', 'CHARITY')) export function getAllCharityTxns() { - return getValues(charitiesQuery) -} - -const getTipsQuery = (contractId: string) => - query( - txnCollection, - where('category', '==', 'TIP'), - where('data.contractId', '==', contractId) - ) - -export function listenForTipTxns( - contractId: string, - setTxns: (txns: TipTxn[]) => void -) { - return listenForValues(getTipsQuery(contractId), setTxns) + return getValues(charitiesQuery) } diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx index 099ba57e..a8ffd461 100644 --- a/web/pages/[username]/[contractSlug].tsx +++ b/web/pages/[username]/[contractSlug].tsx @@ -41,7 +41,6 @@ import ContractEmbedPage from '../embed/[username]/[contractSlug]' import { useBets } from 'web/hooks/use-bets' import { AlertBox } from 'web/components/alert-box' import { useTracking } from 'web/hooks/use-tracking' -import { CommentTipMap, useTipTxns } from 'web/hooks/use-tip-txns' export const getStaticProps = fromPropz(getStaticPropz) export async function getStaticPropz(props: { @@ -120,8 +119,6 @@ export function ContractPageContent( // Sort for now to see if bug is fixed. comments.sort((c1, c2) => c1.createdTime - c2.createdTime) - const tips = useTipTxns(contract.id) - const user = useUser() const { width, height } = useWindowSize() @@ -195,7 +192,11 @@ export function ContractPageContent( )} - + {isNumeric && ( @@ -234,7 +234,6 @@ export function ContractPageContent( contract={contract} user={user} bets={bets} - tips={tips} comments={comments} /> @@ -291,9 +290,8 @@ function ContractTopTrades(props: { contract: Contract bets: Bet[] comments: Comment[] - tips: CommentTipMap }) { - const { contract, bets, comments, tips } = props + const { contract, bets, comments } = props const commentsById = keyBy(comments, 'id') const betsById = keyBy(bets, 'id') @@ -330,7 +328,6 @@ function ContractTopTrades(props: {