Skip to content

Commit 2e92aff

Browse files
committed
Feat/dapp explorer (#2054)
* feat(extension): implement client side dapp explorer data * feat(extension): replace base64 encoded images with asset files
1 parent 7ab870e commit 2e92aff

File tree

90 files changed

+4852
-158
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+4852
-158
lines changed

apps/browser-extension-wallet/src/views/browser-view/features/dapp/explorer/components/SimpleView/SimpleViewContent/index.tsx

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,19 @@
11
import React from 'react';
2-
import { Box } from '@input-output-hk/lace-ui-toolkit';
32
import { IogCardClassic } from '../../../components/Card';
43
import IogEmptyState from '../../../components/EmptyState';
54
import { EDrawerAction, useDrawer } from '../../../components/ProjectDetail/drawer';
65
import { useDAppFetcher } from '../../../services/api/d-app';
76
import { maybeGetCategoryName } from '../../../services/helpers/apis-formatter';
87
import { ISectionCardItem } from '../../../services/helpers/apis-formatter/types';
9-
import { Skeleton } from 'antd';
10-
import useInfiniteScroll from 'react-infinite-scroll-hook';
118
import type { ISimpleViewContent } from './types';
129
import './styles.scss';
1310
import { useAnalyticsContext } from '@providers';
1411
import { PostHogAction } from '@lace/common';
1512

16-
// Defines pagination parameters for infinite scroll mechanism.
17-
const MAX_ITEMS_PER_PAGE = 20;
18-
1913
const SimpleViewContent: React.FC<ISimpleViewContent> = ({ selectedCategory, search }) => {
2014
const { dispatch } = useDrawer<ISectionCardItem>();
21-
const {
22-
data: dapps,
23-
loading,
24-
fetchMore,
25-
hasNextPage
26-
} = useDAppFetcher({
15+
const { data: dapps, loading } = useDAppFetcher({
2716
category: maybeGetCategoryName(selectedCategory),
28-
page: { offset: 0, limit: MAX_ITEMS_PER_PAGE },
2917
search
3018
});
3119
const analytics = useAnalyticsContext();
@@ -44,13 +32,6 @@ const SimpleViewContent: React.FC<ISimpleViewContent> = ({ selectedCategory, sea
4432

4533
const showEmptyState = !loading && dapps?.length === 0;
4634

47-
const [infiniteScrollRef] = useInfiniteScroll({
48-
loading,
49-
hasNextPage,
50-
onLoadMore: fetchMore,
51-
rootMargin: '0px 0px 0px 0px'
52-
});
53-
5435
const renderCards = (dappsToRender: ISectionCardItem[]) =>
5536
dappsToRender.map((dapp, index) => (
5637
<div key={`card-${dapp.id}-${index}`} className="card-container">
@@ -75,11 +56,6 @@ const SimpleViewContent: React.FC<ISimpleViewContent> = ({ selectedCategory, sea
7556
return (
7657
<div className="iog-simple-view-content-container">
7758
<div className="iog-section-card-grid">{renderCards(dapps)}</div>
78-
{(loading || hasNextPage) && (
79-
<Box mt={'$24'} ref={infiniteScrollRef} data-testid="skeleton">
80-
<Skeleton />
81-
</Box>
82-
)}
8359
</div>
8460
);
8561
};

apps/browser-extension-wallet/src/views/browser-view/features/dapp/explorer/services/api/categories/index.ts

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
import { useState, useEffect, useMemo } from 'react';
22
import { usePostHogClientContext } from '@providers/PostHogClientProvider';
3-
import { cacheRequest } from '@views/browser/features/dapp/explorer/services/cache';
4-
import { logger } from '@lace/common';
3+
import { getCachedCategories } from '@views/browser/features/dapp/explorer/services/api/static/dataSource';
54

65
type FetchCategoriesResult = {
76
loading: boolean;
87
data: string[];
98
};
109

11-
const dappRadarCategoriesUrl = `${process.env.DAPP_RADAR_API_URL}/v2/dapps/categories`;
12-
const dappRadarApiKey = process.env.DAPP_RADAR_API_KEY;
13-
1410
export const useCategoriesFetcher = (): FetchCategoriesResult => {
1511
const [loading, setLoading] = useState(true);
1612
const [data, setData] = useState<string[]>([]);
@@ -25,38 +21,12 @@ export const useCategoriesFetcher = (): FetchCategoriesResult => {
2521
);
2622

2723
useEffect(() => {
28-
(async () => {
29-
if (!dappRadarApiKey) {
30-
setLoading(false);
31-
return;
32-
}
33-
34-
let categories: string[] = [];
35-
try {
36-
categories = await cacheRequest(dappRadarCategoriesUrl, async () => {
37-
const response = await window.fetch(dappRadarCategoriesUrl, {
38-
headers: {
39-
Accept: 'application/json',
40-
'x-api-key': dappRadarApiKey
41-
}
42-
});
43-
44-
if (!response.ok) {
45-
throw new Error('Unexpected response');
46-
}
47-
48-
const result = (await response.json()) as { categories: string[] };
49-
return result.categories;
50-
});
51-
} catch (error) {
52-
logger.error('Failed to fetch dapp categories.', error);
53-
}
24+
setLoading(true);
5425

55-
categories = categories.filter((category) => !disallowedDappCategories.has(category));
26+
const categories = getCachedCategories().filter((category) => !disallowedDappCategories.has(category));
5627

57-
setData(categories);
58-
setLoading(false);
59-
})();
28+
setData(categories);
29+
setLoading(false);
6030
}, [disallowedDappCategories]);
6131

6232
return { loading, data };

apps/browser-extension-wallet/src/views/browser-view/features/dapp/explorer/services/api/d-app/index.ts

Lines changed: 23 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,9 @@
11
import { useEffect, useMemo, useState } from 'react';
22
import { ISectionCardItem } from '@views/browser/features/dapp/explorer/services/helpers/apis-formatter/types';
33
import { usePostHogClientContext } from '@providers/PostHogClientProvider';
4-
import { cacheRequest } from '@views/browser/features/dapp/explorer/services/cache';
54
import { logger } from '@lace/common';
6-
7-
const dappRadarApiUrl = process.env.DAPP_RADAR_API_URL;
8-
const dappRadarApiKey = process.env.DAPP_RADAR_API_KEY;
9-
10-
export type PaginationInput = {
11-
offset: number;
12-
limit: number;
13-
};
14-
15-
type DAppRadarDappItem = {
16-
dappId: number;
17-
name: string;
18-
description: string;
19-
fullDescription: string;
20-
logo: string;
21-
link: string;
22-
website: string;
23-
chains: string[];
24-
categories: string[];
25-
socialLinks: Array<{
26-
title: string;
27-
type: string;
28-
url: string;
29-
}>;
30-
metrics: {
31-
transactions: number;
32-
transactionsPercentageChange: number;
33-
uaw: number;
34-
uawPercentageChange: number;
35-
volume: number;
36-
volumePercentageChange: number;
37-
balance: number;
38-
balancePercentageChange: number;
39-
};
40-
tags: Array<{
41-
id: string;
42-
name: string;
43-
slug: string;
44-
}>;
45-
};
5+
import { getCachedDapps, getLogoUrl } from '@views/browser/features/dapp/explorer/services/api/static/dataSource';
6+
import type { DAppRadarDappItem } from '@views/browser/features/dapp/explorer/services/api/static/dataSource';
467

478
const mapResponse = (
489
dapps: DAppRadarDappItem[],
@@ -59,35 +20,29 @@ const mapResponse = (
5920
categories: dapp.categories,
6021
title: dapp.name,
6122
image: {
62-
src: dapp.logo,
23+
src: getLogoUrl(dapp.logo),
6324
alt: dapp.name
6425
},
65-
certificates: undefined,
6626
shortDescription: dapp.description,
6727
longDescription: dapp.fullDescription,
6828
email: '',
6929
link: dapp.website,
7030
companyWebsite: '',
71-
screenshots: undefined,
7231
socialLinks: dapp.socialLinks
7332
}));
7433

7534
type DAppFetcherParams = {
7635
category?: string;
7736
search?: string;
78-
page?: PaginationInput;
7937
// todo: re-instate later if we see fit (TBD)
8038
_subcategory?: string;
8139
};
8240

8341
const useDAppFetcher = ({
84-
category,
85-
page: { limit }
42+
category
8643
}: DAppFetcherParams): {
8744
loading: boolean;
8845
data: ISectionCardItem[];
89-
fetchMore: () => void;
90-
hasNextPage: boolean;
9146
} => {
9247
const [data, setData] = useState<DAppRadarDappItem[]>([]);
9348
const [loading, setLoading] = useState(true);
@@ -111,59 +66,29 @@ const useDAppFetcher = ({
11166
}, [dappExplorerFeaturePayload]);
11267

11368
useEffect(() => {
114-
(async () => {
115-
if (!dappRadarApiKey) {
116-
setData([]);
117-
setLoading(false);
118-
return;
119-
}
120-
121-
setLoading(true);
122-
const searchParams = new URLSearchParams('');
123-
searchParams.set('chain', 'cardano');
124-
searchParams.set('range', '30d');
125-
searchParams.set('top', '100');
126-
if (category) {
127-
searchParams.set('category', category);
128-
}
129-
130-
let results: DAppRadarDappItem[] = [];
131-
const url = `${dappRadarApiUrl}/v2/dapps/top/uaw?${searchParams.toString()}`;
132-
try {
133-
results = await cacheRequest(url, async () => {
134-
const response = await window.fetch(url, {
135-
headers: {
136-
Accept: 'application/json',
137-
'x-api-key': dappRadarApiKey
138-
}
139-
});
140-
141-
if (!response.ok) {
142-
throw new Error('Unexpected response');
143-
}
144-
145-
const parsedResponse = (await response.json()) as { results: DAppRadarDappItem[] };
146-
return parsedResponse.results;
147-
});
148-
} catch (error) {
149-
logger.error('Failed to fetch dapp list.', error);
150-
}
151-
152-
setData(results);
153-
setLoading(false);
154-
})();
155-
}, [category, limit]);
69+
setLoading(true);
70+
71+
try {
72+
const allDapps = getCachedDapps();
73+
const filtered = allDapps.filter((dapp) => {
74+
if (!category) {
75+
return true;
76+
}
77+
return dapp.categories.includes(category);
78+
});
79+
80+
setData(filtered);
81+
} catch (error) {
82+
logger.error('Failed to read cached dapp list.', error);
83+
setData([]);
84+
}
15685

157-
// eslint-disable-next-line unicorn/consistent-function-scoping
158-
const fetchMore = () => {
159-
logger.error('Pagination not implemented!');
160-
};
86+
setLoading(false);
87+
}, [category]);
16188

16289
return {
16390
loading,
164-
data: mapResponse(data, disallowedDappIds, disallowedDappCategories),
165-
fetchMore,
166-
hasNextPage: false
91+
data: mapResponse(data, disallowedDappIds, disallowedDappCategories)
16792
};
16893
};
16994

5.32 KB
15.4 KB
6.01 KB
47.7 KB
26 KB
673 KB

0 commit comments

Comments
 (0)