From 0cb20d89ed005ef4cd8c75c585bb9851f7e8fa24 Mon Sep 17 00:00:00 2001 From: mantikoros Date: Fri, 2 Sep 2022 10:35:41 -0500 Subject: [PATCH 01/68] numeric market labels: LOW/HIGH instead of MIN/MAX; eliminate payout <= MIN, etc. --- web/components/bets-list.tsx | 18 ------------------ web/pages/create.tsx | 6 +++--- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx index 932d689c..a8bd43f9 100644 --- a/web/components/bets-list.tsx +++ b/web/components/bets-list.tsx @@ -8,7 +8,6 @@ import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/solid' import { Bet } from 'web/lib/firebase/bets' import { User } from 'web/lib/firebase/users' import { - formatLargeNumber, formatMoney, formatPercent, formatWithCommas, @@ -483,23 +482,6 @@ export function BetsSummary(props: {
{formatMoney(noWinnings)}
- ) : isPseudoNumeric ? ( - <> - -
- Payout if {'>='} {formatLargeNumber(contract.max)} -
-
- {formatMoney(yesWinnings)} -
- - -
- Payout if {'<='} {formatLargeNumber(contract.min)} -
-
{formatMoney(noWinnings)}
- - ) : (
diff --git a/web/pages/create.tsx b/web/pages/create.tsx index 8ea76cef..23a88ec0 100644 --- a/web/pages/create.tsx +++ b/web/pages/create.tsx @@ -314,14 +314,14 @@ export function NewContract(props: {
e.stopPropagation()} onChange={(e) => setMinString(e.target.value)} min={Number.MIN_SAFE_INTEGER} @@ -332,7 +332,7 @@ export function NewContract(props: { e.stopPropagation()} onChange={(e) => setMaxString(e.target.value)} min={Number.MIN_SAFE_INTEGER} From 4c429cd5191df0cafc980f5db0694057c20cc847 Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Fri, 2 Sep 2022 12:51:14 -0700 Subject: [PATCH 02/68] Remove some old code related to the old feed (#843) --- web/components/feed/find-active-contracts.ts | 99 -------------------- 1 file changed, 99 deletions(-) delete mode 100644 web/components/feed/find-active-contracts.ts diff --git a/web/components/feed/find-active-contracts.ts b/web/components/feed/find-active-contracts.ts deleted file mode 100644 index ad2af970..00000000 --- a/web/components/feed/find-active-contracts.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { groupBy, mapValues, maxBy, sortBy } from 'lodash' -import { Contract } from 'web/lib/firebase/contracts' -import { ContractComment } from 'common/comment' -import { Bet } from 'common/bet' - -const MAX_ACTIVE_CONTRACTS = 75 - -// This does NOT include comment times, since those aren't part of the contract atm. -// TODO: Maybe store last activity time directly in the contract? -// Pros: simplifies this code; cons: harder to tweak "activity" definition later -function lastActivityTime(contract: Contract) { - return Math.max(contract.resolutionTime || 0, contract.createdTime) -} - -// Types of activity to surface: -// - Comment on a market -// - New market created -// - Market resolved -// - Bet on market -export function findActiveContracts( - allContracts: Contract[], - recentComments: ContractComment[], - recentBets: Bet[], - seenContracts: { [contractId: string]: number } -) { - const idToActivityTime = new Map() - function record(contractId: string, time: number) { - // Only record if the time is newer - const oldTime = idToActivityTime.get(contractId) - idToActivityTime.set(contractId, Math.max(oldTime ?? 0, time)) - } - - const contractsById = new Map(allContracts.map((c) => [c.id, c])) - - // Record contract activity. - for (const contract of allContracts) { - record(contract.id, lastActivityTime(contract)) - } - - // Add every contract that had a recent comment, too - for (const comment of recentComments) { - if (comment.contractId) { - const contract = contractsById.get(comment.contractId) - if (contract) record(contract.id, comment.createdTime) - } - } - - // Add contracts by last bet time. - const contractBets = groupBy(recentBets, (bet) => bet.contractId) - const contractMostRecentBet = mapValues( - contractBets, - (bets) => maxBy(bets, (bet) => bet.createdTime) as Bet - ) - for (const bet of Object.values(contractMostRecentBet)) { - const contract = contractsById.get(bet.contractId) - if (contract) record(contract.id, bet.createdTime) - } - - let activeContracts = allContracts.filter( - (contract) => - contract.visibility === 'public' && - !contract.isResolved && - (contract.closeTime ?? Infinity) > Date.now() - ) - activeContracts = sortBy( - activeContracts, - (c) => -(idToActivityTime.get(c.id) ?? 0) - ) - - const contractComments = groupBy( - recentComments, - (comment) => comment.contractId - ) - const contractMostRecentComment = mapValues( - contractComments, - (comments) => maxBy(comments, (c) => c.createdTime) as ContractComment - ) - - const prioritizedContracts = sortBy(activeContracts, (c) => { - const seenTime = seenContracts[c.id] - if (!seenTime) { - return 0 - } - - const lastCommentTime = contractMostRecentComment[c.id]?.createdTime - if (lastCommentTime && lastCommentTime > seenTime) { - return 1 - } - - const lastBetTime = contractMostRecentBet[c.id]?.createdTime - if (lastBetTime && lastBetTime > seenTime) { - return 2 - } - - return seenTime - }) - - return prioritizedContracts.slice(0, MAX_ACTIVE_CONTRACTS) -} From 21b9d0efab69735d74ac75eec05a1b1fcce28c0f Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Fri, 2 Sep 2022 12:51:27 -0700 Subject: [PATCH 03/68] Clean up some old pre-Amplitude tracking code (#841) --- web/components/bets-list.tsx | 11 +----- web/hooks/use-time-since-first-render.ts | 13 ------- web/lib/firebase/tracking.ts | 43 ------------------------ 3 files changed, 1 insertion(+), 66 deletions(-) delete mode 100644 web/hooks/use-time-since-first-render.ts delete mode 100644 web/lib/firebase/tracking.ts diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx index a8bd43f9..b4538767 100644 --- a/web/components/bets-list.tsx +++ b/web/components/bets-list.tsx @@ -1,7 +1,7 @@ import Link from 'next/link' import { keyBy, groupBy, mapValues, sortBy, partition, sumBy } from 'lodash' import dayjs from 'dayjs' -import { useEffect, useMemo, useState } from 'react' +import { useMemo, useState } from 'react' import clsx from 'clsx' import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/solid' @@ -34,8 +34,6 @@ import { resolvedPayout, getContractBetNullMetrics, } from 'common/calculate' -import { useTimeSinceFirstRender } from 'web/hooks/use-time-since-first-render' -import { trackLatency } from 'web/lib/firebase/tracking' import { NumericContract } from 'common/contract' import { formatNumericProbability } from 'common/pseudo-numeric' import { useUser } from 'web/hooks/use-user' @@ -84,13 +82,6 @@ export function BetsList(props: { user: User }) { const start = page * CONTRACTS_PER_PAGE const end = start + CONTRACTS_PER_PAGE - const getTime = useTimeSinceFirstRender() - useEffect(() => { - if (bets && contractsById && signedInUser) { - trackLatency(signedInUser.id, 'portfolio', getTime()) - } - }, [signedInUser, bets, contractsById, getTime]) - if (!bets || !contractsById) { return } diff --git a/web/hooks/use-time-since-first-render.ts b/web/hooks/use-time-since-first-render.ts deleted file mode 100644 index da132146..00000000 --- a/web/hooks/use-time-since-first-render.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useCallback, useEffect, useRef } from 'react' - -export function useTimeSinceFirstRender() { - const startTimeRef = useRef(0) - useEffect(() => { - startTimeRef.current = Date.now() - }, []) - - return useCallback(() => { - if (!startTimeRef.current) return 0 - return Date.now() - startTimeRef.current - }, []) -} diff --git a/web/lib/firebase/tracking.ts b/web/lib/firebase/tracking.ts deleted file mode 100644 index d1828e01..00000000 --- a/web/lib/firebase/tracking.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { doc, collection, setDoc } from 'firebase/firestore' - -import { db } from './init' -import { ClickEvent, LatencyEvent, View } from 'common/tracking' - -export async function trackView(userId: string, contractId: string) { - const ref = doc(collection(db, 'private-users', userId, 'views')) - - const view: View = { - contractId, - timestamp: Date.now(), - } - - return await setDoc(ref, view) -} - -export async function trackClick(userId: string, contractId: string) { - const ref = doc(collection(db, 'private-users', userId, 'events')) - - const clickEvent: ClickEvent = { - type: 'click', - contractId, - timestamp: Date.now(), - } - - return await setDoc(ref, clickEvent) -} - -export async function trackLatency( - userId: string, - type: 'feed' | 'portfolio', - latency: number -) { - const ref = doc(collection(db, 'private-users', userId, 'latency')) - - const latencyEvent: LatencyEvent = { - type, - latency, - timestamp: Date.now(), - } - - return await setDoc(ref, latencyEvent) -} From b1bb6fab5b71854bdb1b25e041588fec367a5f84 Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Fri, 2 Sep 2022 12:51:41 -0700 Subject: [PATCH 04/68] Disable SSR on /home (#839) --- web/pages/home.tsx | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/web/pages/home.tsx b/web/pages/home.tsx index ff4854d7..972aa639 100644 --- a/web/pages/home.tsx +++ b/web/pages/home.tsx @@ -4,23 +4,14 @@ import { PencilAltIcon } from '@heroicons/react/solid' import { Page } from 'web/components/page' import { Col } from 'web/components/layout/col' import { ContractSearch } from 'web/components/contract-search' -import { User } from 'common/user' -import { getUserAndPrivateUser } from 'web/lib/firebase/users' import { useTracking } from 'web/hooks/use-tracking' +import { useUser } from 'web/hooks/use-user' import { track } from 'web/lib/service/analytics' -import { authenticateOnServer } from 'web/lib/firebase/server-auth' import { useSaveReferral } from 'web/hooks/use-save-referral' -import { GetServerSideProps } from 'next' import { usePrefetch } from 'web/hooks/use-prefetch' -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const creds = await authenticateOnServer(ctx) - const auth = creds ? await getUserAndPrivateUser(creds.uid) : null - return { props: { auth } } -} - -const Home = (props: { auth: { user: User } | null }) => { - const user = props.auth ? props.auth.user : null +const Home = () => { + const user = useUser() const router = useRouter() useTracking('view home') From a429a98a29c5dd9e61ee578c232070055226fbad Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Fri, 2 Sep 2022 12:52:27 -0700 Subject: [PATCH 05/68] Tidy up some dead code and markup in sidebar (#842) --- web/components/create-question-button.tsx | 26 ++++++----------------- web/components/nav/menu.tsx | 10 ++++----- web/components/nav/profile-menu.tsx | 2 +- web/components/nav/sidebar.tsx | 10 +++------ web/components/notifications-icon.tsx | 12 +++++------ 5 files changed, 19 insertions(+), 41 deletions(-) diff --git a/web/components/create-question-button.tsx b/web/components/create-question-button.tsx index c7299904..20225b78 100644 --- a/web/components/create-question-button.tsx +++ b/web/components/create-question-button.tsx @@ -1,27 +1,13 @@ import React from 'react' import Link from 'next/link' -import clsx from 'clsx' - -import { User } from 'web/lib/firebase/users' import { Button } from './button' -export const CreateQuestionButton = (props: { - user: User | null | undefined - overrideText?: string - className?: string - query?: string -}) => { - const { user, overrideText, className, query } = props - - if (!user || user?.isBannedFromPosting) return <> - +export const CreateQuestionButton = () => { return ( -
- - - -
+ + + ) } diff --git a/web/components/nav/menu.tsx b/web/components/nav/menu.tsx index 07ee5c77..f61ebad9 100644 --- a/web/components/nav/menu.tsx +++ b/web/components/nav/menu.tsx @@ -19,12 +19,10 @@ export function MenuButton(props: { as="div" className={clsx(className ? className : 'relative z-40 flex-shrink-0')} > -
- - Open user menu - {buttonContent} - -
+ + Open user menu + {buttonContent} + diff --git a/web/components/nav/sidebar.tsx b/web/components/nav/sidebar.tsx index 1b030098..d7adfa28 100644 --- a/web/components/nav/sidebar.tsx +++ b/web/components/nav/sidebar.tsx @@ -234,11 +234,7 @@ export default function Sidebar(props: { className?: string }) { {!user && } - {user && ( -
- -
- )} + {user && } {/* Mobile navigation */}
@@ -255,7 +251,7 @@ export default function Sidebar(props: { className?: string }) {
{/* Desktop navigation */} -
+
{navigationOptions.map((item) => ( ))} @@ -264,7 +260,7 @@ export default function Sidebar(props: { className?: string }) { buttonContent={} /> - {user && } + {user && !user.isBannedFromPosting && }
) diff --git a/web/components/notifications-icon.tsx b/web/components/notifications-icon.tsx index 55284e96..2438fbed 100644 --- a/web/components/notifications-icon.tsx +++ b/web/components/notifications-icon.tsx @@ -12,11 +12,9 @@ export default function NotificationsIcon(props: { className?: string }) { const privateUser = usePrivateUser() return ( - -
- {privateUser && } - -
+ + {privateUser && } + ) } @@ -32,11 +30,11 @@ function UnseenNotificationsBubble(props: { privateUser: PrivateUser }) { const notifications = useUnseenGroupedNotification(privateUser) if (!notifications || notifications.length === 0 || seen) { - return
+ return null } return ( -
+
{notifications.length > NOTIFICATIONS_PER_PAGE ? `${NOTIFICATIONS_PER_PAGE}+` : notifications.length} From 245627a3476ff86b9bf1f49bc5c059abfe54122d Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Fri, 2 Sep 2022 13:00:38 -0700 Subject: [PATCH 06/68] Temporarily patch groups loading to make dev deploy work --- web/pages/groups.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/pages/groups.tsx b/web/pages/groups.tsx index aaf1374c..9ef2d8ff 100644 --- a/web/pages/groups.tsx +++ b/web/pages/groups.tsx @@ -21,7 +21,11 @@ import { SEO } from 'web/components/SEO' import { UserLink } from 'web/components/user-link' export async function getStaticProps() { - const groups = await listAllGroups().catch((_) => []) + let groups = await listAllGroups().catch((_) => []) + + // mqp: temporary fix to make dev deploy while Ian works on migrating groups away + // from the document array member and contracts representation + groups = groups.filter((g) => g.contractIds != null && g.memberIds != null) const creators = await Promise.all( groups.map((group) => getUser(group.creatorId)) From d1e1937195970dfcf6b2dd86a7b15954c60ee93a Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Fri, 2 Sep 2022 13:04:00 -0700 Subject: [PATCH 07/68] Remove custom token generation machinery (#840) --- functions/src/get-custom-token.ts | 33 ------------------------------- functions/src/index.ts | 3 --- functions/src/serve.ts | 2 -- 3 files changed, 38 deletions(-) delete mode 100644 functions/src/get-custom-token.ts diff --git a/functions/src/get-custom-token.ts b/functions/src/get-custom-token.ts deleted file mode 100644 index 4aaaac11..00000000 --- a/functions/src/get-custom-token.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as admin from 'firebase-admin' -import { - APIError, - EndpointDefinition, - lookupUser, - parseCredentials, - writeResponseError, -} from './api' - -const opts = { - method: 'GET', - minInstances: 1, - concurrency: 100, - memory: '2GiB', - cpu: 1, -} as const - -export const getcustomtoken: EndpointDefinition = { - opts, - handler: async (req, res) => { - try { - const credentials = await parseCredentials(req) - if (credentials.kind != 'jwt') { - throw new APIError(403, 'API keys cannot mint custom tokens.') - } - const user = await lookupUser(credentials) - const token = await admin.auth().createCustomToken(user.uid) - res.status(200).json({ token: token }) - } catch (e) { - writeResponseError(e, res) - } - }, -} diff --git a/functions/src/index.ts b/functions/src/index.ts index 2ec7f3ce..9a5ec872 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -72,7 +72,6 @@ import { unsubscribe } from './unsubscribe' import { stripewebhook, createcheckoutsession } from './stripe' import { getcurrentuser } from './get-current-user' import { acceptchallenge } from './accept-challenge' -import { getcustomtoken } from './get-custom-token' import { createpost } from './create-post' const toCloudFunction = ({ opts, handler }: EndpointDefinition) => { @@ -98,7 +97,6 @@ const stripeWebhookFunction = toCloudFunction(stripewebhook) const createCheckoutSessionFunction = toCloudFunction(createcheckoutsession) const getCurrentUserFunction = toCloudFunction(getcurrentuser) const acceptChallenge = toCloudFunction(acceptchallenge) -const getCustomTokenFunction = toCloudFunction(getcustomtoken) const createPostFunction = toCloudFunction(createpost) export { @@ -122,6 +120,5 @@ export { createCheckoutSessionFunction as createcheckoutsession, getCurrentUserFunction as getcurrentuser, acceptChallenge as acceptchallenge, - getCustomTokenFunction as getcustomtoken, createPostFunction as createpost, } diff --git a/functions/src/serve.ts b/functions/src/serve.ts index db847a70..a5291f19 100644 --- a/functions/src/serve.ts +++ b/functions/src/serve.ts @@ -26,7 +26,6 @@ import { resolvemarket } from './resolve-market' import { unsubscribe } from './unsubscribe' import { stripewebhook, createcheckoutsession } from './stripe' import { getcurrentuser } from './get-current-user' -import { getcustomtoken } from './get-custom-token' import { createpost } from './create-post' type Middleware = (req: Request, res: Response, next: NextFunction) => void @@ -66,7 +65,6 @@ addJsonEndpointRoute('/resolvemarket', resolvemarket) addJsonEndpointRoute('/unsubscribe', unsubscribe) addJsonEndpointRoute('/createcheckoutsession', createcheckoutsession) addJsonEndpointRoute('/getcurrentuser', getcurrentuser) -addEndpointRoute('/getcustomtoken', getcustomtoken) addEndpointRoute('/stripewebhook', stripewebhook, express.raw()) addEndpointRoute('/createpost', createpost) From b6449ad296ebf12385010f5ae75746e5e7062d4a Mon Sep 17 00:00:00 2001 From: mantikoros Date: Fri, 2 Sep 2022 15:32:47 -0500 Subject: [PATCH 08/68] fix bet panel warnings --- web/components/bet-panel.tsx | 64 +++++++++++++++++------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index f958ed87..311a6182 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -8,6 +8,7 @@ import { Col } from './layout/col' import { Row } from './layout/row' import { Spacer } from './layout/spacer' import { + formatLargeNumber, formatMoney, formatPercent, formatWithCommas, @@ -28,7 +29,7 @@ import { getProbability } from 'common/calculate' import { useFocus } from 'web/hooks/use-focus' import { useUserContractBets } from 'web/hooks/use-user-bets' import { calculateCpmmSale, getCpmmProbability } from 'common/calculate-cpmm' -import { getFormattedMappedValue } from 'common/pseudo-numeric' +import { getFormattedMappedValue, getMappedValue } from 'common/pseudo-numeric' import { SellRow } from './sell-row' import { useSaveBinaryShares } from './use-save-binary-shares' import { BetSignUpPrompt } from './sign-up-prompt' @@ -256,17 +257,43 @@ function BuyPanel(props: { const resultProb = getCpmmProbability(newPool, newP) const probStayedSame = formatPercent(resultProb) === formatPercent(initialProb) + const probChange = Math.abs(resultProb - initialProb) - const currentPayout = newBet.shares - const currentReturn = betAmount ? (currentPayout - betAmount) / betAmount : 0 const currentReturnPercent = formatPercent(currentReturn) const format = getFormattedMappedValue(contract) + const getValue = getMappedValue(contract) + const rawDifference = Math.abs(getValue(resultProb) - getValue(initialProb)) + const displayedDifference = isPseudoNumeric + ? formatLargeNumber(rawDifference) + : formatPercent(rawDifference) + const bankrollFraction = (betAmount ?? 0) / (user?.balance ?? 1e9) + const warning = + (betAmount ?? 0) > 10 && + bankrollFraction >= 0.5 && + bankrollFraction <= 1 ? ( + + ) : (betAmount ?? 0) > 10 && probChange >= 0.3 && bankrollFraction <= 1 ? ( + + ) : ( + <> + ) + return (
@@ -296,33 +323,7 @@ function BuyPanel(props: { inputRef={inputRef} /> - {(betAmount ?? 0) > 10 && - bankrollFraction >= 0.5 && - bankrollFraction <= 1 ? ( - - ) : ( - '' - )} - - {(betAmount ?? 0) > 10 && probChange >= 0.3 ? ( - - ) : ( - '' - )} + {warning} @@ -351,9 +352,6 @@ function BuyPanel(props: { )}
- {/* */}
From 00de66cd7910205651e8c7a94f7b154fd79f8683 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Fri, 2 Sep 2022 15:59:32 -0500 Subject: [PATCH 09/68] Leaderboard calc: update profit even when portfolio didn't change (#845) * Leaderboard calc: remove didProfitChange optimization that was incorrect * Put back didPortfolioChange for deciding whether to create new history doc. --- functions/src/update-metrics.ts | 60 +++++++++++++++------------------ 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/functions/src/update-metrics.ts b/functions/src/update-metrics.ts index 9ef3fb10..305cd80c 100644 --- a/functions/src/update-metrics.ts +++ b/functions/src/update-metrics.ts @@ -1,13 +1,12 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' -import { groupBy, isEmpty, keyBy, sum, sumBy } from 'lodash' +import { groupBy, isEmpty, keyBy, last, sortBy, sum, sumBy } from 'lodash' import { getValues, log, logMemory, writeAsync } from './utils' import { Bet } from '../../common/bet' import { Contract } from '../../common/contract' import { PortfolioMetrics, User } from '../../common/user' import { calculatePayout } from '../../common/calculate' import { DAY_MS } from '../../common/util/time' -import { last } from 'lodash' import { getLoanUpdates } from '../../common/loans' const firestore = admin.firestore() @@ -88,23 +87,20 @@ export const updateMetricsCore = async () => { currentBets ) const lastPortfolio = last(portfolioHistory) - const didProfitChange = + const didPortfolioChange = lastPortfolio === undefined || lastPortfolio.balance !== newPortfolio.balance || lastPortfolio.totalDeposits !== newPortfolio.totalDeposits || lastPortfolio.investmentValue !== newPortfolio.investmentValue - const newProfit = calculateNewProfit( - portfolioHistory, - newPortfolio, - didProfitChange - ) + const newProfit = calculateNewProfit(portfolioHistory, newPortfolio) + return { user, newCreatorVolume, newPortfolio, newProfit, - didProfitChange, + didPortfolioChange, } }) @@ -120,16 +116,20 @@ export const updateMetricsCore = async () => { const nextLoanByUser = keyBy(userPayouts, (payout) => payout.user.id) const userUpdates = userMetrics.map( - ({ user, newCreatorVolume, newPortfolio, newProfit, didProfitChange }) => { + ({ + user, + newCreatorVolume, + newPortfolio, + newProfit, + didPortfolioChange, + }) => { const nextLoanCached = nextLoanByUser[user.id]?.payout ?? 0 return { fieldUpdates: { doc: firestore.collection('users').doc(user.id), fields: { creatorVolumeCached: newCreatorVolume, - ...(didProfitChange && { - profitCached: newProfit, - }), + profitCached: newProfit, nextLoanCached, }, }, @@ -140,11 +140,7 @@ export const updateMetricsCore = async () => { .doc(user.id) .collection('portfolioHistory') .doc(), - fields: { - ...(didProfitChange && { - ...newPortfolio, - }), - }, + fields: didPortfolioChange ? newPortfolio : {}, }, } } @@ -171,15 +167,15 @@ const computeVolume = (contractBets: Bet[], since: number) => { const calculateProfitForPeriod = ( startTime: number, - portfolioHistory: PortfolioMetrics[], + descendingPortfolio: PortfolioMetrics[], currentProfit: number ) => { - const startingPortfolio = [...portfolioHistory] - .reverse() // so we search in descending order (most recent first), for efficiency - .find((p) => p.timestamp < startTime) + const startingPortfolio = descendingPortfolio.find( + (p) => p.timestamp < startTime + ) if (startingPortfolio === undefined) { - return 0 + return currentProfit } const startingProfit = calculateTotalProfit(startingPortfolio) @@ -233,28 +229,28 @@ const calculateNewPortfolioMetrics = ( const calculateNewProfit = ( portfolioHistory: PortfolioMetrics[], - newPortfolio: PortfolioMetrics, - didProfitChange: boolean + newPortfolio: PortfolioMetrics ) => { - if (!didProfitChange) { - return {} // early return for performance - } - const allTimeProfit = calculateTotalProfit(newPortfolio) + const descendingPortfolio = sortBy( + portfolioHistory, + (p) => p.timestamp + ).reverse() + const newProfit = { daily: calculateProfitForPeriod( Date.now() - 1 * DAY_MS, - portfolioHistory, + descendingPortfolio, allTimeProfit ), weekly: calculateProfitForPeriod( Date.now() - 7 * DAY_MS, - portfolioHistory, + descendingPortfolio, allTimeProfit ), monthly: calculateProfitForPeriod( Date.now() - 30 * DAY_MS, - portfolioHistory, + descendingPortfolio, allTimeProfit ), allTime: allTimeProfit, From 231d3e65c4a86a345d856dbc521c639ef49952fb Mon Sep 17 00:00:00 2001 From: James Grugett Date: Fri, 2 Sep 2022 16:19:10 -0500 Subject: [PATCH 10/68] Fix incorrect error message for no bets --- web/components/bets-list.tsx | 40 ++++++++++++++++++++--------------- web/components/pagination.tsx | 2 +- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx index b4538767..2a9a76a1 100644 --- a/web/components/bets-list.tsx +++ b/web/components/bets-list.tsx @@ -209,26 +209,27 @@ export function BetsList(props: { user: User }) { {displayedContracts.length === 0 ? ( - + ) : ( - displayedContracts.map((contract) => ( - + {displayedContracts.map((contract) => ( + + ))} + - )) + )} - - ) } @@ -236,7 +237,7 @@ export function BetsList(props: { user: User }) { const NoBets = ({ user }: { user: User }) => { const me = useUser() return ( -
+
{user.id === me?.id ? ( <> You have not made any bets yet.{' '} @@ -250,6 +251,11 @@ const NoBets = ({ user }: { user: User }) => {
) } +const NoMatchingBets = () => ( +
+ No bets matching the current filter. +
+) function ContractBets(props: { contract: Contract diff --git a/web/components/pagination.tsx b/web/components/pagination.tsx index 8c008ab0..8dde743c 100644 --- a/web/components/pagination.tsx +++ b/web/components/pagination.tsx @@ -58,7 +58,7 @@ export function Pagination(props: { const maxPage = Math.ceil(totalItems / itemsPerPage) - 1 - if (maxPage === 0) return + if (maxPage <= 0) return return (