From 222d7db2ed4e62dd61d15774bdb67eb2c900c1c1 Mon Sep 17 00:00:00 2001 From: poomthiti Date: Sat, 1 Jul 2023 12:24:06 +0700 Subject: [PATCH 1/4] feat: search by icns names feature and Show registered icns names on account details page --- CHANGELOG.md | 1 + src/lib/app-provider/hooks/useBaseApiRoute.ts | 6 ++ src/lib/components/CopyLink.tsx | 29 +++++-- src/lib/components/icon/CustomIcon.tsx | 11 +++ src/lib/layout/Searchbar.tsx | 44 +++++++--- .../components/AccountHeader.tsx | 87 +++++++++++++++++++ .../components/PrimaryNameMark.tsx | 10 +++ src/lib/pages/account-details/index.tsx | 40 ++------- src/lib/services/nameService.ts | 80 +++++++++++++++++ src/lib/services/ns.ts | 25 ++++++ src/lib/services/searchService.ts | 45 ++++++++-- 11 files changed, 320 insertions(+), 58 deletions(-) create mode 100644 src/lib/pages/account-details/components/AccountHeader.tsx create mode 100644 src/lib/pages/account-details/components/PrimaryNameMark.tsx create mode 100644 src/lib/services/nameService.ts create mode 100644 src/lib/services/ns.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index a89eafd9b..10586e15c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#415](https://github.com/alleslabs/celatone-frontend/pull/415) Search by icns names feature and Show registered icns names on account details page - [#398](https://github.com/alleslabs/celatone-frontend/pull/398) Setup Jest and sample tests - [#411](https://github.com/alleslabs/celatone-frontend/pull/411) Add override api endpoint - [#385](https://github.com/alleslabs/celatone-frontend/pull/385) Upgrade cosmos kit major version and replace hooks diff --git a/src/lib/app-provider/hooks/useBaseApiRoute.ts b/src/lib/app-provider/hooks/useBaseApiRoute.ts index 4d9011300..96c221d81 100644 --- a/src/lib/app-provider/hooks/useBaseApiRoute.ts +++ b/src/lib/app-provider/hooks/useBaseApiRoute.ts @@ -11,6 +11,8 @@ export const useBaseApiRoute = ( | "codes" | "accounts" | "rest" + | "icns_names" + | "icns_address" ): string => { const { chainConfig: { chain, api: configApi }, @@ -41,6 +43,10 @@ export const useBaseApiRoute = ( return `${api}/accounts/${chain}/${currentChainId}`; case "rest": return `${api}/rest/${chain}/${currentChainId}`; + case "icns_names": + return `${api}/icns/names`; + case "icns_address": + return `${api}/icns/address`; default: throw new Error( "Error retrieving chain, api, or currentChainId from chain config." diff --git a/src/lib/components/CopyLink.tsx b/src/lib/components/CopyLink.tsx index 67c98ee9f..c935e3d88 100644 --- a/src/lib/components/CopyLink.tsx +++ b/src/lib/components/CopyLink.tsx @@ -1,3 +1,4 @@ +import type { FlexProps } from "@chakra-ui/react"; import { Flex, Text, useClipboard } from "@chakra-ui/react"; import { useState } from "react"; @@ -7,13 +8,20 @@ import { AmpTrackCopier } from "lib/services/amplitude"; import { CustomIcon } from "./icon"; import { Tooltip } from "./Tooltip"; -interface CopyLinkProps { +interface CopyLinkProps extends FlexProps { value: string; amptrackSection?: string; type: string; + withoutIcon?: boolean; } -export const CopyLink = ({ value, amptrackSection, type }: CopyLinkProps) => { +export const CopyLink = ({ + value, + amptrackSection, + type, + withoutIcon, + ...flexProps +}: CopyLinkProps) => { const { address } = useCurrentChain(); const { onCopy, hasCopied } = useClipboard(value); const [isHover, setIsHover] = useState(false); @@ -37,6 +45,7 @@ export const CopyLink = ({ value, amptrackSection, type }: CopyLinkProps) => { cursor="pointer" onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} + {...flexProps} > { > {value === address ? `${value} (Me)` : value} - + {!withoutIcon && ( + + )} ); diff --git a/src/lib/components/icon/CustomIcon.tsx b/src/lib/components/icon/CustomIcon.tsx index f27579d61..94373e13b 100644 --- a/src/lib/components/icon/CustomIcon.tsx +++ b/src/lib/components/icon/CustomIcon.tsx @@ -1215,6 +1215,17 @@ export const ICONS = { ), viewBox: "0.5 1 16 16", }, + "star-solid": { + svg: ( + + ), + viewBox: "0 0 8 10", + }, "submit-proposal": { svg: ( ; + metadata: ResultMetadata; setCursor: (index: Option) => void; handleSelectResult: (type?: SearchResultType, isClick?: boolean) => void; } @@ -69,19 +75,20 @@ const ResultItem = ({ type, value, cursor, + metadata, setCursor, handleSelectResult, }: ResultItemProps) => { const route = getRouteOptions(type)?.pathname; - + const { data: icnsNames } = useICNSNamesByAddress(value as Addr); return ( {type} {route && ( - index !== cursor && setCursor(index)} onClick={() => handleSelectResult(type, true)} > - {value} - + {metadata.icns.address || icnsNames ? ( + <> + {metadata.icns.address || value} + + {icnsNames ? icnsNames.primary_name : value} + + + ) : ( + {value} + )} + )} ); @@ -102,12 +118,14 @@ const ResultRender = ({ results, keyword, cursor, + metadata, setCursor, handleSelectResult, }: { results: SearchResultType[]; keyword: string; cursor: Option; + metadata: ResultMetadata; setCursor: (index: Option) => void; handleSelectResult: (type?: SearchResultType, isClick?: boolean) => void; }) => ( @@ -126,6 +144,7 @@ const ResultRender = ({ type={type} value={keyword} cursor={cursor} + metadata={metadata} setCursor={setCursor} handleSelectResult={handleSelectResult} /> @@ -171,7 +190,7 @@ const Searchbar = () => { }, } = useCelatoneApp(); const navigate = useInternalNavigate(); - const { results, isLoading } = useSearchHandler(keyword, () => + const { results, isLoading, metadata } = useSearchHandler(keyword, () => setIsTyping(false) ); const boxRef = useRef(null); @@ -191,13 +210,13 @@ const Searchbar = () => { if (routeOptions) { navigate({ pathname: routeOptions.pathname, - query: { [routeOptions.query]: keyword }, + query: { [routeOptions.query]: metadata.icns.address || keyword }, }); setDisplayResults(false); setKeyword(""); } }, - [keyword, navigate] + [metadata.icns.address, keyword, navigate] ); const handleOnKeyEnter = useCallback( @@ -267,10 +286,11 @@ const Searchbar = () => { ) : ( )} diff --git a/src/lib/pages/account-details/components/AccountHeader.tsx b/src/lib/pages/account-details/components/AccountHeader.tsx new file mode 100644 index 000000000..f0300bfd6 --- /dev/null +++ b/src/lib/pages/account-details/components/AccountHeader.tsx @@ -0,0 +1,87 @@ +import { Flex, Heading, Image, Text } from "@chakra-ui/react"; + +import { CopyLink } from "lib/components/CopyLink"; +import { CustomIcon } from "lib/components/icon"; +import type { ICNSNamesResponse } from "lib/services/ns"; +import type { HumanAddr, Option, PublicDetail } from "lib/types"; + +import { PrimaryNameMark } from "./PrimaryNameMark"; + +interface AccounHeaderProps { + publicName: Option; + publicDetail: Option; + icnsName: Option; + accountAddress: HumanAddr; +} + +export const AccountHeader = ({ + publicName, + publicDetail, + icnsName, + accountAddress, +}: AccounHeaderProps) => { + const displayName = icnsName?.primary_name || "Account Details"; + + return ( + + + {publicDetail?.logo || icnsName?.primary_name ? ( + {publicDetail?.name + ) : ( + + )} + + {publicName ?? displayName} + + + + + Wallet Address: + + + + {icnsName?.primary_name && ( + + + Registered ICNS names: + + + {icnsName.names.map((name) => ( + <> + {name === icnsName.primary_name && } + + + ))} + + + )} + + ); +}; diff --git a/src/lib/pages/account-details/components/PrimaryNameMark.tsx b/src/lib/pages/account-details/components/PrimaryNameMark.tsx new file mode 100644 index 000000000..8ad8a330a --- /dev/null +++ b/src/lib/pages/account-details/components/PrimaryNameMark.tsx @@ -0,0 +1,10 @@ +import { CustomIcon } from "lib/components/icon"; +import { Tooltip } from "lib/components/Tooltip"; + +export const PrimaryNameMark = () => ( + +
+ +
+
+); diff --git a/src/lib/pages/account-details/index.tsx b/src/lib/pages/account-details/index.tsx index c32459d3c..37e314394 100644 --- a/src/lib/pages/account-details/index.tsx +++ b/src/lib/pages/account-details/index.tsx @@ -6,14 +6,12 @@ import { TabPanels, Tabs, Text, - Image, } from "@chakra-ui/react"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import { useValidateAddress, useWasmConfig } from "lib/app-provider"; import { Breadcrumb } from "lib/components/Breadcrumb"; -import { CopyLink } from "lib/components/CopyLink"; import { CustomTab } from "lib/components/CustomTab"; import { CustomIcon } from "lib/components/icon"; import { Loading } from "lib/components/Loading"; @@ -22,6 +20,7 @@ import { InvalidState } from "lib/components/state"; import { useAccountDetailsTableCounts } from "lib/model/account"; import { useAccountId } from "lib/services/accountService"; import { AmpEvent, AmpTrack, AmpTrackUseTab } from "lib/services/amplitude"; +import { useICNSNamesByAddress } from "lib/services/nameService"; import { usePublicProjectByAccountAddress, usePublicProjectBySlug, @@ -34,6 +33,7 @@ import { truncate, } from "lib/utils"; +import { AccountHeader } from "./components/AccountHeader"; import { AssetsSection } from "./components/asset"; import { DelegationsSection } from "./components/delegations"; import { @@ -70,6 +70,7 @@ const AccountDetailsBody = ({ accountAddress }: AccountDetailsBodyProps) => { const { data: publicInfo } = usePublicProjectByAccountAddress(accountAddress); const { data: publicInfoBySlug } = usePublicProjectBySlug(publicInfo?.slug); const { data: accountId } = useAccountId(accountAddress); + const { data: icnsName } = useICNSNamesByAddress(accountAddress); const publicDetail = publicInfoBySlug?.details; @@ -90,8 +91,6 @@ const AccountDetailsBody = ({ accountAddress }: AccountDetailsBodyProps) => { scrollToTop(); }; - const displayName = publicInfo?.name ?? "Account Details"; - return ( <> @@ -108,33 +107,12 @@ const AccountDetailsBody = ({ accountAddress }: AccountDetailsBodyProps) => { mb={6} /> )} - - - - {publicDetail?.logo && ( - {publicDetail.name} - )} - - {displayName} - - - - - Wallet Address: - - - - + {publicInfo?.description && ( => { + const resolverEndpoint = useBaseApiRoute("icns_names"); + const getAddressType = useGetAddressType(); + const addressType = getAddressType(address); + + return useQuery({ + queryKey: ["icns_names", resolverEndpoint, address], + queryFn: async () => queryICNSNamesByAddress(resolverEndpoint, address), + refetchOnWindowFocus: false, + enabled: + addressType === "contract_address" || addressType === "user_address", + retry: 1, + }); +}; + +interface AddressByICNSInternal { + address: Addr; + addressType: AddressReturnType; +} + +export const useAddressByICNSName = ( + name: string +): UseQueryResult => { + const resolverEndpoint = useBaseApiRoute("icns_address"); + const lcdEndpoint = useBaseApiRoute("rest"); + const getAddressType = useGetAddressType(); + const { + chain: { bech32_prefix: bech32Prefix }, + } = useCurrentChain(); + + const queryFn = async ({ + queryKey, + }: QueryFunctionContext): Promise => { + const icnsAddress = await queryAddressByICNSName( + queryKey[1], + queryKey[2], + queryKey[3] + ); + let addressType = getAddressType(icnsAddress); + if (addressType === "contract_address") { + const contractData = await queryContract( + lcdEndpoint, + icnsAddress as ContractAddr + ); + if (!contractData) addressType = "user_address"; + } + return { + address: icnsAddress, + addressType, + }; + }; + + return useQuery({ + queryKey: ["icns_address", resolverEndpoint, name, bech32Prefix], + queryFn, + refetchOnWindowFocus: false, + enabled: Boolean(name), + retry: 1, + }); +}; diff --git a/src/lib/services/ns.ts b/src/lib/services/ns.ts new file mode 100644 index 000000000..ad8e1005f --- /dev/null +++ b/src/lib/services/ns.ts @@ -0,0 +1,25 @@ +import axios from "axios"; + +import type { Addr } from "lib/types"; + +export interface ICNSNamesResponse { + names: string[]; + primary_name: string; +} + +export const queryICNSNamesByAddress = async ( + baseEndpoint: string, + address: Addr +): Promise => { + const { data } = await axios.get(`${baseEndpoint}/${address}`); + return data; +}; + +export const queryAddressByICNSName = async ( + baseEndpoint: string, + name: string, + bech32Prefix: string +): Promise => { + const { data } = await axios.get(`${baseEndpoint}/${name}/${bech32Prefix}`); + return data.address; +}; diff --git a/src/lib/services/searchService.ts b/src/lib/services/searchService.ts index 9638f7a4b..8aa805793 100644 --- a/src/lib/services/searchService.ts +++ b/src/lib/services/searchService.ts @@ -1,17 +1,18 @@ import { useQuery } from "@tanstack/react-query"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useBaseApiRoute, useCelatoneApp, useGetAddressType, } from "lib/app-provider"; -import type { ContractAddr } from "lib/types"; +import type { Addr, ContractAddr, Option } from "lib/types"; import { isBlock, isCodeId, isTxHash } from "lib/utils"; import { useBlockDetailsQuery } from "./blockService"; import { useCodeDataByCodeId } from "./codeService"; import { queryContract } from "./contract"; +import { useAddressByICNSName } from "./nameService"; import { useTxData } from "./txService"; export type SearchResultType = @@ -22,11 +23,21 @@ export type SearchResultType = | "Proposal ID" | "Block"; -// TODO: Add Proposal ID, ICNS query +export interface ResultMetadata { + icns: { + address: Option; + }; +} + +// TODO: Add Proposal ID export const useSearchHandler = ( keyword: string, resetHandlerStates: () => void -): { results: SearchResultType[]; isLoading: boolean } => { +): { + results: SearchResultType[]; + isLoading: boolean; + metadata: ResultMetadata; +} => { const [debouncedKeyword, setDebouncedKeyword] = useState(keyword); const { chainConfig: { @@ -54,6 +65,9 @@ export const useSearchHandler = ( ); const { data: blockData, isLoading: blockLoading } = useBlockDetailsQuery(debouncedKeyword); + const { data: icnsAddressData, isLoading: icnsAddressLoading } = + useAddressByICNSName(debouncedKeyword); + const txDataLoading = isTxHash(debouncedKeyword) && txLoading; const codeDataLoading = isWasm && isCodeId(debouncedKeyword) && codeLoading; const contractDataLoading = isWasm && contractLoading; @@ -61,6 +75,19 @@ export const useSearchHandler = ( const isAddr = addressType === "user_address" || addressType === "contract_address"; + const addressResult = useMemo(() => { + if (isAddr) { + return contractData ? "Contract Address" : "Wallet Address"; + } + + return ( + icnsAddressData?.address && + (icnsAddressData.addressType === "contract_address" + ? "Contract Address" + : "Wallet Address") + ); + }, [isAddr, contractData, icnsAddressData]); + useEffect(() => { const timeoutId = setTimeout(() => { setDebouncedKeyword(keyword); @@ -71,7 +98,7 @@ export const useSearchHandler = ( return { results: [ - isAddr && (contractData ? "Contract Address" : "Wallet Address"), + addressResult, txData && "Transaction Hash", codeData && "Code ID", blockData && "Block", @@ -80,6 +107,12 @@ export const useSearchHandler = ( txDataLoading || codeDataLoading || contractDataLoading || - blockDataLoading, + blockDataLoading || + icnsAddressLoading, + metadata: { + icns: { + address: icnsAddressData?.address, + }, + }, }; }; From c8b0d230e471f24c6da3c9b63410c82866a49c7b Mon Sep 17 00:00:00 2001 From: poomthiti Date: Tue, 4 Jul 2023 16:09:18 +0700 Subject: [PATCH 2/4] fix: yarn pkg manager --- .gitignore | 4 ++++ package.json | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 946a6e448..6d14942ca 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,7 @@ next.config.original.js .sentryclirc next.config.original.js next.config.wizardcopy.js + +# yarn +/.yarn +.yarnrc.yml \ No newline at end of file diff --git a/package.json b/package.json index 2f55c8500..06808e71a 100644 --- a/package.json +++ b/package.json @@ -100,5 +100,6 @@ "standard-version": "^9.5.0", "ts-jest": "^29.0.5", "typescript": "^4.9.5" - } + }, + "packageManager": "yarn@1.22.19" } From ec22091c76ad1b2b9df372c0f37e4cb3e16dfb5d Mon Sep 17 00:00:00 2001 From: poomthiti Date: Wed, 5 Jul 2023 15:35:22 +0700 Subject: [PATCH 3/4] feat: strip prefix, rearrange primary name --- .../components/PrimaryNameMark.tsx | 0 src/lib/layout/Searchbar.tsx | 39 +++++++---- .../components/AccountHeader.tsx | 13 ++-- src/lib/services/nameService.ts | 21 +++++- src/lib/services/searchService.ts | 64 ++++++++++++++----- 5 files changed, 101 insertions(+), 36 deletions(-) rename src/lib/{pages/account-details => }/components/PrimaryNameMark.tsx (100%) diff --git a/src/lib/pages/account-details/components/PrimaryNameMark.tsx b/src/lib/components/PrimaryNameMark.tsx similarity index 100% rename from src/lib/pages/account-details/components/PrimaryNameMark.tsx rename to src/lib/components/PrimaryNameMark.tsx diff --git a/src/lib/layout/Searchbar.tsx b/src/lib/layout/Searchbar.tsx index f22f86bf9..90c9db2bc 100644 --- a/src/lib/layout/Searchbar.tsx +++ b/src/lib/layout/Searchbar.tsx @@ -16,14 +16,14 @@ import type { ChangeEvent, KeyboardEvent } from "react"; import { useCelatoneApp, useInternalNavigate } from "lib/app-provider"; import { CustomIcon } from "lib/components/icon"; +import { PrimaryNameMark } from "lib/components/PrimaryNameMark"; import { AmpTrackUseMainSearch } from "lib/services/amplitude"; -import { useICNSNamesByAddress } from "lib/services/nameService"; import type { ResultMetadata, SearchResultType, } from "lib/services/searchService"; import { useSearchHandler } from "lib/services/searchService"; -import type { Addr, Option } from "lib/types"; +import type { Option } from "lib/types"; const NOT_FOUND_MSG = "Matches not found. Please check your spelling or make sure you have selected the correct network."; @@ -80,7 +80,6 @@ const ResultItem = ({ handleSelectResult, }: ResultItemProps) => { const route = getRouteOptions(type)?.pathname; - const { data: icnsNames } = useICNSNamesByAddress(value as Addr); return ( @@ -98,15 +97,31 @@ const ResultItem = ({ onMouseMove={() => index !== cursor && setCursor(index)} onClick={() => handleSelectResult(type, true)} > - {metadata.icns.address || icnsNames ? ( - <> - {metadata.icns.address || value} - - {icnsNames ? icnsNames.primary_name : value} - - - ) : ( - {value} + {metadata.icns.address || value} + {metadata.icns.icnsNames?.primary_name && ( + + + + + {metadata.icns.icnsNames.primary_name} + + + {value !== metadata.icns.address && + value !== metadata.icns.icnsNames?.primary_name && ( + + {value} + + )} + )} )} diff --git a/src/lib/pages/account-details/components/AccountHeader.tsx b/src/lib/pages/account-details/components/AccountHeader.tsx index f0300bfd6..5b3073097 100644 --- a/src/lib/pages/account-details/components/AccountHeader.tsx +++ b/src/lib/pages/account-details/components/AccountHeader.tsx @@ -2,11 +2,10 @@ import { Flex, Heading, Image, Text } from "@chakra-ui/react"; import { CopyLink } from "lib/components/CopyLink"; import { CustomIcon } from "lib/components/icon"; +import { PrimaryNameMark } from "lib/components/PrimaryNameMark"; import type { ICNSNamesResponse } from "lib/services/ns"; import type { HumanAddr, Option, PublicDetail } from "lib/types"; -import { PrimaryNameMark } from "./PrimaryNameMark"; - interface AccounHeaderProps { publicName: Option; publicDetail: Option; @@ -66,16 +65,16 @@ export const AccountHeader = ({ value={name} type="icns_names" withoutIcon - _last={{ - _after: { - display: "none", - }, - }} _after={{ content: '"/"', fontSize: "14px", ml: 1, }} + _last={{ + _after: { + display: "none", + }, + }} /> ))} diff --git a/src/lib/services/nameService.ts b/src/lib/services/nameService.ts index 115e383f1..eacbf1127 100644 --- a/src/lib/services/nameService.ts +++ b/src/lib/services/nameService.ts @@ -23,9 +23,24 @@ export const useICNSNamesByAddress = ( const getAddressType = useGetAddressType(); const addressType = getAddressType(address); + const queryFn = async ({ + queryKey, + }: QueryFunctionContext): Promise => { + const icnsNames = await queryICNSNamesByAddress( + queryKey[1], + queryKey[2] as Addr + ); + const primaryIndex = icnsNames.names.indexOf(icnsNames.primary_name); + if (primaryIndex > -1) { + icnsNames.names.splice(primaryIndex, 1); + icnsNames.names.unshift(icnsNames.primary_name); + } + return icnsNames; + }; + return useQuery({ queryKey: ["icns_names", resolverEndpoint, address], - queryFn: async () => queryICNSNamesByAddress(resolverEndpoint, address), + queryFn, refetchOnWindowFocus: false, enabled: addressType === "contract_address" || addressType === "user_address", @@ -51,9 +66,11 @@ export const useAddressByICNSName = ( const queryFn = async ({ queryKey, }: QueryFunctionContext): Promise => { + // Strip bech32 prefix to allow searching with .prefix (e.g. example.osmo) + const [stripPrefixName] = queryKey[2].split(`.${bech32Prefix}`); const icnsAddress = await queryAddressByICNSName( queryKey[1], - queryKey[2], + stripPrefixName, queryKey[3] ); let addressType = getAddressType(icnsAddress); diff --git a/src/lib/services/searchService.ts b/src/lib/services/searchService.ts index 8aa805793..232e76e8a 100644 --- a/src/lib/services/searchService.ts +++ b/src/lib/services/searchService.ts @@ -12,7 +12,8 @@ import { isBlock, isCodeId, isTxHash } from "lib/utils"; import { useBlockDetailsQuery } from "./blockService"; import { useCodeDataByCodeId } from "./codeService"; import { queryContract } from "./contract"; -import { useAddressByICNSName } from "./nameService"; +import { useAddressByICNSName, useICNSNamesByAddress } from "./nameService"; +import type { ICNSNamesResponse } from "./ns"; import { useTxData } from "./txService"; export type SearchResultType = @@ -24,11 +25,40 @@ export type SearchResultType = | "Block"; export interface ResultMetadata { - icns: { - address: Option; - }; + icns: { icnsNames: Option; address: Option }; } +const resolveLoadingState = ({ + keyword, + txLoading, + codeLoading, + contractLoading, + blockLoading, + icnsAddressLoading, + isWasm, +}: { + keyword: string; + txLoading: boolean; + codeLoading: boolean; + contractLoading: boolean; + blockLoading: boolean; + icnsAddressLoading: boolean; + isWasm: boolean; +}) => { + const txDataLoading = isTxHash(keyword) && txLoading; + const codeDataLoading = isWasm && isCodeId(keyword) && codeLoading; + const contractDataLoading = isWasm && contractLoading; + const blockDataLoading = isBlock(keyword) && blockLoading; + + return ( + txDataLoading || + codeDataLoading || + contractDataLoading || + blockDataLoading || + icnsAddressLoading + ); +}; + // TODO: Add Proposal ID export const useSearchHandler = ( keyword: string, @@ -68,18 +98,18 @@ export const useSearchHandler = ( const { data: icnsAddressData, isLoading: icnsAddressLoading } = useAddressByICNSName(debouncedKeyword); - const txDataLoading = isTxHash(debouncedKeyword) && txLoading; - const codeDataLoading = isWasm && isCodeId(debouncedKeyword) && codeLoading; - const contractDataLoading = isWasm && contractLoading; - const blockDataLoading = isBlock(debouncedKeyword) && blockLoading; const isAddr = addressType === "user_address" || addressType === "contract_address"; + // provide ICNS metadata result + const { data: icnsNames } = useICNSNamesByAddress( + (isAddr ? debouncedKeyword : icnsAddressData?.address) as Addr + ); + const addressResult = useMemo(() => { if (isAddr) { return contractData ? "Contract Address" : "Wallet Address"; } - return ( icnsAddressData?.address && (icnsAddressData.addressType === "contract_address" @@ -103,15 +133,19 @@ export const useSearchHandler = ( codeData && "Code ID", blockData && "Block", ].filter((res) => Boolean(res)) as SearchResultType[], - isLoading: - txDataLoading || - codeDataLoading || - contractDataLoading || - blockDataLoading || + isLoading: resolveLoadingState({ + keyword: debouncedKeyword, + txLoading, + codeLoading, + contractLoading, + blockLoading, icnsAddressLoading, + isWasm, + }), metadata: { icns: { - address: icnsAddressData?.address, + icnsNames, + address: (isAddr ? debouncedKeyword : icnsAddressData?.address) as Addr, }, }, }; From 1539d6e190f85b48ea220b0443edd3798a102b9b Mon Sep 17 00:00:00 2001 From: evilpeach Date: Tue, 18 Jul 2023 13:32:00 +0700 Subject: [PATCH 4/4] chore: add type, remove warning --- src/lib/hooks/useLocalStorage.ts | 3 +-- src/lib/pages/account-details/components/AccountHeader.tsx | 4 ++-- src/lib/services/ns.ts | 6 ++++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/hooks/useLocalStorage.ts b/src/lib/hooks/useLocalStorage.ts index 9b18a30ab..6f83fa03f 100644 --- a/src/lib/hooks/useLocalStorage.ts +++ b/src/lib/hooks/useLocalStorage.ts @@ -13,7 +13,6 @@ export const useLocalStorage = ( const value = window.localStorage.getItem(key); return value ? (JSON.parse(value) as T) : defaultValue; } catch (e) { - console.warn(`Error reading localStorage key “${key}”:`, e); return defaultValue as T; } }); @@ -22,7 +21,7 @@ export const useLocalStorage = ( try { window.localStorage.setItem(key, JSON.stringify(storedValue)); } catch (e) { - console.warn(`Error setting localStorage key “${key}”:`, e); + // I want application to not crush, but don't care about the message } }, [key, storedValue]); diff --git a/src/lib/pages/account-details/components/AccountHeader.tsx b/src/lib/pages/account-details/components/AccountHeader.tsx index dc24d2a34..1d2d6a885 100644 --- a/src/lib/pages/account-details/components/AccountHeader.tsx +++ b/src/lib/pages/account-details/components/AccountHeader.tsx @@ -63,7 +63,7 @@ export const AccountHeader = ({ {icnsName.names.map((name) => ( - <> +
{name === icnsName.primary_name && } - +
))}
diff --git a/src/lib/services/ns.ts b/src/lib/services/ns.ts index ad8e1005f..a73358743 100644 --- a/src/lib/services/ns.ts +++ b/src/lib/services/ns.ts @@ -10,8 +10,10 @@ export interface ICNSNamesResponse { export const queryICNSNamesByAddress = async ( baseEndpoint: string, address: Addr -): Promise => { - const { data } = await axios.get(`${baseEndpoint}/${address}`); +) => { + const { data } = await axios.get( + `${baseEndpoint}/${address}` + ); return data; };