From 7c78c59c5d292124bf80e9da3cd80e5fe755a61b Mon Sep 17 00:00:00 2001 From: Ian Philips Date: Tue, 30 Aug 2022 16:14:50 -0600 Subject: [PATCH] Show old details on lg, don't unfill heart --- functions/src/index.ts | 3 +- functions/src/on-delete-like.ts | 32 ------ .../{on-create-like.ts => on-update-like.ts} | 42 ++++++- web/components/contract/contract-details.tsx | 103 ++++++++++++++---- .../contract/contract-info-dialog.tsx | 10 +- web/components/contract/contract-overview.tsx | 48 ++++---- .../contract/extra-contract-actions-row.tsx | 58 ++++++++++ .../contract/like-market-button.tsx | 24 ++-- web/components/contract/share-modal.tsx | 38 ++++++- web/components/contract/share-row.tsx | 73 ------------- web/components/follow-market-button.tsx | 10 +- web/components/user-link.tsx | 2 +- web/pages/embed/[username]/[contractSlug].tsx | 3 +- 13 files changed, 263 insertions(+), 183 deletions(-) delete mode 100644 functions/src/on-delete-like.ts rename functions/src/{on-create-like.ts => on-update-like.ts} (61%) create mode 100644 web/components/contract/extra-contract-actions-row.tsx delete mode 100644 web/components/contract/share-row.tsx diff --git a/functions/src/index.ts b/functions/src/index.ts index 6ede39a0..2ec7f3ce 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -31,8 +31,7 @@ export * from './weekly-markets-emails' export * from './reset-betting-streaks' export * from './reset-weekly-emails-flag' export * from './on-update-contract-follow' -export * from './on-create-like' -export * from './on-delete-like' +export * from './on-update-like' // v2 export * from './health' diff --git a/functions/src/on-delete-like.ts b/functions/src/on-delete-like.ts deleted file mode 100644 index 151614b0..00000000 --- a/functions/src/on-delete-like.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as functions from 'firebase-functions' -import * as admin from 'firebase-admin' -import { Like } from '../../common/like' -import { getContract, log } from './utils' -import { uniq } from 'lodash' - -const firestore = admin.firestore() - -export const onDeleteLike = functions.firestore - .document('users/{userId}/likes/{likeId}') - .onDelete(async (change) => { - const like = change.data() as Like - if (like.type === 'contract') { - await removeContractLike(like) - } - }) - -const removeContractLike = async (like: Like) => { - const contract = await getContract(like.id) - if (!contract) { - log('Could not find contract') - return - } - const likedByUserIds = uniq(contract.likedByUserIds ?? []) - const newLikedByUserIds = likedByUserIds.filter( - (userId) => userId !== like.userId - ) - await firestore.collection('contracts').doc(like.id).update({ - likedByUserIds: newLikedByUserIds, - likedByUserCount: newLikedByUserIds.length, - }) -} diff --git a/functions/src/on-create-like.ts b/functions/src/on-update-like.ts similarity index 61% rename from functions/src/on-create-like.ts rename to functions/src/on-update-like.ts index 8c5885b0..7633c395 100644 --- a/functions/src/on-create-like.ts +++ b/functions/src/on-update-like.ts @@ -19,14 +19,36 @@ export const onCreateLike = functions.firestore } }) +export const onUpdateLike = functions.firestore + .document('users/{userId}/likes/{likeId}') + .onUpdate(async (change, context) => { + const like = change.after.data() as Like + const prevLike = change.before.data() as Like + const { eventId } = context + if (like.type === 'contract' && like.tipTxnId !== prevLike.tipTxnId) { + await handleCreateLikeNotification(like, eventId) + await updateContractLikes(like) + } + }) + +export const onDeleteLike = functions.firestore + .document('users/{userId}/likes/{likeId}') + .onDelete(async (change) => { + const like = change.data() as Like + if (like.type === 'contract') { + await removeContractLike(like) + } + }) + const updateContractLikes = async (like: Like) => { const contract = await getContract(like.id) if (!contract) { log('Could not find contract') return } - const likedByUserIds = uniq(contract.likedByUserIds ?? []) - likedByUserIds.push(like.userId) + const likedByUserIds = uniq( + (contract.likedByUserIds ?? []).concat(like.userId) + ) await firestore .collection('contracts') .doc(like.id) @@ -69,3 +91,19 @@ const handleCreateLikeNotification = async (like: Like, eventId: string) => { tipTxnData ) } + +const removeContractLike = async (like: Like) => { + const contract = await getContract(like.id) + if (!contract) { + log('Could not find contract') + return + } + const likedByUserIds = uniq(contract.likedByUserIds ?? []) + const newLikedByUserIds = likedByUserIds.filter( + (userId) => userId !== like.userId + ) + await firestore.collection('contracts').doc(like.id).update({ + likedByUserIds: newLikedByUserIds, + likedByUserCount: newLikedByUserIds.length, + }) +} diff --git a/web/components/contract/contract-details.tsx b/web/components/contract/contract-details.tsx index 72ecbb1f..55784ab6 100644 --- a/web/components/contract/contract-details.tsx +++ b/web/components/contract/contract-details.tsx @@ -16,7 +16,7 @@ import { Contract, updateContract } from 'web/lib/firebase/contracts' import { DateTimeTooltip } from '../datetime-tooltip' import { fromNow } from 'web/lib/util/time' import { Avatar } from '../avatar' -import { useState } from 'react' +import React, { useState } from 'react' import { ContractInfoDialog } from './contract-info-dialog' import { Bet } from 'common/bet' import NewContractBadge from '../new-contract-badge' @@ -35,6 +35,8 @@ import { contractMetrics } from 'common/contract-details' import { User } from 'common/user' import { UserLink } from 'web/components/user-link' import { FeaturedContractBadge } from 'web/components/contract/featured-contract-badge' +import { Tooltip } from 'web/components/tooltip' +import { useWindowSize } from 'web/hooks/use-window-size' export type ShowTime = 'resolve-date' | 'close-date' @@ -152,6 +154,8 @@ export function ContractDetails(props: { groupLinks?.sort((a, b) => a.createdTime - b.createdTime)[0] ?? null const user = useUser() const [open, setOpen] = useState(false) + const { width } = useWindowSize() + const isMobile = (width ?? 0) < 768 const groupInfo = ( @@ -178,6 +182,7 @@ export function ContractDetails(props: { className="whitespace-nowrap" name={creatorName} username={creatorUsername} + short={isMobile} /> )} {!disabled && } @@ -228,7 +233,7 @@ export function ContractDetails(props: { {(!!closeTime || !!resolvedDate) && ( - + {resolvedDate && contract.resolutionTime ? ( <> @@ -255,17 +260,81 @@ export function ContractDetails(props: { )} {user && ( <> - +
{volumeLabel}
- {!disabled && } + {!disabled && ( + + )} )}
) } +export function ExtraMobileContractDetails(props: { + contract: Contract + user: User | null | undefined + forceShowVolume?: boolean +}) { + const { contract, user, forceShowVolume } = props + const { resolvedDate } = contractMetrics(contract) + const volumeTranslation = + contract.volume > 1000 ? 'High' : contract.volume > 200 ? 'Medium' : 'Low' + + return ( + + {resolvedDate && contract.resolutionTime ? ( + + + + {resolvedDate} + + + Ended + + ) : ( + !resolvedDate && + contract.closeTime && ( + + + + + + + Ends + + ) + )} + {(user || forceShowVolume) && ( + + + {volumeTranslation} + + Activity + + )} + + ) +} + function EditableCloseDate(props: { closeTime: number contract: Contract @@ -340,28 +409,24 @@ function EditableCloseDate(props: { Date.now() ? 'Trading ends:' : 'Trading ended:'} time={closeTime} + className={isCreator ? 'cursor-pointer' : ''} > - {isSameYear - ? dayJsCloseTime.format('MMM D') - : dayJsCloseTime.format('MMM D, YYYY')} - {isSameDay && <> ({fromNow(closeTime)})} + isCreator && setIsEditingCloseTime(true)}> + {isSameYear + ? dayJsCloseTime.format('MMM D') + : dayJsCloseTime.format('MMM D, YYYY')} + {isSameDay && <> ({fromNow(closeTime)})} + )} - {isCreator && - (isEditingCloseTime ? ( + {isCreator && isEditingCloseTime && ( + - ) : ( - - ))} + + )} ) } diff --git a/web/components/contract/contract-info-dialog.tsx b/web/components/contract/contract-info-dialog.tsx index f418db06..ac8a8298 100644 --- a/web/components/contract/contract-info-dialog.tsx +++ b/web/components/contract/contract-info-dialog.tsx @@ -22,8 +22,12 @@ import ShortToggle from '../widgets/short-toggle' export const contractDetailsButtonClassName = 'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500' -export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) { - const { contract, bets } = props +export function ContractInfoDialog(props: { + contract: Contract + bets: Bet[] + className?: string +}) { + const { contract, bets, className } = props const [open, setOpen] = useState(false) const [featured, setFeatured] = useState( @@ -69,7 +73,7 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) { return ( <> + + + + + + +
+ ) +} diff --git a/web/components/contract/like-market-button.tsx b/web/components/contract/like-market-button.tsx index f4fed287..925434c9 100644 --- a/web/components/contract/like-market-button.tsx +++ b/web/components/contract/like-market-button.tsx @@ -6,10 +6,11 @@ import { User } from 'common/user' import { useUserLikes } from 'web/hooks/use-likes' import toast from 'react-hot-toast' import { formatMoney } from 'common/util/format' -import { likeContract, unLikeContract } from 'web/lib/firebase/likes' +import { likeContract } from 'web/lib/firebase/likes' import { LIKE_TIP_AMOUNT } from 'common/like' import clsx from 'clsx' -import { Row } from 'web/components/layout/row' +import { Col } from 'web/components/layout/col' +import { firebaseLogin } from 'web/lib/firebase/users' export function LikeMarketButton(props: { contract: Contract @@ -18,16 +19,12 @@ export function LikeMarketButton(props: { const { contract, user } = props const likes = useUserLikes(user?.id) - const likedContractIds = likes + const userLikedContractIds = likes ?.filter((l) => l.type === 'contract') .map((l) => l.id) - if (!user) return
const onLike = async () => { - if (likedContractIds?.includes(contract.id)) { - await unLikeContract(user.id, contract.id) - return - } + if (!user) return firebaseLogin() await likeContract(user, contract) toast(`You tipped ${contract.creatorName} ${formatMoney(LIKE_TIP_AMOUNT)}!`) } @@ -39,18 +36,19 @@ export function LikeMarketButton(props: { color={'gray-white'} onClick={onLike} > - + - Tip - + Tip + ) } diff --git a/web/components/contract/share-modal.tsx b/web/components/contract/share-modal.tsx index 2c74a5a4..5bae101d 100644 --- a/web/components/contract/share-modal.tsx +++ b/web/components/contract/share-modal.tsx @@ -12,12 +12,15 @@ import { TweetButton } from '../tweet-button' import { DuplicateContractButton } from '../copy-contract-button' import { Button } from '../button' import { copyToClipboard } from 'web/lib/util/copy' -import { track } from 'web/lib/service/analytics' +import { track, withTracking } from 'web/lib/service/analytics' import { ENV_CONFIG } from 'common/envs/constants' import { User } from 'common/user' import { SiteLink } from '../site-link' import { formatMoney } from 'common/util/format' import { REFERRAL_AMOUNT } from 'common/economy' +import { CreateChallengeModal } from 'web/components/challenges/create-challenge-modal' +import { useState } from 'react' +import { CHALLENGES_ENABLED } from 'common/challenge' export function ShareModal(props: { contract: Contract @@ -26,8 +29,13 @@ export function ShareModal(props: { setOpen: (open: boolean) => void }) { const { contract, user, isOpen, setOpen } = props + const { outcomeType, resolution } = contract + const [openCreateChallengeModal, setOpenCreateChallengeModal] = + useState(false) const linkIcon =