Setup react-query

pull/4/head
J M Rossy 2 years ago
parent edf5652bea
commit e95f5cf6c5
  1. 2
      .prettierrc
  2. 1
      package.json
  3. 41
      src/components/search/SearchError.tsx
  4. 2
      src/consts/appConfig.ts
  5. 2
      src/consts/networksConfig.ts
  6. 30
      src/features/debugger/TxDebugger.tsx
  7. 3
      src/features/search/MessageSearch.tsx
  8. 15
      src/pages/_app.tsx
  9. 27
      yarn.lock

@ -3,7 +3,7 @@
"printWidth": 100, "printWidth": 100,
"singleQuote": true, "singleQuote": true,
"trailingComma": "all", "trailingComma": "all",
"importOrder": ["^@abacus-network/(.*)$", "^../(.*)$", "^./(.*)$"], "importOrder": ["^@hyperlane-xyz/(.*)$", "^../(.*)$", "^./(.*)$"],
"importOrderSeparation": true, "importOrderSeparation": true,
"importOrderSortSpecifiers": true "importOrderSortSpecifiers": true
} }

@ -7,6 +7,7 @@
"@hyperlane-xyz/sdk": "^0.5.0-beta0", "@hyperlane-xyz/sdk": "^0.5.0-beta0",
"@metamask/jazzicon": "https://github.com/jmrossy/jazzicon#7a8df28974b4e81129bfbe3cab76308b889032a6", "@metamask/jazzicon": "https://github.com/jmrossy/jazzicon#7a8df28974b4e81129bfbe3cab76308b889032a6",
"@rainbow-me/rainbowkit": "^0.4.5", "@rainbow-me/rainbowkit": "^0.4.5",
"@tanstack/react-query": "^4.6.0",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"ethers": "^5.6.8", "ethers": "^5.6.8",
"formik": "^2.2.9", "formik": "^2.2.9",

@ -1,5 +1,6 @@
import Image from 'next/future/image'; import Image from 'next/future/image';
import BugIcon from '../../images/icons/bug.svg';
import ErrorIcon from '../../images/icons/error-circle.svg'; import ErrorIcon from '../../images/icons/error-circle.svg';
import SearchOffIcon from '../../images/icons/search-off.svg'; import SearchOffIcon from '../../images/icons/search-off.svg';
import ShrugIcon from '../../images/icons/shrug.svg'; import ShrugIcon from '../../images/icons/shrug.svg';
@ -31,25 +32,55 @@ export function SearchError({
); );
} }
export function SearchInvalidError({ show }: { show: boolean }) { export function NoSearchError({ show }: { show: boolean }) {
return (
<SearchError
show={show}
imgSrc={BugIcon}
text="Enter a transaction hash that involved at least one Hyperlane message to begin."
imgWidth={50}
/>
);
}
export function SearchInvalidError({
show,
allowAddress,
}: {
show: boolean;
allowAddress: boolean;
}) {
return ( return (
<SearchError <SearchError
show={show} show={show}
imgSrc={SearchOffIcon} imgSrc={SearchOffIcon}
text="Sorry, that search input is not valid. Please try an account text={`Sorry, that search input is not valid. Please try ${
addresses or a transaction hash like 0x123..." allowAddress ? 'an account addresses or ' : ''
}a transaction hash like 0xABC123...`}
imgWidth={70} imgWidth={70}
/> />
); );
} }
export function SearchEmptyError({ show, hasInput }: { show: boolean; hasInput: boolean }) { export function SearchEmptyError({
show,
hasInput,
allowAddress,
}: {
show: boolean;
hasInput: boolean;
allowAddress: boolean;
}) {
return ( return (
<SearchError <SearchError
show={show} show={show}
imgSrc={ShrugIcon} imgSrc={ShrugIcon}
text={`Sorry, no results found. Please try ${ text={`Sorry, no results found. Please try ${
hasInput ? 'a different address or hash' : 'again later' hasInput
? allowAddress
? 'a different address or transaction hash'
: 'a different transaction hash'
: 'again later'
}.`} }.`}
imgWidth={110} imgWidth={110}
/> />

@ -9,7 +9,7 @@ export const configs: Record<Environment, Config> = {
debug: isDevMode, debug: isDevMode,
version, version,
url: 'https://explorer.hyperlane.xyz', url: 'https://explorer.hyperlane.xyz',
apiUrl: 'https://abacus-explorer-api.hasura.app/v1/graphql', apiUrl: 'https://abacus-explorer-api.hasura.app/v1/graphql', // TODO change
}, },
testnet2: { testnet2: {
environment: Environment.Testnet2, environment: Environment.Testnet2,

@ -1,6 +1,6 @@
import { Chain, allChains as allChainsWagmi, chain } from 'wagmi'; import { Chain, allChains as allChainsWagmi, chain } from 'wagmi';
import { chainConnectionConfigs } from '@abacus-network/sdk'; import { chainConnectionConfigs } from '@hyperlane-xyz/sdk';
export const testConfigs = { export const testConfigs = {
goerli: chainConnectionConfigs.goerli, goerli: chainConnectionConfigs.goerli,

@ -1,8 +1,10 @@
import { useState } from 'react'; import { useQuery } from '@tanstack/react-query';
import { useCallback, useState } from 'react';
import { Fade } from '../../components/animation/Fade'; import { Fade } from '../../components/animation/Fade';
import { SearchBar } from '../../components/search/SearchBar'; import { SearchBar } from '../../components/search/SearchBar';
import { import {
NoSearchError,
SearchEmptyError, SearchEmptyError,
SearchInvalidError, SearchInvalidError,
SearchUnknownError, SearchUnknownError,
@ -13,6 +15,8 @@ import useDebounce from '../../utils/debounce';
import { sanitizeString } from '../../utils/string'; import { sanitizeString } from '../../utils/string';
import { isValidSearchQuery } from '../search/utils'; import { isValidSearchQuery } from '../search/utils';
import { debugMessageForHash } from './debugMessage';
export function TxDebugger() { export function TxDebugger() {
const environment = useStore((s) => s.environment); const environment = useStore((s) => s.environment);
@ -21,11 +25,15 @@ export function TxDebugger() {
const debouncedSearchInput = useDebounce(searchInput, 750); const debouncedSearchInput = useDebounce(searchInput, 750);
const hasInput = !!debouncedSearchInput; const hasInput = !!debouncedSearchInput;
const sanitizedInput = sanitizeString(debouncedSearchInput); const sanitizedInput = sanitizeString(debouncedSearchInput);
const isValidInput = hasInput ? isValidSearchQuery(sanitizedInput, false) : true; const isValidInput = isValidSearchQuery(sanitizedInput, false);
const fetching = false; // Debugger query
const hasError = false; const query = useCallback(() => {
const txResult = {}; if (!isValidInput || !sanitizedInput) return null;
else return debugMessageForHash(sanitizedInput, environment);
}, [isValidInput, sanitizedInput, environment]);
const { isLoading: fetching, error, data } = useQuery(['debugMessage'], query);
const hasError = !!error;
return ( return (
<> <>
@ -36,19 +44,19 @@ export function TxDebugger() {
placeholder="Search transaction hash to debug message" placeholder="Search transaction hash to debug message"
/> />
<div className="w-full h-[38.05rem] mt-5 bg-white shadow-md border border-blue-50 rounded overflow-auto relative"> <div className="w-full h-[38.05rem] mt-5 bg-white shadow-md border border-blue-50 rounded overflow-auto relative">
{/* Content header and filter bar */}
<div className="px-2 py-3 sm:px-4 md:px-5 md:py-3 flex items-center justify-between border-b border-gray-100"> <div className="px-2 py-3 sm:px-4 md:px-5 md:py-3 flex items-center justify-between border-b border-gray-100">
<h2 className="text-gray-600">{`Transaction Debugger (${envDisplayValue[environment]})`}</h2> <h2 className="text-gray-600">{`Transaction Debugger (${envDisplayValue[environment]})`}</h2>
</div> </div>
{/* Message list */}
<Fade show={!hasError && isValidInput && !!txResult}>{JSON.stringify(txResult)}</Fade>
<SearchInvalidError show={!isValidInput} /> <Fade show={isValidInput && !hasError && !!data}>{JSON.stringify(data)}</Fade>
<SearchUnknownError show={isValidInput && hasError} />
<SearchEmptyError <SearchEmptyError
show={isValidInput && !hasError && !fetching && !txResult} show={isValidInput && !hasError && !fetching && !data}
hasInput={hasInput} hasInput={hasInput}
allowAddress={false}
/> />
<NoSearchError show={!hasInput && !hasError} />
<SearchInvalidError show={hasInput && !hasError && !isValidInput} allowAddress={false} />
<SearchUnknownError show={hasInput && hasError} />
</div> </div>
</> </>
); );

@ -125,11 +125,12 @@ export function MessageSearch() {
))} ))}
</Fade> </Fade>
<SearchInvalidError show={!isValidInput} /> <SearchInvalidError show={!isValidInput} allowAddress={true} />
<SearchUnknownError show={isValidInput && hasError} /> <SearchUnknownError show={isValidInput && hasError} />
<SearchEmptyError <SearchEmptyError
show={isValidInput && !hasError && !fetching && messageList.length === 0} show={isValidInput && !hasError && !fetching && messageList.length === 0}
hasInput={hasInput} hasInput={hasInput}
allowAddress={true}
/> />
</div> </div>
</> </>

@ -5,6 +5,7 @@ import {
wallet, wallet,
} from '@rainbow-me/rainbowkit'; } from '@rainbow-me/rainbowkit';
import '@rainbow-me/rainbowkit/styles.css'; import '@rainbow-me/rainbowkit/styles.css';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { AppProps } from 'next/app'; import type { AppProps } from 'next/app';
import { ToastContainer, Zoom, toast } from 'react-toastify'; import { ToastContainer, Zoom, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css'; import 'react-toastify/dist/ReactToastify.css';
@ -52,6 +53,8 @@ const urqlClients: Record<Environment, Client> = {
}), }),
}; };
const reactQueryClient = new QueryClient();
export default function App({ Component, router, pageProps }: AppProps) { export default function App({ Component, router, pageProps }: AppProps) {
const environment = useStore((s) => s.environment); const environment = useStore((s) => s.environment);
@ -74,11 +77,13 @@ export default function App({ Component, router, pageProps }: AppProps) {
fontStack: 'system', fontStack: 'system',
})} })}
> >
<UrqlProvider value={urqlClients[environment]}> <QueryClientProvider client={reactQueryClient}>
<AppLayout pathName={pathName}> <UrqlProvider value={urqlClients[environment]}>
<Component {...pageProps} /> <AppLayout pathName={pathName}>
</AppLayout> <Component {...pageProps} />
</UrqlProvider> </AppLayout>
</UrqlProvider>
</QueryClientProvider>
</RainbowKitProvider> </RainbowKitProvider>
<ToastContainer transition={Zoom} position={toast.POSITION.BOTTOM_RIGHT} limit={2} /> <ToastContainer transition={Zoom} position={toast.POSITION.BOTTOM_RIGHT} limit={2} />
</WagmiConfig> </WagmiConfig>

@ -885,6 +885,7 @@ __metadata:
"@hyperlane-xyz/sdk": ^0.5.0-beta0 "@hyperlane-xyz/sdk": ^0.5.0-beta0
"@metamask/jazzicon": "https://github.com/jmrossy/jazzicon#7a8df28974b4e81129bfbe3cab76308b889032a6" "@metamask/jazzicon": "https://github.com/jmrossy/jazzicon#7a8df28974b4e81129bfbe3cab76308b889032a6"
"@rainbow-me/rainbowkit": ^0.4.5 "@rainbow-me/rainbowkit": ^0.4.5
"@tanstack/react-query": ^4.6.0
"@trivago/prettier-plugin-sort-imports": ^3.2.0 "@trivago/prettier-plugin-sort-imports": ^3.2.0
"@types/node": 18.0.4 "@types/node": 18.0.4
"@types/react": 18.0.15 "@types/react": 18.0.15
@ -1257,6 +1258,32 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@tanstack/query-core@npm:4.6.0":
version: 4.6.0
resolution: "@tanstack/query-core@npm:4.6.0"
checksum: 945a3b1ddc89ddf484f828cee0be5db0939f51865b2518f8c4ef351c6a3fc992f8c9fbbd32a5bf16b97d0250e95f43c1e571d5a1dfefd99ab835ffe0f934b159
languageName: node
linkType: hard
"@tanstack/react-query@npm:^4.6.0":
version: 4.6.0
resolution: "@tanstack/react-query@npm:4.6.0"
dependencies:
"@tanstack/query-core": 4.6.0
use-sync-external-store: ^1.2.0
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
react-native: "*"
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
checksum: 39b9f5a71b1c699927db515419889b04e60410472481c5b08645eda8310c73c0c8acfcdffd9d63a5730eefff5e74a4a84939082fbe467d3af0571d837978fbb5
languageName: node
linkType: hard
"@tootallnate/once@npm:2": "@tootallnate/once@npm:2":
version: 2.0.0 version: 2.0.0
resolution: "@tootallnate/once@npm:2.0.0" resolution: "@tootallnate/once@npm:2.0.0"

Loading…
Cancel
Save