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 (
<>
- {(outcomeType === 'FREE_RESPONSE' ||
- outcomeType === 'MULTIPLE_CHOICE') &&
- !resolution && (
-
-
-
- )}
+
{isBinary && (
+
{tradingAllowed(contract) && (
-
-
-
{!user && (
@@ -98,11 +94,9 @@ export const ContractOverview = (props: {
) : isPseudoNumeric ? (
+
{tradingAllowed(contract) && (
-
-
-
{!user && (
@@ -130,13 +124,6 @@ export const ContractOverview = (props: {
)}
-
-
{(isBinary || isPseudoNumeric) && (
@@ -144,10 +131,17 @@ export const ContractOverview = (props: {
)}{' '}
{(outcomeType === 'FREE_RESPONSE' ||
outcomeType === 'MULTIPLE_CHOICE') && (
-
+
+
+
+
)}
{outcomeType === 'NUMERIC' && }
-
+
+
+
+
+
+
+
+
+
+ )
+}
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 =
+ const showChallenge =
+ user && outcomeType === 'BINARY' && !resolution && CHALLENGES_ENABLED
const shareUrl = `https://${ENV_CONFIG.domain}${contractPath(contract)}${
user?.username && contract.creatorUsername !== user?.username
@@ -46,7 +54,6 @@ export function ShareModal(props: {
{' '}
if a new user signs up using the link!
-
-
-
+ {showChallenge && (
+
+ )}
+
-
-
- {showChallenge && (
-
- )}
-
-
-
-
-
- )
-}
diff --git a/web/components/follow-market-button.tsx b/web/components/follow-market-button.tsx
index 45d26ce4..332b044a 100644
--- a/web/components/follow-market-button.tsx
+++ b/web/components/follow-market-button.tsx
@@ -13,7 +13,7 @@ import { firebaseLogin, updateUser } from 'web/lib/firebase/users'
import { track } from 'web/lib/service/analytics'
import { FollowMarketModal } from 'web/components/contract/follow-market-modal'
import { useState } from 'react'
-import { Row } from 'web/components/layout/row'
+import { Col } from 'web/components/layout/col'
export const FollowMarketButton = (props: {
contract: Contract
@@ -55,15 +55,15 @@ export const FollowMarketButton = (props: {
}}
>
{followers?.includes(user?.id ?? 'nope') ? (
-
+
Unwatch
-
+
) : (
-
+
Watch
-
+
)}
= 3
+ firstName.length >= 4
? firstName.length < maxLength
? firstName
: firstName.substring(0, maxLength - 3) + '...'
diff --git a/web/pages/embed/[username]/[contractSlug].tsx b/web/pages/embed/[username]/[contractSlug].tsx
index afec84bb..793d2458 100644
--- a/web/pages/embed/[username]/[contractSlug].tsx
+++ b/web/pages/embed/[username]/[contractSlug].tsx
@@ -107,9 +107,8 @@ export function ContractEmbed(props: { contract: Contract; bets: Bet[] }) {