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,
+ });
+}