diff --git a/src/components/DappBrowser/Homepage.tsx b/src/components/DappBrowser/Homepage.tsx index d609feae647..6bda90a0717 100644 --- a/src/components/DappBrowser/Homepage.tsx +++ b/src/components/DappBrowser/Homepage.tsx @@ -34,6 +34,8 @@ import { analyticsV2 } from '@/analytics'; import haptics from '@/utils/haptics'; import * as i18n from '@/languages'; import { getNameFromFormattedUrl } from './utils'; +import { useTrendingDApps } from '@/resources/metadata/trendingDapps'; +import { DApp } from '@/graphql/__generated__/metadata'; const HORIZONTAL_PAGE_INSET = 24; const MAX_RECENTS_TO_DISPLAY = 6; @@ -73,9 +75,9 @@ export const Homepage = () => { }; const Trending = ({ goToUrl }: { goToUrl: (url: string) => void }) => { - const { dapps } = useDapps({ select: dapps => dapps.filter(dapp => dapp.trending).slice(0, 8) }); + const { data } = useTrendingDApps(); - if (dapps.length === 0) { + if (!data?.dApps?.length) { return null; } @@ -95,13 +97,15 @@ const Trending = ({ goToUrl }: { goToUrl: (url: string) => void }) => { decelerationRate="fast" disableIntervalMomentum showsHorizontalScrollIndicator={false} - snapToOffsets={dapps.map((_, index) => index * (CARD_WIDTH + CARD_PADDING))} + snapToOffsets={data.dApps.map((_, index) => index * (CARD_WIDTH + CARD_PADDING))} > - {dapps.map((site, index) => ( - - ))} + {data.dApps + .filter((dApp): dApp is DApp => dApp !== null) + .map((dApp, index) => ( + + ))} diff --git a/src/graphql/queries/metadata.graphql b/src/graphql/queries/metadata.graphql index e69a3c6c7f5..e398cbdd2ea 100644 --- a/src/graphql/queries/metadata.graphql +++ b/src/graphql/queries/metadata.graphql @@ -604,3 +604,23 @@ mutation claimUserRewards($address: String!) { txHash } } + +query trendingDApps($period: DAppRankingPeriod) { + dApps(trending: true, period: $period) { + name + shortName + description + url + iconURL + colors { + primary + fallback + shadow + } + status + report { + url + } + trending + } +} diff --git a/src/resources/metadata/trendingDapps.ts b/src/resources/metadata/trendingDapps.ts new file mode 100644 index 00000000000..c52975d79c4 --- /dev/null +++ b/src/resources/metadata/trendingDapps.ts @@ -0,0 +1,47 @@ +import { metadataClient } from '@/graphql'; +import { DAppRankingPeriod, DAppStatus, TrendingDAppsQuery } from '@/graphql/__generated__/metadata'; +import { createQueryKey, QueryConfigWithSelect } from '@/react-query'; +import { QueryFunction, useQuery } from '@tanstack/react-query'; + +const trendingDAppsQueryKey = ({ period }: { period: DAppRankingPeriod }) => + createQueryKey('trendingDApps', { period }, { persisterVersion: 1 }); + +type TrendingDAppsQueryKey = ReturnType; + +const fetchTrendingDApps: QueryFunction = async ({ queryKey }) => { + const [{ period }] = queryKey; + + return metadataClient.trendingDApps({ + period, + }); +}; + +export function selectValidNonScamDApps(data: TrendingDAppsQuery): TrendingDAppsQuery { + if (!data.dApps?.length) return { ...data, dApps: [] }; + return { + ...data, + dApps: data.dApps.filter(d => Boolean(d) && d?.status !== DAppStatus.Scam), + }; +} + +export function selectFirstEightDApps(data: TrendingDAppsQuery): TrendingDAppsQuery { + if (!data.dApps?.length) return { ...data, dApps: [] }; + return { + ...data, + dApps: data.dApps.slice(0, 8), + }; +} + +export function useTrendingDApps( + period = DAppRankingPeriod.Day, + config: QueryConfigWithSelect, TrendingDAppsQueryKey> = {} +) { + return useQuery(trendingDAppsQueryKey({ period }), fetchTrendingDApps, { + staleTime: 1000 * 60 * 20, // 20 minutes + cacheTime: 1000 * 60 * 60 * 24 * 2, // 2 days + retry: 3, + keepPreviousData: true, + select: data => selectFirstEightDApps(selectValidNonScamDApps(data)), + ...config, + }); +}