diff --git a/web/components/portfolio/portfolio-value-section.tsx b/web/components/portfolio/portfolio-value-section.tsx index 706630b2..ab4bef0c 100644 --- a/web/components/portfolio/portfolio-value-section.tsx +++ b/web/components/portfolio/portfolio-value-section.tsx @@ -1,43 +1,26 @@ -import { PortfolioMetrics } from 'common/user' import { formatMoney } from 'common/util/format' import { last } from 'lodash' -import { memo, useEffect, useState } from 'react' -import { Period, getPortfolioHistory } from 'web/lib/firebase/users' +import { memo, useRef, useState } from 'react' +import { usePortfolioHistory } from 'web/hooks/use-portfolio-history' +import { Period } from 'web/lib/firebase/users' import { Col } from '../layout/col' import { Row } from '../layout/row' 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( function PortfolioValueSection(props: { userId: string }) { const { userId } = props const [portfolioPeriod, setPortfolioPeriod] = useState('weekly') - const [portfolioHistory, setUsersPortfolioHistory] = useState< - PortfolioMetrics[] - >([]) + const portfolioHistory = usePortfolioHistory(userId, portfolioPeriod) - useEffect(() => { - const cutoff = periodToCutoff(Date.now(), portfolioPeriod).valueOf() - getPortfolioHistory(userId, cutoff).then(setUsersPortfolioHistory) - }, [portfolioPeriod, userId]) + // Remember the last defined portfolio history. + const portfolioRef = useRef(portfolioHistory) + if (portfolioHistory) portfolioRef.current = portfolioHistory + const currPortfolioHistory = portfolioRef.current - const lastPortfolioMetrics = last(portfolioHistory) - if (portfolioHistory.length === 0 || !lastPortfolioMetrics) { + const lastPortfolioMetrics = last(currPortfolioHistory) + if (!currPortfolioHistory || !lastPortfolioMetrics) { return <> } @@ -64,7 +47,7 @@ export const PortfolioValueSection = memo( diff --git a/web/hooks/use-portfolio-history.ts b/web/hooks/use-portfolio-history.ts new file mode 100644 index 00000000..d5919783 --- /dev/null +++ b/web/hooks/use-portfolio-history.ts @@ -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) + } +} diff --git a/web/lib/firebase/users.ts b/web/lib/firebase/users.ts index bad13c8c..c0764f0a 100644 --- a/web/lib/firebase/users.ts +++ b/web/lib/firebase/users.ts @@ -12,6 +12,7 @@ import { deleteDoc, collectionGroup, onSnapshot, + Query, } from 'firebase/firestore' import { getAuth } from 'firebase/auth' import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth' @@ -252,15 +253,13 @@ export async function unfollow(userId: string, unfollowedUserId: string) { await deleteDoc(followDoc) } -export async function getPortfolioHistory(userId: string, since: number) { - return getValues( - query( - collectionGroup(db, 'portfolioHistory'), - where('userId', '==', userId), - where('timestamp', '>=', since), - orderBy('timestamp', 'asc') - ) - ) +export function getPortfolioHistoryQuery(userId: string, since: number) { + return query( + collectionGroup(db, 'portfolioHistory'), + where('userId', '==', userId), + where('timestamp', '>=', since), + orderBy('timestamp', 'asc') + ) as Query } export function listenForFollows(