diff --git a/src/components/Tokens/TokenDetails/ChartSection.tsx b/src/components/Tokens/TokenDetails/ChartSection.tsx index ccd255756..746d7bb8e 100644 --- a/src/components/Tokens/TokenDetails/ChartSection.tsx +++ b/src/components/Tokens/TokenDetails/ChartSection.tsx @@ -5,11 +5,12 @@ import { isPricePoint, PricePoint } from 'graphql/data/util' import { TimePeriod } from 'graphql/data/util' import { useAtomValue } from 'jotai/utils' import { pageTimePeriodAtom } from 'pages/TokenDetails' -import { startTransition, Suspense, useMemo } from 'react' +import { startTransition, Suspense, useMemo, useEffect, useState } from 'react' import { PriceChart } from './PriceChart' import TimePeriodSelector from './TimeSelector' import { ti } from 'make-plural' +import { left } from '@popperjs/core' function fillMissingTimestamps(priceHistory: any, interval: number, totalTime: number) { if (!Array.isArray(priceHistory) || priceHistory.length === 0) { @@ -20,19 +21,19 @@ function fillMissingTimestamps(priceHistory: any, interval: number, totalTime: n priceHistory.sort((a, b) => a.timestamp - b.timestamp); const currentTimestamp = Date.now() / 1000 const filledHistory = []; - + for (let i = 0; i < priceHistory.length - 1; i++) { const current = priceHistory[i]; const next = priceHistory[i + 1]; // Add the current object to the filled array - if(next.timestamp + totalTime >= currentTimestamp) { - if(current.timestamp + totalTime >= currentTimestamp) filledHistory.push(current); + if (next.timestamp + totalTime >= currentTimestamp) { + if (current.timestamp + totalTime >= currentTimestamp) filledHistory.push(current); // Fill missing timestamps let timestamp = current.timestamp + interval; while (timestamp < next.timestamp) { - if(timestamp + totalTime >= currentTimestamp) + if (timestamp + totalTime >= currentTimestamp) filledHistory.push({ ...current, // Copy previous values timestamp, // Update timestamp @@ -47,8 +48,8 @@ function fillMissingTimestamps(priceHistory: any, interval: number, totalTime: n return filledHistory; } -function getTimeInterval(timePeriod:any) { - switch(timePeriod) { +function getTimeInterval(timePeriod: any) { + switch (timePeriod) { case 0: return [300, 3600]; case 1: @@ -64,23 +65,34 @@ function getTimeInterval(timePeriod:any) { } function usePriceHistory(tokenPriceData: TokenPriceQuery, timePeriod: any): PricePoint[] | undefined { - + const [priceHistory, setPriceHistory] = useState(undefined); const [timeInterval, totalTime] = getTimeInterval(timePeriod); - // Appends the current price to the end of the priceHistory array - const priceHistory = useMemo(() => { - const market = tokenPriceData.token?.market - const priceHistory = market?.priceHistory?.filter(isPricePoint) - // const priceHistory = market?.priceHistory?.filter(isPricePoint) - const currentPrice = market?.price?.value - if (Array.isArray(priceHistory) && currentPrice !== undefined) { - const timestamp = Date.now() / 1000 - return fillMissingTimestamps([...priceHistory, { timestamp, value: currentPrice }], timeInterval, totalTime) - } - return priceHistory - }, [tokenPriceData]) - return priceHistory + useEffect(() => { + const updatePriceHistory = () => { + const market = tokenPriceData.token?.market; + const history = market?.priceHistory?.filter(isPricePoint); + const currentPrice = market?.price?.value; + + if (Array.isArray(history) && currentPrice !== undefined) { + const timestamp = Date.now() / 1000; + const filledHistory = fillMissingTimestamps([...history, { timestamp, value: currentPrice }], timeInterval, totalTime); + setPriceHistory(filledHistory); + } else { + setPriceHistory(history); + } + }; + + // Update immediately and then at intervals + updatePriceHistory(); + const intervalId = setInterval(updatePriceHistory, 12000); // Update every 12 seconds + + return () => clearInterval(intervalId); // Cleanup on component unmount + }, [tokenPriceData, timeInterval, totalTime]); + + return priceHistory; } + export default function ChartSection({ tokenPriceQuery, onChangeTimePeriod, @@ -112,7 +124,6 @@ function Chart({ // Initializes time period to global & maintain separate time period for subsequent changes const timePeriod = useAtomValue(pageTimePeriodAtom) const prices = usePriceHistory(tokenPriceQuery, timePeriod) - console.log(tokenPriceQuery, prices); return ( diff --git a/src/pages/TokenDetails/index.tsx b/src/pages/TokenDetails/index.tsx index d92f7d8a4..5c9e412dc 100644 --- a/src/pages/TokenDetails/index.tsx +++ b/src/pages/TokenDetails/index.tsx @@ -17,7 +17,7 @@ import { luxNetClient } from 'graphql/thegraph/apollo' import { zooNetClient } from 'graphql/thegraph/apollo' const GetTokenInfo = gql` -query GetTokenInfo($tokenAddress: String!, $days: Int, $hours: Int) { +query GetTokenInfo($tokenAddress: String!, $days: Int, $hours: Int, $mins: Int) { bundles(first: 10) { ethPriceUSD } @@ -47,6 +47,14 @@ query GetTokenInfo($tokenAddress: String!, $days: Int, $hours: Int) { volumeUSD } + token5MinData(first: $mins, orderBy: periodStartUnix, orderDirection: desc) { + id + periodStartUnix + priceUSD # The price of the token in USD for the day + totalValueLockedUSD + volumeUSD + } + # Get all pools involving this token for liquidity details whitelistPools { id @@ -70,15 +78,15 @@ export const pageTimePeriodAtom = atomWithStorage('tokenDetailsTimeP function getQueryParams(timePeriod: any) { switch (timePeriod) { case 0: - return [2, 2]; + return [2, 2, 12]; case 1: - return [2, 24]; + return [2, 30, 2]; case 2: - return [2, 168]; + return [2, 168, 2]; case 3: - return [2, 720]; + return [2, 720, 2]; case 4: - return [365, 2]; + return [365, 2, 2]; } return [2, 2]; } @@ -89,36 +97,55 @@ export default function TokenDetailsPage() { const chain = validateUrlChainParam(chainName) const isNative = tokenAddress === NATIVE_CHAIN_ID const [timePeriod, setTimePeriod] = useAtom(pageTimePeriodAtom) - const [totalDays, totalHours] = getQueryParams(timePeriod); + const [totalDays, totalHours, total5Mins] = getQueryParams(timePeriod); const [address, duration] = useMemo( /* tokenAddress will always be defined in the path for for this page to render, but useParams will always return optional arguments; nullish coalescing operator is present here to appease typechecker */ () => [isNative ? getNativeTokenDBAddress(chain) : tokenAddress ?? '', toHistoryDuration(timePeriod)], [chain, isNative, timePeriod, tokenAddress] ) - const { data: tokenQuery } = useTokenQuery({ + const { data: tokenQuery, refetch: refetchTokenQuery } = useTokenQuery({ variables: { address, chain, }, + pollInterval: 12000, // 12 seconds }) - const { data: tokenPriceQuery } = useTokenPriceQuery({ + const { data: tokenPriceQuery, refetch: refetchTokenPriceQuery } = useTokenPriceQuery({ variables: { address, chain, duration, }, + pollInterval: 12000, // 12 seconds }) - const { data: luxData, loading: luxLoading } = useQuery(GetTokenInfo, { + const { data: luxData, loading: luxLoading, refetch: refetchLuxData } = useQuery(GetTokenInfo, { client: chainName == 'lux' ? luxNetClient : zooNetClient, variables: { tokenAddress: address, days: totalDays, hours: totalHours, + mins: total5Mins, }, + pollInterval: 12000, // 12 seconds }) + + // Use effect to handle periodic refetching + useEffect(() => { + const intervalId = setInterval(() => { + refetchTokenQuery() + refetchTokenPriceQuery() + if (chainName === 'lux' || chainName === 'zoo') { + refetchLuxData() + } + }, 12000) // 12 seconds interval + + // Clear interval on component unmount + return () => clearInterval(intervalId) + }, [refetchTokenQuery, refetchTokenPriceQuery, refetchLuxData, chainName]) + if (luxLoading) { console.log("Loading data..."); } else { @@ -135,6 +162,20 @@ export default function TokenDetailsPage() { const priceLow52W = dailyPrices && Math.min(...dailyPrices); const token = luxData?.token; + // Use effect to handle periodic refetching + useEffect(() => { + const intervalId = setInterval(() => { + refetchTokenQuery() + refetchTokenPriceQuery() + if (chainName === 'lux' || chainName === 'zoo') { + refetchLuxData() + } + }, 12000) // 12 seconds interval + + // Clear interval on component unmount + return () => clearInterval(intervalId) + }, []) + // Now, you can assign the JSON data to a variable of type TokenQuery const transformedTokenDetail: TokenQuery = tokenPriceQuery ?? { token: { @@ -192,6 +233,11 @@ export default function TokenDetailsPage() { timestamp: data.periodStartUnix, value: parseFloat(data.priceUSD), })) + const token5MinData = luxData?.token?.token5MinData.filter((data: any) => parseFloat(data.priceUSD) !== 0).map((data: any) => ({ + id: `VGltZXN0YW1wZWRBbW91bnQ6MV8x${data.periodStartUnix}_VVNE`, // Encoded version of the timestamped amount + timestamp: data.periodStartUnix, + value: parseFloat(data.priceUSD), + })) const transformedTokenPriceHistory: TokenPriceQuery = { token: { @@ -204,7 +250,7 @@ export default function TokenDetailsPage() { id: "QW1vdW50OjFfVVNE", // Encoded amount ID value: parseFloat(ethPriceUSD) * parseFloat(ethPrice), }, - priceHistory: timePeriod < 4 ? tokenHourData : tokenDayData, + priceHistory: timePeriod < 1 ? token5MinData : timePeriod < 4 ? tokenHourData : tokenDayData, }, }, }; diff --git a/src/tokens-lux/tokens.ts b/src/tokens-lux/tokens.ts index 7da06c729..d871bbcca 100644 --- a/src/tokens-lux/tokens.ts +++ b/src/tokens-lux/tokens.ts @@ -163,7 +163,7 @@ export const TOKENS_LUX_LIST = { "name": "Zoo LUX", "symbol": "ZLUX", "decimals": 18, - "logoURI": "https://cdn.lux.network/exchange/icon-png/lux.png", + "logoURI": "https://cdn.lux.network/bridge/currencies/zoo/zlux.svg", "extensions": {} }, {