Skip to content

Commit

Permalink
feat: api.universalprofile.cloud removal (#24)
Browse files Browse the repository at this point in the history
* Add batshit

* Render profile images with graph data

* Fix incorrect name field

* Update profile query and lukso-profile package

* Display checksummed address

* Cleanup
  • Loading branch information
Wolmin authored Oct 18, 2024
1 parent aebd9f3 commit 172581b
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 178 deletions.
1 change: 0 additions & 1 deletion deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,6 @@ const schema = yup
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY: yup.string(),
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: yup.string(),
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN: yup.string(),
NEXT_PUBLIC_UNIVERSAL_PROFILES_API_URL: yup.string(),
NEXT_PUBLIC_GRAPH_URL: yup.string(),
NEXT_PUBLIC_GROWTH_BOOK_CLIENT_KEY: yup.string(),

Expand Down
1 change: 0 additions & 1 deletion docs/ENVS.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ Settings for meta tags, OG tags and SEO
| NEXT_PUBLIC_VIEWS_ADDRESS_HIDDEN_VIEWS | `Array<AddressViewId>` | Address views that should not be displayed. See below the list of the possible id values. | - | - | `'["top_accounts"]'` | v1.15.0+ |
| NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED | `boolean` | Set to `true` if SolidityScan reports are supported | - | - | `true` | v1.19.0+ |
| NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS | `Array<'solidity-hardhat' \| 'solidity-foundry'>` | Pass an array of additional methods from which users can choose while verifying a smart contract. Both methods are available by default, pass `'none'` string to disable them all. | - | - | `['solidity-hardhat']` | v1.33.0+ |
| NEXT_PUBLIC_UNIVERSAL_PROFILES_API_URL | `string` | LUKSO UNIVERSAL PROFILE API URL used for getting various universal profile data | - | - | `https://api.universalprofile.com` | - |
| NEXT_PUBLIC_GRAPH_URL | `string` | URL of LUKSO Graph Indexer | - | - | `https://envio.mainnet.lukso.dev/`| - |

##### Address views list
Expand Down
4 changes: 3 additions & 1 deletion lib/api/graphClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const graphUrl = getEnvValue('NEXT_PUBLIC_GRAPH_URL') || '';
type FetchFunc<T> = (queryParams?: string) => Promise<GraphResponse<T> | null>

type GraphClient = {
searchProfiles: FetchFunc<SearchProfileQueryResponse>;
getProfiles: FetchFunc<SearchProfileQueryResponse>;
};

Expand Down Expand Up @@ -41,7 +42,8 @@ const fetchQuery = <T>(operationName: QueryOperation): FetchFunc<T> => {
};

const createGraphClient = (): GraphClient => ({
getProfiles: fetchQuery<SearchProfileQueryResponse>('search_profiles'),
searchProfiles: fetchQuery<SearchProfileQueryResponse>('search_profiles'),
getProfiles: fetchQuery<SearchProfileQueryResponse>('Profile'),
});

export const graphClient: GraphClient = createGraphClient();
20 changes: 18 additions & 2 deletions lib/api/graphQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const constructQuery = (operationType: QueryOperation, queryParams?: stri
return queryConstruct(queryParams);
};

export const searchProfileQuery = (queryParams?: string): string => `query search_profiles {
const searchProfilesQuery = (queryParams?: string): string => `query search_profiles {
search_profiles(args: { search: "${ queryParams }" }) {
profileImages(order_by: { width: asc }) {
src,
Expand All @@ -20,6 +20,22 @@ export const searchProfileQuery = (queryParams?: string): string => `query searc
}
}`;

const profilesQuery = (queryParams?: string): string => `query Profile {
Profile(
limit: 50
where: { id: { _in: ${ queryParams } } }
) {
profileImages( where: { error: { _is_null: true } }, order_by: { width: asc }) {
src,
width,
},
id,
name,
fullName,
}
}`;

const queryConstructors: Record<QueryOperation, QueryConstructor> = {
search_profiles: searchProfileQuery,
search_profiles: searchProfilesQuery,
Profile: profilesQuery,
};
2 changes: 1 addition & 1 deletion lib/api/graphTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ export type GraphQuery = {
query: string;
};

export type QueryOperation = 'search_profiles';
export type QueryOperation = 'search_profiles' | 'Profile';
5 changes: 3 additions & 2 deletions lib/api/useUniversalProfileApiFetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';

import type { SearchResultAddressOrContractOrUniversalProfile } from '../../types/api/search';

import getCheckedSummedAddress from 'lib/address/getCheckedSummedAddress';
import type { Params as FetchParams } from 'lib/hooks/useFetch';

import { graphClient } from './graphClient';
Expand All @@ -22,7 +23,7 @@ export default function useUniversalProfileApiFetch() {
return [] as Array<SearchResultAddressOrContractOrUniversalProfile>;
}
try {
const result = await graphClient.getProfiles(queryParams);
const result = await graphClient.searchProfiles(queryParams);
if (result == null) {
return [] as Array<SearchResultAddressOrContractOrUniversalProfile>;
}
Expand All @@ -34,7 +35,7 @@ export default function useUniversalProfileApiFetch() {
return {
type: 'universal_profile',
name: hitAsUp.name !== '' ? hitAsUp.name.trim() : null,
address: hit.id,
address: getCheckedSummedAddress(hit.id),
is_smart_contract_verified: false,
};
});
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
"@chakra-ui/theme-tools": "^2.0.18",
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@lukso/web-components": "^1.47.1",
"@growthbook/growthbook-react": "0.21.0",
"@hypelab/sdk-react": "^1.0.0",
"@lukso/web-components": "^1.90.0",
"@metamask/post-message-stream": "^7.0.0",
"@metamask/providers": "^10.2.1",
"@monaco-editor/react": "^4.4.6",
Expand All @@ -66,8 +66,8 @@
"@tanstack/react-query-devtools": "5.55.4",
"@types/papaparse": "^5.3.5",
"@types/react-scroll": "^1.8.4",
"algoliasearch": "^4.20.0",
"@web3modal/wagmi": "5.1.7",
"@yornaath/batshit": "^0.10.1",
"airtable": "^0.12.2",
"bignumber.js": "^9.1.0",
"blo": "^1.1.1",
Expand Down
2 changes: 1 addition & 1 deletion ui/shared/entities/address/AddressEntity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const Content = chakra((props: ContentProps) => {
);
}
const { data: upData, isLoading: upIsLoading } = useUniversalProfile(props.address.hash);
const upName = upIsLoading ? '' : upData?.LSP3Profile?.name ?? '';
const upName = upIsLoading ? '' : upData?.name ?? '';

const displayedName = upName !== '' ? formattedLuksoName(props.address.hash, upName) : props.address.hash;
return (
Expand Down
61 changes: 34 additions & 27 deletions ui/shared/entities/address/IdenticonUniversalProfileQuery.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
import { Box, Skeleton } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import { create, windowScheduler, keyResolver } from '@yornaath/batshit';
import React from 'react';

import type { UniversalProfileProxyResponse } from '../../../../types/api/universalProfile';

import { getEnvValue } from '../../../../configs/app/utils';
import { isUniversalProfileEnabled } from '../../../../lib/api/isUniversalProfileEnabled';
import { graphClient } from 'lib/api/graphClient';
import type { SearchProfileQueryResponse } from 'lib/api/graphTypes';

interface Props {
address: string;
fallbackIcon: JSX.Element;
}

const profiles = create({
fetcher: async(addresses: Array<string>) => {
const resp = await graphClient.getProfiles(JSON.stringify(addresses));
if (resp === null) {
return [] as Array<SearchProfileQueryResponse>;
}

return resp.data.Profile;
},

resolver: keyResolver('id'),
scheduler: windowScheduler(2000),
});

export const formattedLuksoName = (hash: string, name: string | null) => {
return `@${ name } (${ hash })`;
};

const resizeProfileImage = (imageUrl: string): string => {
if (imageUrl.includes('api.universalprofile.cloud/image')) {
imageUrl += '&width=40&height=40';
}

return imageUrl;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const useUniversalProfile = (address: string): UseQueryResult<UniversalProfileProxyResponse | null> => {
export const useUniversalProfile = (address: string): UseQueryResult<SearchProfileQueryResponse | null> => {
return useQuery({
refetchOnWindowFocus: false,
refetchOnReconnect: false,
retryOnMount: false,
staleTime: 60 * 60 * 1000,
queryKey: [ 'universalProfile', { address } ],
queryKey: [ 'universalProfile', address ],
queryFn: async() => {
if (!isUniversalProfileEnabled() || /0x0+$/i.test(address)) {
return null;
}
const upApiUrl =
getEnvValue('NEXT_PUBLIC_UNIVERSAL_PROFILES_API_URL') || '';
const networkId = getEnvValue('NEXT_PUBLIC_NETWORK_ID') || '42';

const url = `${ upApiUrl }/v1/${ networkId }/address/${ address }`;
try {
const resp = await fetch(url);
const json = await resp.json();
return json as UniversalProfileProxyResponse;
} catch (err) {
return null;
}
return profiles.fetch(address.toLowerCase());
},
});
};
Expand All @@ -49,15 +56,15 @@ export const IdenticonUniversalProfile: React.FC<Props> = ({
address,
fallbackIcon,
}) => {
const { data: up, isLoading } = useUniversalProfile(address);

const { data: up, isLoading } = useUniversalProfile(address.toLowerCase());
let profileImageUrl = '';
if (up?.LSP3Profile?.profileImage !== null && up?.hasProfileImage) {
const hasProfileImages = up?.profileImages !== null && up?.profileImages !== undefined && up?.profileImages.length > 0;
if (hasProfileImages) {
const lastImageIndex =
Object.values(up?.LSP3Profile?.profileImage || {}).length - 1;
Object.values(up?.profileImages || {}).length - 1;

profileImageUrl = up?.hasProfileImage ?
up?.LSP3Profile?.profileImage[lastImageIndex].url :
profileImageUrl = hasProfileImages ?
resizeProfileImage(up?.profileImages[lastImageIndex].src) :
'';
}

Expand Down
Loading

0 comments on commit 172581b

Please sign in to comment.