⚡ Cache user bets tab with react query!! (#813)
* Convert useUserBets to react query * Fix duplicate key warnings * Fix react-query workaround to use refetchOnMount: always' * Use react query for portfolio history * Fix useUserBet workaround * Script to back fill unique bettors in all contracts * React query for user bet contracts, using uniqueBettorsId! * Prefetch user bets / portfolio data
This commit is contained in:
parent
7e00f29189
commit
996b4795ea
39
functions/src/scripts/backfill-unique-bettors.ts
Normal file
39
functions/src/scripts/backfill-unique-bettors.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import * as admin from 'firebase-admin'
|
||||||
|
import { initAdmin } from './script-init'
|
||||||
|
import { getValues, log, writeAsync } from '../utils'
|
||||||
|
import { Bet } from '../../../common/bet'
|
||||||
|
import { groupBy, mapValues, sortBy, uniq } from 'lodash'
|
||||||
|
|
||||||
|
initAdmin()
|
||||||
|
const firestore = admin.firestore()
|
||||||
|
|
||||||
|
const getBettorsByContractId = async () => {
|
||||||
|
const bets = await getValues<Bet>(firestore.collectionGroup('bets'))
|
||||||
|
log(`Loaded ${bets.length} bets.`)
|
||||||
|
const betsByContractId = groupBy(bets, 'contractId')
|
||||||
|
return mapValues(betsByContractId, (bets) =>
|
||||||
|
uniq(sortBy(bets, 'createdTime').map((bet) => bet.userId))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateUniqueBettors = async () => {
|
||||||
|
const bettorsByContractId = await getBettorsByContractId()
|
||||||
|
|
||||||
|
const updates = Object.entries(bettorsByContractId).map(
|
||||||
|
([contractId, userIds]) => {
|
||||||
|
const update = {
|
||||||
|
uniqueBettorIds: userIds,
|
||||||
|
uniqueBettorCount: userIds.length,
|
||||||
|
}
|
||||||
|
const docRef = firestore.collection('contracts').doc(contractId)
|
||||||
|
return { doc: docRef, fields: update }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
log(`Updating ${updates.length} contracts.`)
|
||||||
|
await writeAsync(firestore, updates)
|
||||||
|
log(`Updated all contracts.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
updateUniqueBettors()
|
||||||
|
}
|
|
@ -1,14 +1,5 @@
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import {
|
import { keyBy, groupBy, mapValues, sortBy, partition, sumBy } from 'lodash'
|
||||||
Dictionary,
|
|
||||||
keyBy,
|
|
||||||
groupBy,
|
|
||||||
mapValues,
|
|
||||||
sortBy,
|
|
||||||
partition,
|
|
||||||
sumBy,
|
|
||||||
uniq,
|
|
||||||
} from 'lodash'
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
@ -28,7 +19,6 @@ import {
|
||||||
Contract,
|
Contract,
|
||||||
contractPath,
|
contractPath,
|
||||||
getBinaryProbPercent,
|
getBinaryProbPercent,
|
||||||
getContractFromId,
|
|
||||||
} from 'web/lib/firebase/contracts'
|
} from 'web/lib/firebase/contracts'
|
||||||
import { Row } from './layout/row'
|
import { Row } from './layout/row'
|
||||||
import { UserLink } from './user-page'
|
import { UserLink } from './user-page'
|
||||||
|
@ -56,9 +46,9 @@ import { SellSharesModal } from './sell-modal'
|
||||||
import { useUnfilledBets } from 'web/hooks/use-bets'
|
import { useUnfilledBets } from 'web/hooks/use-bets'
|
||||||
import { LimitBet } from 'common/bet'
|
import { LimitBet } from 'common/bet'
|
||||||
import { floatingEqual } from 'common/util/math'
|
import { floatingEqual } from 'common/util/math'
|
||||||
import { filterDefined } from 'common/util/array'
|
|
||||||
import { Pagination } from './pagination'
|
import { Pagination } from './pagination'
|
||||||
import { LimitOrderTable } from './limit-bets'
|
import { LimitOrderTable } from './limit-bets'
|
||||||
|
import { useUserBetContracts } from 'web/hooks/use-contracts'
|
||||||
|
|
||||||
type BetSort = 'newest' | 'profit' | 'closeTime' | 'value'
|
type BetSort = 'newest' | 'profit' | 'closeTime' | 'value'
|
||||||
type BetFilter = 'open' | 'limit_bet' | 'sold' | 'closed' | 'resolved' | 'all'
|
type BetFilter = 'open' | 'limit_bet' | 'sold' | 'closed' | 'resolved' | 'all'
|
||||||
|
@ -72,26 +62,22 @@ export function BetsList(props: { user: User }) {
|
||||||
const signedInUser = useUser()
|
const signedInUser = useUser()
|
||||||
const isYourBets = user.id === signedInUser?.id
|
const isYourBets = user.id === signedInUser?.id
|
||||||
const hideBetsBefore = isYourBets ? 0 : JUNE_1_2022
|
const hideBetsBefore = isYourBets ? 0 : JUNE_1_2022
|
||||||
const userBets = useUserBets(user.id, { includeRedemptions: true })
|
const userBets = useUserBets(user.id)
|
||||||
const [contractsById, setContractsById] = useState<
|
|
||||||
Dictionary<Contract> | undefined
|
|
||||||
>()
|
|
||||||
|
|
||||||
// Hide bets before 06-01-2022 if this isn't your own profile
|
// Hide bets before 06-01-2022 if this isn't your own profile
|
||||||
// NOTE: This means public profits also begin on 06-01-2022 as well.
|
// NOTE: This means public profits also begin on 06-01-2022 as well.
|
||||||
const bets = useMemo(
|
const bets = useMemo(
|
||||||
() => userBets?.filter((bet) => bet.createdTime >= (hideBetsBefore ?? 0)),
|
() =>
|
||||||
|
userBets?.filter(
|
||||||
|
(bet) => !bet.isAnte && bet.createdTime >= (hideBetsBefore ?? 0)
|
||||||
|
),
|
||||||
[userBets, hideBetsBefore]
|
[userBets, hideBetsBefore]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
const contractList = useUserBetContracts(user.id)
|
||||||
if (bets) {
|
const contractsById = useMemo(() => {
|
||||||
const contractIds = uniq(bets.map((b) => b.contractId))
|
return contractList ? keyBy(contractList, 'id') : undefined
|
||||||
Promise.all(contractIds.map(getContractFromId)).then((contracts) => {
|
}, [contractList])
|
||||||
setContractsById(keyBy(filterDefined(contracts), 'id'))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [bets])
|
|
||||||
|
|
||||||
const [sort, setSort] = useState<BetSort>('newest')
|
const [sort, setSort] = useState<BetSort>('newest')
|
||||||
const [filter, setFilter] = useState<BetFilter>('open')
|
const [filter, setFilter] = useState<BetFilter>('open')
|
||||||
|
|
|
@ -319,7 +319,7 @@ function GroupsList(props: { currentPage: string; memberItems: Item[] }) {
|
||||||
{memberItems.map((item) => (
|
{memberItems.map((item) => (
|
||||||
<a
|
<a
|
||||||
href={item.href}
|
href={item.href}
|
||||||
key={item.name}
|
key={item.href}
|
||||||
onClick={trackCallback('click sidebar group', { name: item.name })}
|
onClick={trackCallback('click sidebar group', { name: item.name })}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'cursor-pointer truncate',
|
'cursor-pointer truncate',
|
||||||
|
|
|
@ -1,43 +1,26 @@
|
||||||
import { PortfolioMetrics } from 'common/user'
|
|
||||||
import { formatMoney } from 'common/util/format'
|
import { formatMoney } from 'common/util/format'
|
||||||
import { last } from 'lodash'
|
import { last } from 'lodash'
|
||||||
import { memo, useEffect, useState } from 'react'
|
import { memo, useRef, useState } from 'react'
|
||||||
import { Period, getPortfolioHistory } from 'web/lib/firebase/users'
|
import { usePortfolioHistory } from 'web/hooks/use-portfolio-history'
|
||||||
|
import { Period } from 'web/lib/firebase/users'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
import { Row } from '../layout/row'
|
import { Row } from '../layout/row'
|
||||||
import { PortfolioValueGraph } from './portfolio-value-graph'
|
import { PortfolioValueGraph } from './portfolio-value-graph'
|
||||||
import { DAY_MS } from 'common/util/time'
|
|
||||||
|
|
||||||
const periodToCutoff = (now: number, period: Period) => {
|
|
||||||
switch (period) {
|
|
||||||
case 'daily':
|
|
||||||
return now - 1 * DAY_MS
|
|
||||||
case 'weekly':
|
|
||||||
return now - 7 * DAY_MS
|
|
||||||
case 'monthly':
|
|
||||||
return now - 30 * DAY_MS
|
|
||||||
case 'allTime':
|
|
||||||
default:
|
|
||||||
return new Date(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PortfolioValueSection = memo(
|
export const PortfolioValueSection = memo(
|
||||||
function PortfolioValueSection(props: { userId: string }) {
|
function PortfolioValueSection(props: { userId: string }) {
|
||||||
const { userId } = props
|
const { userId } = props
|
||||||
|
|
||||||
const [portfolioPeriod, setPortfolioPeriod] = useState<Period>('weekly')
|
const [portfolioPeriod, setPortfolioPeriod] = useState<Period>('weekly')
|
||||||
const [portfolioHistory, setUsersPortfolioHistory] = useState<
|
const portfolioHistory = usePortfolioHistory(userId, portfolioPeriod)
|
||||||
PortfolioMetrics[]
|
|
||||||
>([])
|
|
||||||
|
|
||||||
useEffect(() => {
|
// Remember the last defined portfolio history.
|
||||||
const cutoff = periodToCutoff(Date.now(), portfolioPeriod).valueOf()
|
const portfolioRef = useRef(portfolioHistory)
|
||||||
getPortfolioHistory(userId, cutoff).then(setUsersPortfolioHistory)
|
if (portfolioHistory) portfolioRef.current = portfolioHistory
|
||||||
}, [portfolioPeriod, userId])
|
const currPortfolioHistory = portfolioRef.current
|
||||||
|
|
||||||
const lastPortfolioMetrics = last(portfolioHistory)
|
const lastPortfolioMetrics = last(currPortfolioHistory)
|
||||||
if (portfolioHistory.length === 0 || !lastPortfolioMetrics) {
|
if (!currPortfolioHistory || !lastPortfolioMetrics) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +47,7 @@ export const PortfolioValueSection = memo(
|
||||||
</select>
|
</select>
|
||||||
</Row>
|
</Row>
|
||||||
<PortfolioValueGraph
|
<PortfolioValueGraph
|
||||||
portfolioHistory={portfolioHistory}
|
portfolioHistory={currPortfolioHistory}
|
||||||
includeTime={portfolioPeriod == 'daily'}
|
includeTime={portfolioPeriod == 'daily'}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useFirestoreQueryData } from '@react-query-firebase/firestore'
|
||||||
import { isEqual } from 'lodash'
|
import { isEqual } from 'lodash'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
|
@ -8,6 +9,7 @@ import {
|
||||||
listenForHotContracts,
|
listenForHotContracts,
|
||||||
listenForInactiveContracts,
|
listenForInactiveContracts,
|
||||||
listenForNewContracts,
|
listenForNewContracts,
|
||||||
|
getUserBetContractsQuery,
|
||||||
} from 'web/lib/firebase/contracts'
|
} from 'web/lib/firebase/contracts'
|
||||||
|
|
||||||
export const useContracts = () => {
|
export const useContracts = () => {
|
||||||
|
@ -89,3 +91,15 @@ export const useUpdatedContracts = (contracts: Contract[] | undefined) => {
|
||||||
? contracts.map((c) => contractDict.current[c.id])
|
? contracts.map((c) => contractDict.current[c.id])
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useUserBetContracts = (userId: string) => {
|
||||||
|
const result = useFirestoreQueryData(
|
||||||
|
['contracts', 'bets', userId],
|
||||||
|
getUserBetContractsQuery(userId),
|
||||||
|
{ subscribe: true, includeMetadataChanges: true },
|
||||||
|
// Temporary workaround for react-query bug:
|
||||||
|
// https://github.com/invertase/react-query-firebase/issues/25
|
||||||
|
{ refetchOnMount: 'always' }
|
||||||
|
)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
|
@ -20,8 +20,9 @@ function useNotifications(privateUser: PrivateUser) {
|
||||||
{ subscribe: true, includeMetadataChanges: true },
|
{ subscribe: true, includeMetadataChanges: true },
|
||||||
// Temporary workaround for react-query bug:
|
// Temporary workaround for react-query bug:
|
||||||
// https://github.com/invertase/react-query-firebase/issues/25
|
// https://github.com/invertase/react-query-firebase/issues/25
|
||||||
{ cacheTime: 0 }
|
{ refetchOnMount: 'always' }
|
||||||
)
|
)
|
||||||
|
|
||||||
const notifications = useMemo(() => {
|
const notifications = useMemo(() => {
|
||||||
if (!result.data) return undefined
|
if (!result.data) return undefined
|
||||||
const notifications = result.data as Notification[]
|
const notifications = result.data as Notification[]
|
||||||
|
|
32
web/hooks/use-portfolio-history.ts
Normal file
32
web/hooks/use-portfolio-history.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { useFirestoreQueryData } from '@react-query-firebase/firestore'
|
||||||
|
import { DAY_MS, HOUR_MS } from 'common/util/time'
|
||||||
|
import { getPortfolioHistoryQuery, Period } from 'web/lib/firebase/users'
|
||||||
|
|
||||||
|
export const usePortfolioHistory = (userId: string, period: Period) => {
|
||||||
|
const nowRounded = Math.round(Date.now() / HOUR_MS) * HOUR_MS
|
||||||
|
const cutoff = periodToCutoff(nowRounded, period).valueOf()
|
||||||
|
|
||||||
|
const result = useFirestoreQueryData(
|
||||||
|
['portfolio-history', userId, cutoff],
|
||||||
|
getPortfolioHistoryQuery(userId, cutoff),
|
||||||
|
{ subscribe: true, includeMetadataChanges: true },
|
||||||
|
// Temporary workaround for react-query bug:
|
||||||
|
// https://github.com/invertase/react-query-firebase/issues/25
|
||||||
|
{ refetchOnMount: 'always' }
|
||||||
|
)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
const periodToCutoff = (now: number, period: Period) => {
|
||||||
|
switch (period) {
|
||||||
|
case 'daily':
|
||||||
|
return now - 1 * DAY_MS
|
||||||
|
case 'weekly':
|
||||||
|
return now - 7 * DAY_MS
|
||||||
|
case 'monthly':
|
||||||
|
return now - 30 * DAY_MS
|
||||||
|
case 'allTime':
|
||||||
|
default:
|
||||||
|
return new Date(0)
|
||||||
|
}
|
||||||
|
}
|
11
web/hooks/use-prefetch.ts
Normal file
11
web/hooks/use-prefetch.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { useUserBetContracts } from './use-contracts'
|
||||||
|
import { usePortfolioHistory } from './use-portfolio-history'
|
||||||
|
import { useUserBets } from './use-user-bets'
|
||||||
|
|
||||||
|
export function usePrefetch(userId: string | undefined) {
|
||||||
|
const maybeUserId = userId ?? ''
|
||||||
|
|
||||||
|
useUserBets(maybeUserId)
|
||||||
|
useUserBetContracts(maybeUserId)
|
||||||
|
usePortfolioHistory(maybeUserId, 'weekly')
|
||||||
|
}
|
|
@ -1,22 +1,21 @@
|
||||||
import { uniq } from 'lodash'
|
import { useFirestoreQueryData } from '@react-query-firebase/firestore'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
Bet,
|
Bet,
|
||||||
listenForUserBets,
|
getUserBetsQuery,
|
||||||
listenForUserContractBets,
|
listenForUserContractBets,
|
||||||
} from 'web/lib/firebase/bets'
|
} from 'web/lib/firebase/bets'
|
||||||
|
|
||||||
export const useUserBets = (
|
export const useUserBets = (userId: string) => {
|
||||||
userId: string | undefined,
|
const result = useFirestoreQueryData(
|
||||||
options: { includeRedemptions: boolean }
|
['bets', userId],
|
||||||
) => {
|
getUserBetsQuery(userId),
|
||||||
const [bets, setBets] = useState<Bet[] | undefined>(undefined)
|
{ subscribe: true, includeMetadataChanges: true },
|
||||||
|
// Temporary workaround for react-query bug:
|
||||||
useEffect(() => {
|
// https://github.com/invertase/react-query-firebase/issues/25
|
||||||
if (userId) return listenForUserBets(userId, setBets, options)
|
{ refetchOnMount: 'always' }
|
||||||
}, [userId])
|
)
|
||||||
|
return result.data
|
||||||
return bets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUserContractBets = (
|
export const useUserContractBets = (
|
||||||
|
@ -33,36 +32,6 @@ export const useUserContractBets = (
|
||||||
return bets
|
return bets
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUserBetContracts = (
|
|
||||||
userId: string | undefined,
|
|
||||||
options: { includeRedemptions: boolean }
|
|
||||||
) => {
|
|
||||||
const [contractIds, setContractIds] = useState<string[] | undefined>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (userId) {
|
|
||||||
const key = `user-bet-contractIds-${userId}`
|
|
||||||
|
|
||||||
const userBetContractJson = localStorage.getItem(key)
|
|
||||||
if (userBetContractJson) {
|
|
||||||
setContractIds(JSON.parse(userBetContractJson))
|
|
||||||
}
|
|
||||||
|
|
||||||
return listenForUserBets(
|
|
||||||
userId,
|
|
||||||
(bets) => {
|
|
||||||
const contractIds = uniq(bets.map((bet) => bet.contractId))
|
|
||||||
setContractIds(contractIds)
|
|
||||||
localStorage.setItem(key, JSON.stringify(contractIds))
|
|
||||||
},
|
|
||||||
options
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}, [userId])
|
|
||||||
|
|
||||||
return contractIds
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useGetUserBetContractIds = (userId: string | undefined) => {
|
export const useGetUserBetContractIds = (userId: string | undefined) => {
|
||||||
const [contractIds, setContractIds] = useState<string[] | undefined>()
|
const [contractIds, setContractIds] = useState<string[] | undefined>()
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
getDocs,
|
getDocs,
|
||||||
getDoc,
|
getDoc,
|
||||||
DocumentSnapshot,
|
DocumentSnapshot,
|
||||||
|
Query,
|
||||||
} from 'firebase/firestore'
|
} from 'firebase/firestore'
|
||||||
import { uniq } from 'lodash'
|
import { uniq } from 'lodash'
|
||||||
|
|
||||||
|
@ -131,24 +132,12 @@ export async function getContractsOfUserBets(userId: string) {
|
||||||
return filterDefined(contracts)
|
return filterDefined(contracts)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listenForUserBets(
|
export function getUserBetsQuery(userId: string) {
|
||||||
userId: string,
|
return query(
|
||||||
setBets: (bets: Bet[]) => void,
|
|
||||||
options: { includeRedemptions: boolean }
|
|
||||||
) {
|
|
||||||
const { includeRedemptions } = options
|
|
||||||
const userQuery = query(
|
|
||||||
collectionGroup(db, 'bets'),
|
collectionGroup(db, 'bets'),
|
||||||
where('userId', '==', userId),
|
where('userId', '==', userId),
|
||||||
orderBy('createdTime', 'desc')
|
orderBy('createdTime', 'desc')
|
||||||
)
|
) as Query<Bet>
|
||||||
return listenForValues<Bet>(userQuery, (bets) => {
|
|
||||||
setBets(
|
|
||||||
bets.filter(
|
|
||||||
(bet) => (includeRedemptions || !bet.isRedemption) && !bet.isAnte
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listenForUserContractBets(
|
export function listenForUserContractBets(
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
getDocs,
|
getDocs,
|
||||||
limit,
|
limit,
|
||||||
orderBy,
|
orderBy,
|
||||||
|
Query,
|
||||||
query,
|
query,
|
||||||
setDoc,
|
setDoc,
|
||||||
startAfter,
|
startAfter,
|
||||||
|
@ -156,6 +157,13 @@ export function listenForUserContracts(
|
||||||
return listenForValues<Contract>(q, setContracts)
|
return listenForValues<Contract>(q, setContracts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getUserBetContractsQuery(userId: string) {
|
||||||
|
return query(
|
||||||
|
contracts,
|
||||||
|
where('uniqueBettorIds', 'array-contains', userId)
|
||||||
|
) as Query<Contract>
|
||||||
|
}
|
||||||
|
|
||||||
const activeContractsQuery = query(
|
const activeContractsQuery = query(
|
||||||
contracts,
|
contracts,
|
||||||
where('isResolved', '==', false),
|
where('isResolved', '==', false),
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
deleteDoc,
|
deleteDoc,
|
||||||
collectionGroup,
|
collectionGroup,
|
||||||
onSnapshot,
|
onSnapshot,
|
||||||
|
Query,
|
||||||
} from 'firebase/firestore'
|
} from 'firebase/firestore'
|
||||||
import { getAuth } from 'firebase/auth'
|
import { getAuth } from 'firebase/auth'
|
||||||
import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth'
|
import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth'
|
||||||
|
@ -252,15 +253,13 @@ export async function unfollow(userId: string, unfollowedUserId: string) {
|
||||||
await deleteDoc(followDoc)
|
await deleteDoc(followDoc)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getPortfolioHistory(userId: string, since: number) {
|
export function getPortfolioHistoryQuery(userId: string, since: number) {
|
||||||
return getValues<PortfolioMetrics>(
|
return query(
|
||||||
query(
|
|
||||||
collectionGroup(db, 'portfolioHistory'),
|
collectionGroup(db, 'portfolioHistory'),
|
||||||
where('userId', '==', userId),
|
where('userId', '==', userId),
|
||||||
where('timestamp', '>=', since),
|
where('timestamp', '>=', since),
|
||||||
orderBy('timestamp', 'asc')
|
orderBy('timestamp', 'asc')
|
||||||
)
|
) as Query<PortfolioMetrics>
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listenForFollows(
|
export function listenForFollows(
|
||||||
|
|
|
@ -42,6 +42,7 @@ import {
|
||||||
} from 'web/components/contract/contract-leaderboard'
|
} from 'web/components/contract/contract-leaderboard'
|
||||||
import { ContractsGrid } from 'web/components/contract/contracts-grid'
|
import { ContractsGrid } from 'web/components/contract/contracts-grid'
|
||||||
import { Title } from 'web/components/title'
|
import { Title } from 'web/components/title'
|
||||||
|
import { usePrefetch } from 'web/hooks/use-prefetch'
|
||||||
|
|
||||||
export const getStaticProps = fromPropz(getStaticPropz)
|
export const getStaticProps = fromPropz(getStaticPropz)
|
||||||
export async function getStaticPropz(props: {
|
export async function getStaticPropz(props: {
|
||||||
|
@ -157,6 +158,7 @@ export function ContractPageContent(
|
||||||
const { backToHome, comments, user } = props
|
const { backToHome, comments, user } = props
|
||||||
|
|
||||||
const contract = useContractWithPreload(props.contract) ?? props.contract
|
const contract = useContractWithPreload(props.contract) ?? props.contract
|
||||||
|
usePrefetch(user?.id)
|
||||||
|
|
||||||
useTracking('view market', {
|
useTracking('view market', {
|
||||||
slug: contract.slug,
|
slug: contract.slug,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { track } from 'web/lib/service/analytics'
|
||||||
import { authenticateOnServer } from 'web/lib/firebase/server-auth'
|
import { authenticateOnServer } from 'web/lib/firebase/server-auth'
|
||||||
import { useSaveReferral } from 'web/hooks/use-save-referral'
|
import { useSaveReferral } from 'web/hooks/use-save-referral'
|
||||||
import { GetServerSideProps } from 'next'
|
import { GetServerSideProps } from 'next'
|
||||||
|
import { usePrefetch } from 'web/hooks/use-prefetch'
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
||||||
const creds = await authenticateOnServer(ctx)
|
const creds = await authenticateOnServer(ctx)
|
||||||
|
@ -30,6 +31,7 @@ const Home = (props: { auth: { user: User } | null }) => {
|
||||||
useTracking('view home')
|
useTracking('view home')
|
||||||
|
|
||||||
useSaveReferral()
|
useSaveReferral()
|
||||||
|
usePrefetch(user?.id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user