Commit 46af7ea9 authored by tom's avatar tom

Merge branch 'main' of github.com:blockscout/frontend into tx-api-update

parents b72dd002 6eda0ea4
...@@ -11,7 +11,9 @@ NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_ASSETS ...@@ -11,7 +11,9 @@ NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_ASSETS
NEXT_PUBLIC_NETWORK_TYPE=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_TYPE__ NEXT_PUBLIC_NETWORK_TYPE=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_TYPE__
NEXT_PUBLIC_NETWORK_SUBTYPE=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_SUBTYPE__ NEXT_PUBLIC_NETWORK_SUBTYPE=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_SUBTYPE__
NEXT_PUBLIC_NETWORK_ID=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_ID__ NEXT_PUBLIC_NETWORK_ID=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_ID__
NEXT_PUBLIC_NETWORK_CURRENCY=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_CURRENCY__ NEXT_PUBLIC_NETWORK_CURRENCY_NAME=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_CURRENCY_NAME__
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL__
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS__
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS__ NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS__
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=__PLACEHOLDER_FOR_NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED__ NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=__PLACEHOLDER_FOR_NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED__
......
...@@ -24,7 +24,7 @@ For local development please follow next steps: ...@@ -24,7 +24,7 @@ For local development please follow next steps:
- clone `.env.example` into `configs/envs/.env.secrets` and fill it with necessary secret values (see description [below](#environment-variables)) - clone `.env.example` into `configs/envs/.env.secrets` and fill it with necessary secret values (see description [below](#environment-variables))
- to spin up local dev server - to spin up local dev server
- for predefined networks configs (see full available list in `package.json`) you can just run `yarn dev:<app_name>` - for predefined networks configs (see full available list in `package.json`) you can just run `yarn dev:<app_name>`
- for custom network setup create `.env.local` file with all required environment variables from the [list](#environment-variables) and run `yarn dev` - for custom network setup create `.env.local` file with all required environment variables from the [list](#environment-variables) and run `yarn dev`
- navigate to the host from logs output - navigate to the host from logs output
## Components visual testing ## Components visual testing
...@@ -47,7 +47,9 @@ The app instance could be customized by passing following variables to NodeJS en ...@@ -47,7 +47,9 @@ The app instance could be customized by passing following variables to NodeJS en
| NEXT_PUBLIC_NETWORK_TYPE | `string` | Network type (used as first part of the base path) | `xdai` | | NEXT_PUBLIC_NETWORK_TYPE | `string` | Network type (used as first part of the base path) | `xdai` |
| NEXT_PUBLIC_NETWORK_SUBTYPE | `string` | Network subtype (used as second part of the base path) | `mainnet` | | NEXT_PUBLIC_NETWORK_SUBTYPE | `string` | Network subtype (used as second part of the base path) | `mainnet` |
| NEXT_PUBLIC_NETWORK_ID | `number` | Chain id, see [https://chainlist.org/](https://chainlist.org/) for the reference | `99` | | NEXT_PUBLIC_NETWORK_ID | `number` | Chain id, see [https://chainlist.org/](https://chainlist.org/) for the reference | `99` |
| NEXT_PUBLIC_NETWORK_CURRENCY | `string` | Network currency symbol | `xDAI` | | NEXT_PUBLIC_NETWORK_CURRENCY_NAME | `string` | Network currency name | `Ether` |
| NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL | `string` | Network currency symbol | `ETH` |
| NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS | `string` | Network currency decimals | `18` |
| NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS | `string` | Address of network's native token | `0x029a799563238d0e75e20be2f4bda0ea68d00172` | | NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS | `string` | Address of network's native token | `0x029a799563238d0e75e20be2f4bda0ea68d00172` |
| NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME | `string` *(optional)* | Network name for constructing url of token logos according to template `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${assetsNamePath}/assets/${tokenAddress}/logo.png`. It should match network name in TrustWallet assets repo, see the full list [here](https://github.com/trustwallet/assets/tree/master/blockchains). If not provided, the network type will be used as its assets path part | `ethereum` | | NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME | `string` *(optional)* | Network name for constructing url of token logos according to template `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${assetsNamePath}/assets/${tokenAddress}/logo.png`. It should match network name in TrustWallet assets repo, see the full list [here](https://github.com/trustwallet/assets/tree/master/blockchains). If not provided, the network type will be used as its assets path part | `ethereum` |
| NEXT_PUBLIC_NETWORK_LOGO | `string` *(optional)* | Network logo; if not provided, will fallback to logo predefined in the project; if the project doesn't have logo for such network then the common placeholder will be shown; *Note* that logo height should be 20px and width less than 120px | `https://www.fillmurray.com/240/40` | | NEXT_PUBLIC_NETWORK_LOGO | `string` *(optional)* | Network logo; if not provided, will fallback to logo predefined in the project; if the project doesn't have logo for such network then the common placeholder will be shown; *Note* that logo height should be 20px and width less than 120px | `https://www.fillmurray.com/240/40` |
...@@ -123,4 +125,4 @@ These are the steps that you have to follow to make everything work: ...@@ -123,4 +125,4 @@ These are the steps that you have to follow to make everything work:
- `deploy/values/main/values.yaml` - production environment - `deploy/values/main/values.yaml` - production environment
- `deploy/values/e2e/values.yaml` - e2e-test environment - `deploy/values/e2e/values.yaml` - e2e-test environment
Keep in mind that all json-like values should be single-quoted, e.g `[{'foo': 'bar'}]` Keep in mind that all json-like values should be single-quoted, e.g `[{'foo': 'bar'}]`
\ No newline at end of file
...@@ -8,6 +8,8 @@ const baseUrl = [ ...@@ -8,6 +8,8 @@ const baseUrl = [
process.env.NEXT_PUBLIC_APP_PORT ? ':' + process.env.NEXT_PUBLIC_APP_PORT : '', process.env.NEXT_PUBLIC_APP_PORT ? ':' + process.env.NEXT_PUBLIC_APP_PORT : '',
].join(''); ].join('');
const DEFAULT_CURRENCY_DECIMALS = 18;
const config = Object.freeze({ const config = Object.freeze({
env, env,
isDev, isDev,
...@@ -18,7 +20,11 @@ const config = Object.freeze({ ...@@ -18,7 +20,11 @@ const config = Object.freeze({
name: process.env.NEXT_PUBLIC_NETWORK_NAME, name: process.env.NEXT_PUBLIC_NETWORK_NAME,
id: process.env.NEXT_PUBLIC_NETWORK_ID, id: process.env.NEXT_PUBLIC_NETWORK_ID,
shortName: process.env.NEXT_PUBLIC_NETWORK_SHORT_NAME, shortName: process.env.NEXT_PUBLIC_NETWORK_SHORT_NAME,
currency: process.env.NEXT_PUBLIC_NETWORK_CURRENCY, currency: {
name: process.env.NEXT_PUBLIC_NETWORK_CURRENCY_NAME,
symbol: process.env.NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL,
decimals: Number(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS) || DEFAULT_CURRENCY_DECIMALS,
},
assetsPathname: process.env.NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME, assetsPathname: process.env.NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME,
nativeTokenAddress: process.env.NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS, nativeTokenAddress: process.env.NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS,
basePath: '/' + [ process.env.NEXT_PUBLIC_NETWORK_TYPE, process.env.NEXT_PUBLIC_NETWORK_SUBTYPE ].filter(Boolean).join('/'), basePath: '/' + [ process.env.NEXT_PUBLIC_NETWORK_TYPE, process.env.NEXT_PUBLIC_NETWORK_SUBTYPE ].filter(Boolean).join('/'),
......
...@@ -11,7 +11,9 @@ NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=poa ...@@ -11,7 +11,9 @@ NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=poa
NEXT_PUBLIC_NETWORK_TYPE=poa NEXT_PUBLIC_NETWORK_TYPE=poa
NEXT_PUBLIC_NETWORK_SUBTYPE=core NEXT_PUBLIC_NETWORK_SUBTYPE=core
NEXT_PUBLIC_NETWORK_ID=99 NEXT_PUBLIC_NETWORK_ID=99
NEXT_PUBLIC_NETWORK_CURRENCY=POA NEXT_PUBLIC_NETWORK_CURRENCY_NAME=POA
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=POA
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0x029a799563238d0e75e20be2f4bda0ea68d00172 NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0x029a799563238d0e75e20be2f4bda0ea68d00172
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
......
...@@ -309,8 +309,12 @@ frontend: ...@@ -309,8 +309,12 @@ frontend:
_default: sokol _default: sokol
NEXT_PUBLIC_NETWORK_ID: NEXT_PUBLIC_NETWORK_ID:
_default: 77 _default: 77
NEXT_PUBLIC_NETWORK_CURRENCY: NEXT_PUBLIC_NETWORK_CURRENCY_NAME:
_default: POA Network Sokol
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL:
_default: SPOA _default: SPOA
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS:
_default: 18
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED: NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED:
_default: 'true' _default: 'true'
NEXT_PUBLIC_FEATURED_NETWORKS: NEXT_PUBLIC_FEATURED_NETWORKS:
......
...@@ -305,8 +305,12 @@ frontend: ...@@ -305,8 +305,12 @@ frontend:
_default: sokol _default: sokol
NEXT_PUBLIC_NETWORK_ID: NEXT_PUBLIC_NETWORK_ID:
_default: 77 _default: 77
NEXT_PUBLIC_NETWORK_CURRENCY: NEXT_PUBLIC_NETWORK_CURRENCY_NAME:
_default: POA Network Sokol
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL:
_default: SPOA _default: SPOA
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS:
_default: 18
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED: NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED:
_default: 'true' _default: 'true'
NEXT_PUBLIC_FEATURED_NETWORKS: NEXT_PUBLIC_FEATURED_NETWORKS:
......
...@@ -305,8 +305,12 @@ frontend: ...@@ -305,8 +305,12 @@ frontend:
_default: sokol _default: sokol
NEXT_PUBLIC_NETWORK_ID: NEXT_PUBLIC_NETWORK_ID:
_default: 77 _default: 77
NEXT_PUBLIC_NETWORK_CURRENCY: NEXT_PUBLIC_NETWORK_CURRENCY_NAME:
_default: POA Network Sokol
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL:
_default: SPOA _default: SPOA
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS:
_default: 18
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED: NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED:
_default: 'true' _default: 'true'
NEXT_PUBLIC_FEATURED_NETWORKS: NEXT_PUBLIC_FEATURED_NETWORKS:
......
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import type { UserInfo } from 'types/api/account'; import type { UserInfo } from 'types/api/account';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
...@@ -14,7 +15,7 @@ interface Error { ...@@ -14,7 +15,7 @@ interface Error {
export default function useFetchProfileInfo() { export default function useFetchProfileInfo() {
const fetch = useFetch(); const fetch = useFetch();
return useQuery<unknown, Error, UserInfo>([ 'profile' ], async() => { return useQuery<unknown, Error, UserInfo>([ QueryKeys.profile ], async() => {
return fetch('/api/account/profile'); return fetch('/api/account/profile');
}, { }, {
refetchOnMount: false, refetchOnMount: false,
......
import handler from 'lib/api/handler';
const getUrl = () => {
return `/v2/config/json-rpc-url`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
export type JsonRpcUrlResponse = {
json_rpc_url: string;
}
export enum QueryKeys {
addressTags = 'address-tags',
apiKeys = 'api-keys',
block = 'block',
blocks = 'blocks',
customAbis = 'custom-abis',
profile = 'profile',
publicTags = 'public-tags',
transactionTags = 'transaction-tags',
watchlist = 'watchlist',
}
export enum QueryKeys {
csrf = 'csrf',
profile = 'profile',
transactionsPending = 'transactions_pending',
transactionsValidated = 'transactions_validated',
tx = 'tx',
txInternals = 'tx-internals',
txLog = 'tx-log',
txRawTrace = 'tx-raw-trace',
}
...@@ -12,6 +12,7 @@ import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form'; ...@@ -12,6 +12,7 @@ import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import type { ApiKey, ApiKeys, ApiKeyErrors } from 'types/api/account'; import type { ApiKey, ApiKeys, ApiKeyErrors } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import getPlaceholderWithError from 'lib/getPlaceholderWithError'; import getPlaceholderWithError from 'lib/getPlaceholderWithError';
...@@ -57,7 +58,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -57,7 +58,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
onSuccess: async(data) => { onSuccess: async(data) => {
const response = data as unknown as ApiKey; const response = data as unknown as ApiKey;
queryClient.setQueryData([ 'api-keys' ], (prevData: ApiKeys | undefined) => { queryClient.setQueryData([ QueryKeys.apiKeys ], (prevData: ApiKeys | undefined) => {
const isExisting = prevData && prevData.some((item) => item.api_key === response.api_key); const isExisting = prevData && prevData.some((item) => item.api_key === response.api_key);
if (isExisting) { if (isExisting) {
......
...@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { ApiKey, ApiKeys } from 'types/api/account'; import type { ApiKey, ApiKeys } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import DeleteModal from 'ui/shared/DeleteModal'; import DeleteModal from 'ui/shared/DeleteModal';
...@@ -22,7 +23,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => { ...@@ -22,7 +23,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
}, [ data.api_key, fetch ]); }, [ data.api_key, fetch ]);
const onSuccess = useCallback(async() => { const onSuccess = useCallback(async() => {
queryClient.setQueryData([ 'api-keys' ], (prevData: ApiKeys | undefined) => { queryClient.setQueryData([ QueryKeys.apiKeys ], (prevData: ApiKeys | undefined) => {
return prevData?.filter((item) => item.api_key !== data.api_key); return prevData?.filter((item) => item.api_key !== data.api_key);
}); });
}, [ data, queryClient ]); }, [ data, queryClient ]);
......
...@@ -6,6 +6,7 @@ import React from 'react'; ...@@ -6,6 +6,7 @@ import React from 'react';
import { scroller, Element } from 'react-scroll'; import { scroller, Element } from 'react-scroll';
import type { Block } from 'types/api/block'; import type { Block } from 'types/api/block';
import { QueryKeys } from 'types/client/accountQueries';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import clockIcon from 'icons/clock.svg'; import clockIcon from 'icons/clock.svg';
...@@ -34,7 +35,7 @@ const BlockDetails = () => { ...@@ -34,7 +35,7 @@ const BlockDetails = () => {
const fetch = useFetch(); const fetch = useFetch();
const { data, isLoading, isError, error } = useQuery<unknown, ErrorType<{ status: number }>, Block>( const { data, isLoading, isError, error } = useQuery<unknown, ErrorType<{ status: number }>, Block>(
[ 'block', router.query.id ], [ QueryKeys.block, router.query.id ],
async() => await fetch(`/api/blocks/${ router.query.id }`), async() => await fetch(`/api/blocks/${ router.query.id }`),
{ {
enabled: Boolean(router.query.id), enabled: Boolean(router.query.id),
...@@ -122,12 +123,12 @@ const BlockDetails = () => { ...@@ -122,12 +123,12 @@ const BlockDetails = () => {
<DetailsInfoItem <DetailsInfoItem
title="Block reward" title="Block reward"
hint={ hint={
`For each block, the miner is rewarded with a finite amount of ${ appConfig.network.currency || 'native token' } `For each block, the miner is rewarded with a finite amount of ${ appConfig.network.currency.symbol || 'native token' }
on top of the fees paid for all transactions in the block.` on top of the fees paid for all transactions in the block.`
} }
columnGap={ 1 } columnGap={ 1 }
> >
<Text>{ totalReward.dividedBy(WEI).toFixed() } { appConfig.network.currency }</Text> <Text>{ totalReward.dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }</Text>
{ (!txFees.isEqualTo(ZERO) || !burntFees.isEqualTo(ZERO)) && ( { (!txFees.isEqualTo(ZERO) || !burntFees.isEqualTo(ZERO)) && (
<Text variant="secondary" whiteSpace="break-spaces">( <Text variant="secondary" whiteSpace="break-spaces">(
<Tooltip label="Static block reward"> <Tooltip label="Static block reward">
...@@ -161,7 +162,7 @@ const BlockDetails = () => { ...@@ -161,7 +162,7 @@ const BlockDetails = () => {
title={ type } title={ type }
hint="Amount of distributed reward. Miners receive a static block reward + Tx fees + uncle fees." hint="Amount of distributed reward. Miners receive a static block reward + Tx fees + uncle fees."
> >
{ BigNumber(reward).dividedBy(WEI).toFixed() } { appConfig.network.currency } { BigNumber(reward).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
</DetailsInfoItem> </DetailsInfoItem>
)) ))
} }
...@@ -192,7 +193,7 @@ const BlockDetails = () => { ...@@ -192,7 +193,7 @@ const BlockDetails = () => {
title="Base fee per gas" title="Base fee per gas"
hint="Minimum fee required per unit of gas. Fee adjusts based on network congestion." hint="Minimum fee required per unit of gas. Fee adjusts based on network congestion."
> >
<Text>{ BigNumber(data.base_fee_per_gas).dividedBy(WEI).toFixed() } { appConfig.network.currency } </Text> <Text>{ BigNumber(data.base_fee_per_gas).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } </Text>
<Text variant="secondary" whiteSpace="pre"> <Text variant="secondary" whiteSpace="pre">
{ space }({ BigNumber(data.base_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } Gwei) { space }({ BigNumber(data.base_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } Gwei)
</Text> </Text>
...@@ -201,13 +202,13 @@ const BlockDetails = () => { ...@@ -201,13 +202,13 @@ const BlockDetails = () => {
<DetailsInfoItem <DetailsInfoItem
title="Burnt fees" title="Burnt fees"
hint={ hint={
`Amount of ${ appConfig.network.currency || 'native token' } burned from transactions included in the block. `Amount of ${ appConfig.network.currency.symbol || 'native token' } burned from transactions included in the block.
Equals Block Base Fee per Gas * Gas Used.` Equals Block Base Fee per Gas * Gas Used.`
} }
> >
<Icon as={ flameIcon } boxSize={ 5 } color="gray.500"/> <Icon as={ flameIcon } boxSize={ 5 } color="gray.500"/>
<Text ml={ 1 }>{ burntFees.dividedBy(WEI).toFixed() } { appConfig.network.currency }</Text> <Text ml={ 1 }>{ burntFees.dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }</Text>
{ !txFees.isEqualTo(ZERO) && ( { !txFees.isEqualTo(ZERO) && (
<Tooltip label="Burnt fees / Txn fees * 100%"> <Tooltip label="Burnt fees / Txn fees * 100%">
<Box> <Box>
...@@ -224,7 +225,7 @@ const BlockDetails = () => { ...@@ -224,7 +225,7 @@ const BlockDetails = () => {
title="Priority fee / Tip" title="Priority fee / Tip"
hint="User-defined tips sent to validator for transaction priority/inclusion." hint="User-defined tips sent to validator for transaction priority/inclusion."
> >
{ BigNumber(data.priority_fee).dividedBy(WEI).toFixed() } { appConfig.network.currency } { BigNumber(data.priority_fee).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
{ /* api doesn't support extra data yet */ } { /* api doesn't support extra data yet */ }
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { BlockType, BlocksResponse } from 'types/api/block'; import type { BlockType, BlocksResponse } from 'types/api/block';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import BlocksList from 'ui/blocks/BlocksList'; import BlocksList from 'ui/blocks/BlocksList';
...@@ -20,7 +21,7 @@ const BlocksContent = ({ type }: Props) => { ...@@ -20,7 +21,7 @@ const BlocksContent = ({ type }: Props) => {
const fetch = useFetch(); const fetch = useFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, BlocksResponse>( const { data, isLoading, isError } = useQuery<unknown, unknown, BlocksResponse>(
[ 'blocks', type ], [ QueryKeys.blocks, type ],
async() => await fetch(`/api/blocks${ type ? `?type=${ type }` : '' }`), async() => await fetch(`/api/blocks${ type ? `?type=${ type }` : '' }`),
); );
......
...@@ -38,7 +38,7 @@ const BlocksListItem = ({ data, isPending }: Props) => { ...@@ -38,7 +38,7 @@ const BlocksListItem = ({ data, isPending }: Props) => {
{ data.height } { data.height }
</Link> </Link>
</Flex> </Flex>
<Text variant="secondary"fontWeight={ 400 }>{ dayjs(data.timestamp).fromNow() }</Text> <Text variant="secondary" fontWeight={ 400 }>{ dayjs(data.timestamp).fromNow() }</Text>
</Flex> </Flex>
<Flex columnGap={ 2 }> <Flex columnGap={ 2 }>
<Text fontWeight={ 500 }>Size</Text> <Text fontWeight={ 500 }>Size</Text>
...@@ -61,7 +61,7 @@ const BlocksListItem = ({ data, isPending }: Props) => { ...@@ -61,7 +61,7 @@ const BlocksListItem = ({ data, isPending }: Props) => {
</Flex> </Flex>
</Box> </Box>
<Flex columnGap={ 2 }> <Flex columnGap={ 2 }>
<Text fontWeight={ 500 }>Reward { appConfig.network.currency }</Text> <Text fontWeight={ 500 }>Reward { appConfig.network.currency.symbol }</Text>
<Text variant="secondary">{ totalReward.div(WEI).toFixed() }</Text> <Text variant="secondary">{ totalReward.div(WEI).toFixed() }</Text>
</Flex> </Flex>
<Flex> <Flex>
......
...@@ -22,8 +22,8 @@ const BlocksTable = ({ data }: Props) => { ...@@ -22,8 +22,8 @@ const BlocksTable = ({ data }: Props) => {
<Th width="21%" minW="144px">Miner</Th> <Th width="21%" minW="144px">Miner</Th>
<Th width="64px" isNumeric>Txn</Th> <Th width="64px" isNumeric>Txn</Th>
<Th width="35%">Gas used</Th> <Th width="35%">Gas used</Th>
<Th width="22%">Reward { appConfig.network.currency }</Th> <Th width="22%">Reward { appConfig.network.currency.symbol }</Th>
<Th width="22%">Burnt fees { appConfig.network.currency }</Th> <Th width="22%">Burnt fees { appConfig.network.currency.symbol }</Th>
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
......
...@@ -13,6 +13,7 @@ import type { ControllerRenderProps, SubmitHandler } from 'react-hook-form'; ...@@ -13,6 +13,7 @@ import type { ControllerRenderProps, SubmitHandler } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import type { CustomAbi, CustomAbis, CustomAbiErrors } from 'types/api/account'; import type { CustomAbi, CustomAbis, CustomAbiErrors } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import getPlaceholderWithError from 'lib/getPlaceholderWithError'; import getPlaceholderWithError from 'lib/getPlaceholderWithError';
...@@ -63,7 +64,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -63,7 +64,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
const mutation = useMutation(customAbiKey, { const mutation = useMutation(customAbiKey, {
onSuccess: (data) => { onSuccess: (data) => {
const response = data as unknown as CustomAbi; const response = data as unknown as CustomAbi;
queryClient.setQueryData([ 'custom-abis' ], (prevData: CustomAbis | undefined) => { queryClient.setQueryData([ QueryKeys.customAbis ], (prevData: CustomAbis | undefined) => {
const isExisting = prevData && prevData.some((item) => item.id === response.id); const isExisting = prevData && prevData.some((item) => item.id === response.id);
if (isExisting) { if (isExisting) {
......
...@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { CustomAbi, CustomAbis } from 'types/api/account'; import type { CustomAbi, CustomAbis } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import DeleteModal from 'ui/shared/DeleteModal'; import DeleteModal from 'ui/shared/DeleteModal';
...@@ -21,7 +22,7 @@ const DeleteCustomAbiModal: React.FC<Props> = ({ isOpen, onClose, data }) => { ...@@ -21,7 +22,7 @@ const DeleteCustomAbiModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
}, [ data ]); }, [ data ]);
const onSuccess = useCallback(async() => { const onSuccess = useCallback(async() => {
queryClient.setQueryData([ 'custom-abis' ], (prevData: CustomAbis | undefined) => { queryClient.setQueryData([ QueryKeys.customAbis ], (prevData: CustomAbis | undefined) => {
return prevData?.filter((item) => item.id !== data.id); return prevData?.filter((item) => item.id !== data.id);
}); });
}, [ data, queryClient ]); }, [ data, queryClient ]);
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { ApiKey, ApiKeys } from 'types/api/account'; import type { ApiKey, ApiKeys } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -30,7 +31,7 @@ const ApiKeysPage: React.FC = () => { ...@@ -30,7 +31,7 @@ const ApiKeysPage: React.FC = () => {
const [ apiKeyModalData, setApiKeyModalData ] = useState<ApiKey>(); const [ apiKeyModalData, setApiKeyModalData ] = useState<ApiKey>();
const [ deleteModalData, setDeleteModalData ] = useState<ApiKey>(); const [ deleteModalData, setDeleteModalData ] = useState<ApiKey>();
const { data, isLoading, isError } = useQuery<unknown, unknown, ApiKeys>([ 'api-keys' ], async() => await fetch('/api/account/api-keys')); const { data, isLoading, isError } = useQuery<unknown, unknown, ApiKeys>([ QueryKeys.apiKeys ], async() => await fetch('/api/account/api-keys'));
const onEditClick = useCallback((data: ApiKey) => { const onEditClick = useCallback((data: ApiKey) => {
setApiKeyModalData(data); setApiKeyModalData(data);
......
import { Box, Icon, Link } from '@chakra-ui/react'; import { Box, Icon, Link } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { JsonRpcUrlResponse } from 'types/api/json-rpc-url';
import config from 'configs/app/config'; import config from 'configs/app/config';
import PlusIcon from 'icons/plus.svg'; import PlusIcon from 'icons/plus.svg';
import useFetch from 'lib/hooks/useFetch';
import AppList from 'ui/apps/AppList'; import AppList from 'ui/apps/AppList';
import AppListSkeleton from 'ui/apps/AppListSkeleton'; import AppListSkeleton from 'ui/apps/AppListSkeleton';
import CategoriesMenu from 'ui/apps/CategoriesMenu'; import CategoriesMenu from 'ui/apps/CategoriesMenu';
...@@ -11,6 +15,8 @@ import FilterInput from 'ui/shared/FilterInput'; ...@@ -11,6 +15,8 @@ import FilterInput from 'ui/shared/FilterInput';
import useMarketplaceApps from '../apps/useMarkeplaceApps'; import useMarketplaceApps from '../apps/useMarkeplaceApps';
const Apps = () => { const Apps = () => {
const fetch = useFetch();
const { const {
isLoading, isLoading,
category, category,
...@@ -24,6 +30,11 @@ const Apps = () => { ...@@ -24,6 +30,11 @@ const Apps = () => {
handleFavoriteClick, handleFavoriteClick,
} = useMarketplaceApps(); } = useMarketplaceApps();
useQuery<unknown, unknown, JsonRpcUrlResponse>(
[ 'json-rpc-url' ],
async() => await fetch(`/api/config/json-rpc-url`),
);
return ( return (
<> <>
<Box <Box
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { CustomAbi, CustomAbis } from 'types/api/account'; import type { CustomAbi, CustomAbis } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -27,7 +28,7 @@ const CustomAbiPage: React.FC = () => { ...@@ -27,7 +28,7 @@ const CustomAbiPage: React.FC = () => {
const [ customAbiModalData, setCustomAbiModalData ] = useState<CustomAbi>(); const [ customAbiModalData, setCustomAbiModalData ] = useState<CustomAbi>();
const [ deleteModalData, setDeleteModalData ] = useState<CustomAbi>(); const [ deleteModalData, setDeleteModalData ] = useState<CustomAbi>();
const { data, isLoading, isError } = useQuery<unknown, unknown, CustomAbis>([ 'custom-abis' ], async() => await fetch('/api/account/custom-abis')); const { data, isLoading, isError } = useQuery<unknown, unknown, CustomAbis>([ QueryKeys.customAbis ], async() => await fetch('/api/account/custom-abis'));
const onEditClick = useCallback((data: CustomAbi) => { const onEditClick = useCallback((data: CustomAbi) => {
setCustomAbiModalData(data); setCustomAbiModalData(data);
......
import { Box, Center, useColorMode } from '@chakra-ui/react'; import { Box, Center, useColorMode } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import type { JsonRpcUrlResponse } from 'types/api/json-rpc-url';
import type { AppItemOverview } from 'types/client/apps'; import type { AppItemOverview } from 'types/client/apps';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import useFetch from 'lib/hooks/useFetch';
import link from 'lib/link/link'; import link from 'lib/link/link';
import ContentLoader from 'ui/shared/ContentLoader'; import ContentLoader from 'ui/shared/ContentLoader';
import Page from 'ui/shared/Page/Page'; import Page from 'ui/shared/Page/Page';
...@@ -15,30 +18,43 @@ type Props = { ...@@ -15,30 +18,43 @@ type Props = {
const MarketplaceApp = ({ app, isLoading }: Props) => { const MarketplaceApp = ({ app, isLoading }: Props) => {
const [ isFrameLoading, setIsFrameLoading ] = useState(isLoading); const [ isFrameLoading, setIsFrameLoading ] = useState(isLoading);
const ref = useRef<HTMLIFrameElement>(null);
const { colorMode } = useColorMode(); const { colorMode } = useColorMode();
const fetch = useFetch();
const ref = useRef<HTMLIFrameElement>(null);
const handleIframeLoad = useCallback(() => { const handleIframeLoad = useCallback(() => {
setIsFrameLoading(false); setIsFrameLoading(false);
}, []); }, []);
const sandboxAttributeValue = 'allow-forms allow-orientation-lock ' + const { data: jsonRpcUrlResponse } = useQuery<unknown, unknown, JsonRpcUrlResponse>(
'allow-pointer-lock allow-popups-to-escape-sandbox ' + [ 'json-rpc-url' ],
'allow-same-origin allow-scripts ' + async() => await fetch(`/api/config/json-rpc-url`),
'allow-top-navigation-by-user-activation allow-popups'; { refetchOnMount: false },
);
const allowAttributeValue = 'clipboard-read; clipboard-write;';
useEffect(() => { useEffect(() => {
if (app && !isFrameLoading) { if (app && !isFrameLoading) {
ref?.current?.contentWindow?.postMessage({ const message = {
blockscoutColorMode: colorMode, blockscoutColorMode: colorMode,
blockscoutChainId: Number(appConfig.network.id), blockscoutRootUrl: link('network_index'),
blockscoutAddressExplorerUrl: link('address_index'), blockscoutAddressExplorerUrl: link('address_index'),
blockscoutTransactionExplorerUrl: link('tx'), blockscoutTransactionExplorerUrl: link('tx'),
}, app.url); blockscoutNetworkName: appConfig.network.name,
blockscoutNetworkId: Number(appConfig.network.id),
blockscoutNetworkCurrency: appConfig.network.currency,
blockscoutNetworkRpc: jsonRpcUrlResponse?.json_rpc_url,
};
ref?.current?.contentWindow?.postMessage(message, app.url);
} }
}, [ isFrameLoading, app, colorMode, ref ]); }, [ isFrameLoading, app, colorMode, ref, jsonRpcUrlResponse ]);
const sandboxAttributeValue = 'allow-forms allow-orientation-lock ' +
'allow-pointer-lock allow-popups-to-escape-sandbox ' +
'allow-same-origin allow-scripts ' +
'allow-top-navigation-by-user-activation allow-popups';
const allowAttributeValue = 'clipboard-read; clipboard-write;';
return ( return (
<Page wrapChildren={ false }> <Page wrapChildren={ false }>
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { TWatchlist, TWatchlistItem } from 'types/client/account'; import type { TWatchlist, TWatchlistItem } from 'types/client/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -19,7 +20,7 @@ import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable'; ...@@ -19,7 +20,7 @@ import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable';
const WatchList: React.FC = () => { const WatchList: React.FC = () => {
const { data, isLoading, isError } = const { data, isLoading, isError } =
useQuery<unknown, unknown, TWatchlist>([ 'watchlist' ], async() => fetch('/api/account/watchlist/get-with-tokens')); useQuery<unknown, unknown, TWatchlist>([ QueryKeys.watchlist ], async() => fetch('/api/account/watchlist/get-with-tokens'));
const addressModalProps = useDisclosure(); const addressModalProps = useDisclosure();
const deleteModalProps = useDisclosure(); const deleteModalProps = useDisclosure();
......
...@@ -9,6 +9,7 @@ import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form'; ...@@ -9,6 +9,7 @@ import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import type { AddressTag, AddressTagErrors } from 'types/api/account'; import type { AddressTag, AddressTagErrors } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import type { ErrorType } from 'lib/hooks/useFetch'; import type { ErrorType } from 'lib/hooks/useFetch';
...@@ -70,7 +71,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -70,7 +71,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
} }
}, },
onSuccess: () => { onSuccess: () => {
queryClient.refetchQueries([ 'address-tags' ]).then(() => { queryClient.refetchQueries([ QueryKeys.addressTags ]).then(() => {
onClose(); onClose();
setPending(false); setPending(false);
}); });
......
...@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { AddressTag, TransactionTag, AddressTags, TransactionTags } from 'types/api/account'; import type { AddressTag, TransactionTag, AddressTags, TransactionTags } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import DeleteModal from 'ui/shared/DeleteModal'; import DeleteModal from 'ui/shared/DeleteModal';
...@@ -27,11 +28,11 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type }) ...@@ -27,11 +28,11 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type })
const onSuccess = useCallback(async() => { const onSuccess = useCallback(async() => {
if (type === 'address') { if (type === 'address') {
queryClient.setQueryData([ 'address-tags' ], (prevData: AddressTags | undefined) => { queryClient.setQueryData([ QueryKeys.addressTags ], (prevData: AddressTags | undefined) => {
return prevData?.filter((item: AddressTag) => item.id !== id); return prevData?.filter((item: AddressTag) => item.id !== id);
}); });
} else { } else {
queryClient.setQueryData([ 'transaction-tags' ], (prevData: TransactionTags | undefined) => { queryClient.setQueryData([ QueryKeys.transactionTags ], (prevData: TransactionTags | undefined) => {
return prevData?.filter((item: TransactionTag) => item.id !== id); return prevData?.filter((item: TransactionTag) => item.id !== id);
}); });
} }
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { AddressTags, AddressTag } from 'types/api/account'; import type { AddressTags, AddressTag } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -18,7 +19,7 @@ import DeletePrivateTagModal from './DeletePrivateTagModal'; ...@@ -18,7 +19,7 @@ import DeletePrivateTagModal from './DeletePrivateTagModal';
const PrivateAddressTags = () => { const PrivateAddressTags = () => {
const { data: addressTagsData, isLoading, isError } = const { data: addressTagsData, isLoading, isError } =
useQuery<unknown, unknown, AddressTags>([ 'address-tags' ], async() => fetch('/api/account/private-tags/address'), { refetchOnMount: false }); useQuery<unknown, unknown, AddressTags>([ QueryKeys.addressTags ], async() => fetch('/api/account/private-tags/address'), { refetchOnMount: false });
const addressModalProps = useDisclosure(); const addressModalProps = useDisclosure();
const deleteModalProps = useDisclosure(); const deleteModalProps = useDisclosure();
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { TransactionTags, TransactionTag } from 'types/api/account'; import type { TransactionTags, TransactionTag } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -18,7 +19,10 @@ import TransactionTagTable from './TransactionTagTable/TransactionTagTable'; ...@@ -18,7 +19,10 @@ import TransactionTagTable from './TransactionTagTable/TransactionTagTable';
const PrivateTransactionTags = () => { const PrivateTransactionTags = () => {
const { data: transactionTagsData, isLoading, isError } = const { data: transactionTagsData, isLoading, isError } =
useQuery<unknown, unknown, TransactionTags>([ 'transaction-tags' ], async() => fetch('/api/account/private-tags/transaction'), { refetchOnMount: false }); useQuery<unknown, unknown, TransactionTags>(
[ QueryKeys.transactionTags ],
async() => fetch('/api/account/private-tags/transaction'), { refetchOnMount: false },
);
const transactionModalProps = useDisclosure(); const transactionModalProps = useDisclosure();
const deleteModalProps = useDisclosure(); const deleteModalProps = useDisclosure();
......
...@@ -9,6 +9,7 @@ import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form'; ...@@ -9,6 +9,7 @@ import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import type { TransactionTag, TransactionTagErrors } from 'types/api/account'; import type { TransactionTag, TransactionTagErrors } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import type { ErrorType } from 'lib/hooks/useFetch'; import type { ErrorType } from 'lib/hooks/useFetch';
...@@ -70,7 +71,7 @@ const TransactionForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => ...@@ -70,7 +71,7 @@ const TransactionForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) =>
} }
}, },
onSuccess: () => { onSuccess: () => {
queryClient.refetchQueries([ 'transaction-tags' ]).then(() => { queryClient.refetchQueries([ QueryKeys.transactionTags ]).then(() => {
onClose(); onClose();
setPending(false); setPending(false);
}); });
......
...@@ -4,6 +4,7 @@ import React, { useCallback, useState } from 'react'; ...@@ -4,6 +4,7 @@ import React, { useCallback, useState } from 'react';
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
import type { PublicTags, PublicTag } from 'types/api/account'; import type { PublicTags, PublicTag } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import DeleteModal from 'ui/shared/DeleteModal'; import DeleteModal from 'ui/shared/DeleteModal';
...@@ -32,7 +33,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete ...@@ -32,7 +33,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
const onSuccess = useCallback(async() => { const onSuccess = useCallback(async() => {
onDeleteSuccess(); onDeleteSuccess();
queryClient.setQueryData([ 'public-tags' ], (prevData: PublicTags | undefined) => { queryClient.setQueryData([ QueryKeys.publicTags ], (prevData: PublicTags | undefined) => {
return prevData?.filter((item) => item.id !== data.id); return prevData?.filter((item) => item.id !== data.id);
}); });
}, [ queryClient, data, onDeleteSuccess ]); }, [ queryClient, data, onDeleteSuccess ]);
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { PublicTags, PublicTag } from 'types/api/account'; import type { PublicTags, PublicTag } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -26,7 +27,7 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => { ...@@ -26,7 +27,7 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const fetch = useFetch(); const fetch = useFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, PublicTags>([ 'public-tags' ], async() => await fetch('/api/account/public-tags')); const { data, isLoading, isError } = useQuery<unknown, unknown, PublicTags>([ QueryKeys.publicTags ], async() => await fetch('/api/account/public-tags'));
const onDeleteModalClose = useCallback(() => { const onDeleteModalClose = useCallback(() => {
setDeleteModalData(undefined); setDeleteModalData(undefined);
......
...@@ -12,6 +12,7 @@ import type { FieldError, Path, SubmitHandler } from 'react-hook-form'; ...@@ -12,6 +12,7 @@ import type { FieldError, Path, SubmitHandler } from 'react-hook-form';
import { useForm, useFieldArray } from 'react-hook-form'; import { useForm, useFieldArray } from 'react-hook-form';
import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types/api/account'; import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import type { ErrorType } from 'lib/hooks/useFetch'; import type { ErrorType } from 'lib/hooks/useFetch';
...@@ -108,7 +109,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => { ...@@ -108,7 +109,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
onSuccess: async(data) => { onSuccess: async(data) => {
const response = data as unknown as PublicTag; const response = data as unknown as PublicTag;
queryClient.setQueryData([ 'public-tags' ], (prevData: PublicTags | undefined) => { queryClient.setQueryData([ QueryKeys.publicTags ], (prevData: PublicTags | undefined) => {
const isExisting = prevData && prevData.some((item) => item.id === response.id); const isExisting = prevData && prevData.some((item) => item.id === response.id);
if (isExisting) { if (isExisting) {
......
...@@ -2,6 +2,8 @@ import { Flex } from '@chakra-ui/react'; ...@@ -2,6 +2,8 @@ import { Flex } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import PageContent from 'ui/shared/Page/PageContent'; import PageContent from 'ui/shared/Page/PageContent';
import Header from 'ui/snippets/header/Header'; import Header from 'ui/snippets/header/Header';
...@@ -15,7 +17,7 @@ interface Props { ...@@ -15,7 +17,7 @@ interface Props {
const Page = ({ children, wrapChildren = true }: Props) => { const Page = ({ children, wrapChildren = true }: Props) => {
const fetch = useFetch(); const fetch = useFetch();
useQuery<unknown, unknown, unknown>([ 'csrf' ], async() => await fetch('/api/account/csrf')); useQuery<unknown, unknown, unknown>([ QueryKeys.csrf ], async() => await fetch('/api/account/csrf'));
const renderedChildren = wrapChildren ? ( const renderedChildren = wrapChildren ? (
<PageContent>{ children }</PageContent> <PageContent>{ children }</PageContent>
......
...@@ -6,6 +6,7 @@ import React from 'react'; ...@@ -6,6 +6,7 @@ import React from 'react';
import { scroller, Element } from 'react-scroll'; import { scroller, Element } from 'react-scroll';
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import clockIcon from 'icons/clock.svg'; import clockIcon from 'icons/clock.svg';
...@@ -47,7 +48,7 @@ const TxDetails = () => { ...@@ -47,7 +48,7 @@ const TxDetails = () => {
const fetch = useFetch(); const fetch = useFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, Transaction>( const { data, isLoading, isError } = useQuery<unknown, unknown, Transaction>(
[ 'tx', router.query.id ], [ QueryKeys.tx, router.query.id ],
async() => await fetch(`/api/transactions/${ router.query.id }`), async() => await fetch(`/api/transactions/${ router.query.id }`),
{ {
enabled: Boolean(router.query.id), enabled: Boolean(router.query.id),
...@@ -211,7 +212,7 @@ const TxDetails = () => { ...@@ -211,7 +212,7 @@ const TxDetails = () => {
title="Value" title="Value"
hint="Value sent in the native token (and USD) if applicable." hint="Value sent in the native token (and USD) if applicable."
> >
<CurrencyValue value={ data.value } currency={ appConfig.network.currency } exchangeRate={ data.exchange_rate }/> <CurrencyValue value={ data.value } currency={ appConfig.network.currency.symbol } exchangeRate={ data.exchange_rate }/>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Transaction fee" title="Transaction fee"
...@@ -219,7 +220,7 @@ const TxDetails = () => { ...@@ -219,7 +220,7 @@ const TxDetails = () => {
> >
<CurrencyValue <CurrencyValue
value={ data.fee.value } value={ data.fee.value }
currency={ appConfig.network.currency } currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate } exchangeRate={ data.exchange_rate }
flexWrap="wrap" flexWrap="wrap"
/> />
...@@ -228,7 +229,7 @@ const TxDetails = () => { ...@@ -228,7 +229,7 @@ const TxDetails = () => {
title="Gas price" title="Gas price"
hint="Price per unit of gas specified by the sender. Higher gas prices can prioritize transaction inclusion during times of high usage." hint="Price per unit of gas specified by the sender. Higher gas prices can prioritize transaction inclusion during times of high usage."
> >
<Text mr={ 1 }>{ BigNumber(data.gas_price).dividedBy(WEI).toFixed() } { appConfig.network.currency }</Text> <Text mr={ 1 }>{ BigNumber(data.gas_price).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }</Text>
<Text variant="secondary">({ BigNumber(data.gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei)</Text> <Text variant="secondary">({ BigNumber(data.gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei)</Text>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
...@@ -271,12 +272,12 @@ const TxDetails = () => { ...@@ -271,12 +272,12 @@ const TxDetails = () => {
{ data.tx_burnt_fee && ( { data.tx_burnt_fee && (
<DetailsInfoItem <DetailsInfoItem
title="Burnt fees" title="Burnt fees"
hint={ `Amount of ${ appConfig.network.currency } burned for this transaction. Equals Block Base Fee per Gas * Gas Used.` } hint={ `Amount of ${ appConfig.network.currency.symbol } burned for this transaction. Equals Block Base Fee per Gas * Gas Used.` }
> >
<Icon as={ flameIcon } mr={ 1 } boxSize={ 5 } color="gray.500"/> <Icon as={ flameIcon } mr={ 1 } boxSize={ 5 } color="gray.500"/>
<CurrencyValue <CurrencyValue
value={ String(data.tx_burnt_fee) } value={ String(data.tx_burnt_fee) }
currency={ appConfig.network.currency } currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate } exchangeRate={ data.exchange_rate }
flexWrap="wrap" flexWrap="wrap"
/> />
......
...@@ -4,6 +4,7 @@ import { useRouter } from 'next/router'; ...@@ -4,6 +4,7 @@ import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { InternalTransactionsResponse, TxInternalsType, InternalTransaction } from 'types/api/internalTransaction'; import type { InternalTransactionsResponse, TxInternalsType, InternalTransaction } from 'types/api/internalTransaction';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -72,7 +73,7 @@ const TxInternals = () => { ...@@ -72,7 +73,7 @@ const TxInternals = () => {
const [ searchTerm, setSearchTerm ] = React.useState<string>(''); const [ searchTerm, setSearchTerm ] = React.useState<string>('');
const [ sort, setSort ] = React.useState<Sort>(); const [ sort, setSort ] = React.useState<Sort>();
const { data, isLoading, isError } = useQuery<unknown, unknown, InternalTransactionsResponse>( const { data, isLoading, isError } = useQuery<unknown, unknown, InternalTransactionsResponse>(
[ 'tx-internals', router.query.id ], [ QueryKeys.txInternals, router.query.id ],
async() => await fetch(`/api/transactions/${ router.query.id }/internal-transactions`), async() => await fetch(`/api/transactions/${ router.query.id }/internal-transactions`),
{ {
enabled: Boolean(router.query.id), enabled: Boolean(router.query.id),
......
...@@ -4,6 +4,7 @@ import { useRouter } from 'next/router'; ...@@ -4,6 +4,7 @@ import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { LogsResponse } from 'types/api/log'; import type { LogsResponse } from 'types/api/log';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
...@@ -15,7 +16,7 @@ const TxLogs = () => { ...@@ -15,7 +16,7 @@ const TxLogs = () => {
const fetch = useFetch(); const fetch = useFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, LogsResponse>( const { data, isLoading, isError } = useQuery<unknown, unknown, LogsResponse>(
[ 'tx-log', router.query.id ], [ QueryKeys.txLog, router.query.id ],
async() => await fetch(`/api/transactions/${ router.query.id }/logs`), async() => await fetch(`/api/transactions/${ router.query.id }/logs`),
{ {
enabled: Boolean(router.query.id), enabled: Boolean(router.query.id),
......
...@@ -4,6 +4,7 @@ import { useRouter } from 'next/router'; ...@@ -4,6 +4,7 @@ import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { RawTracesResponse } from 'types/api/rawTrace'; import type { RawTracesResponse } from 'types/api/rawTrace';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
...@@ -14,7 +15,7 @@ const TxRawTrace = () => { ...@@ -14,7 +15,7 @@ const TxRawTrace = () => {
const fetch = useFetch(); const fetch = useFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, RawTracesResponse>( const { data, isLoading, isError } = useQuery<unknown, unknown, RawTracesResponse>(
[ 'tx-raw-trace', router.query.id ], [ QueryKeys.txRawTrace, router.query.id ],
async() => await fetch(`/api/transactions/${ router.query.id }/raw-trace`), async() => await fetch(`/api/transactions/${ router.query.id }/raw-trace`),
{ {
enabled: Boolean(router.query.id), enabled: Boolean(router.query.id),
......
...@@ -36,7 +36,7 @@ const TxInternalsListItem = ({ type, from, to, value, success, error, gas_limit: ...@@ -36,7 +36,7 @@ const TxInternalsListItem = ({ type, from, to, value, success, error, gas_limit:
</Address> </Address>
</Box> </Box>
<HStack spacing={ 3 }> <HStack spacing={ 3 }>
<Text fontSize="sm" fontWeight={ 500 }>Value { appConfig.network.currency }</Text> <Text fontSize="sm" fontWeight={ 500 }>Value { appConfig.network.currency.symbol }</Text>
<Text fontSize="sm" variant="secondary">{ value }</Text> <Text fontSize="sm" variant="secondary">{ value }</Text>
</HStack> </HStack>
<HStack spacing={ 3 }> <HStack spacing={ 3 }>
......
...@@ -29,7 +29,7 @@ const TxInternalsTable = ({ data, sort, onSortToggle }: Props) => { ...@@ -29,7 +29,7 @@ const TxInternalsTable = ({ data, sort, onSortToggle }: Props) => {
<Th width="16%" isNumeric> <Th width="16%" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('value') } columnGap={ 1 }> <Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('value') } columnGap={ 1 }>
{ sort?.includes('value') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> } { sort?.includes('value') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
Value { appConfig.network.currency } Value { appConfig.network.currency.symbol }
</Link> </Link>
</Th> </Th>
<Th width="16%" isNumeric> <Th width="16%" isNumeric>
......
...@@ -64,7 +64,7 @@ const TxStateListItem = ({ storage, address, miner, after, before, diff }: Props ...@@ -64,7 +64,7 @@ const TxStateListItem = ({ storage, address, miner, after, before, diff }: Props
<Link>{ miner }</Link> <Link>{ miner }</Link>
</Box> </Box>
<Box> <Box>
<Text as="span">Before { appConfig.network.currency } </Text> <Text as="span">Before { appConfig.network.currency.symbol } </Text>
<Text as="span" variant="secondary">{ before.balance }</Text> <Text as="span" variant="secondary">{ before.balance }</Text>
</Box> </Box>
{ typeof before.nonce !== 'undefined' && ( { typeof before.nonce !== 'undefined' && (
...@@ -74,7 +74,7 @@ const TxStateListItem = ({ storage, address, miner, after, before, diff }: Props ...@@ -74,7 +74,7 @@ const TxStateListItem = ({ storage, address, miner, after, before, diff }: Props
</Box> </Box>
) } ) }
<Box> <Box>
<Text as="span">After { appConfig.network.currency } </Text> <Text as="span">After { appConfig.network.currency.symbol } </Text>
<Text as="span" variant="secondary">{ after.balance }</Text> <Text as="span" variant="secondary">{ after.balance }</Text>
</Box> </Box>
{ typeof after.nonce !== 'undefined' && ( { typeof after.nonce !== 'undefined' && (
...@@ -83,7 +83,7 @@ const TxStateListItem = ({ storage, address, miner, after, before, diff }: Props ...@@ -83,7 +83,7 @@ const TxStateListItem = ({ storage, address, miner, after, before, diff }: Props
<Text as="span" fontWeight={ 600 }>{ nbsp }{ after.nonce }</Text> <Text as="span" fontWeight={ 600 }>{ nbsp }{ after.nonce }</Text>
</Box> </Box>
) } ) }
<Text>State difference { appConfig.network.currency }</Text> <Text>State difference { appConfig.network.currency.symbol }</Text>
<Stat> <Stat>
{ diff } { diff }
<StatArrow ml={ 2 } type={ Number(diff) > 0 ? 'increase' : 'decrease' }/> <StatArrow ml={ 2 } type={ Number(diff) > 0 ? 'increase' : 'decrease' }/>
......
...@@ -21,9 +21,9 @@ const TxStateTable = () => { ...@@ -21,9 +21,9 @@ const TxStateTable = () => {
<Th width="92px">Storage</Th> <Th width="92px">Storage</Th>
<Th width="146px">Address</Th> <Th width="146px">Address</Th>
<Th width="120px">Miner</Th> <Th width="120px">Miner</Th>
<Th width="33%" isNumeric>{ `After ${ appConfig.network.currency }` }</Th> <Th width="33%" isNumeric>{ `After ${ appConfig.network.currency.symbol }` }</Th>
<Th width="33%" isNumeric>{ `Before ${ appConfig.network.currency }` }</Th> <Th width="33%" isNumeric>{ `Before ${ appConfig.network.currency.symbol }` }</Th>
<Th width="33%" isNumeric>{ `State difference ${ appConfig.network.currency }` }</Th> <Th width="33%" isNumeric>{ `State difference ${ appConfig.network.currency.symbol }` }</Th>
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
......
...@@ -34,7 +34,7 @@ const TxAdditionalInfo = ({ tx }: { tx: Transaction }) => { ...@@ -34,7 +34,7 @@ const TxAdditionalInfo = ({ tx }: { tx: Transaction }) => {
<Flex> <Flex>
<CurrencyValue <CurrencyValue
value={ tx.fee.value } value={ tx.fee.value }
currency={ appConfig.network.currency } currency={ appConfig.network.currency.symbol }
exchangeRate={ tx.exchange_rate } exchangeRate={ tx.exchange_rate }
accuracyUsd={ 2 } accuracyUsd={ 2 }
/> />
......
...@@ -113,11 +113,11 @@ const TxsListItem = ({ tx }: {tx: Transaction}) => { ...@@ -113,11 +113,11 @@ const TxsListItem = ({ tx }: {tx: Transaction}) => {
</Address> </Address>
</Flex> </Flex>
<Box mt={ 2 }> <Box mt={ 2 }>
<Text as="span">Value { appConfig.network.currency } </Text> <Text as="span">Value { appConfig.network.currency.symbol } </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.value).toFormat() }</Text> <Text as="span" variant="secondary">{ getValueWithUnit(tx.value).toFormat() }</Text>
</Box> </Box>
<Box mt={ 2 } mb={ 3 }> <Box mt={ 2 } mb={ 3 }>
<Text as="span">Fee { appConfig.network.currency } </Text> <Text as="span">Fee { appConfig.network.currency.symbol } </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).toFormat() }</Text> <Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).toFormat() }</Text>
</Box> </Box>
</Box> </Box>
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { TransactionsResponse } from 'types/api/transaction'; import type { TransactionsResponse } from 'types/api/transaction';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
...@@ -14,7 +15,7 @@ import TxsSkeletonMobile from './TxsSkeletonMobile'; ...@@ -14,7 +15,7 @@ import TxsSkeletonMobile from './TxsSkeletonMobile';
const TxsValidated = () => { const TxsValidated = () => {
const fetch = useFetch(); const fetch = useFetch();
const { data, isLoading, isError } = const { data, isLoading, isError } =
useQuery<unknown, unknown, TransactionsResponse>([ 'transactions_pending' ], async() => fetch('/api/transactions/?filter=pending')); useQuery<unknown, unknown, TransactionsResponse>([ QueryKeys.transactionsPending ], async() => fetch('/api/transactions/?filter=pending'));
if (isError) { if (isError) {
return <DataFetchAlert/>; return <DataFetchAlert/>;
......
...@@ -33,14 +33,14 @@ const TxsTable = ({ txs, sort, sorting }: Props) => { ...@@ -33,14 +33,14 @@ const TxsTable = ({ txs, sort, sorting }: Props) => {
<Link onClick={ sort('val') } display="flex" justifyContent="end"> <Link onClick={ sort('val') } display="flex" justifyContent="end">
{ sorting === 'val-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> } { sorting === 'val-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> }
{ sorting === 'val-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> } { sorting === 'val-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> }
{ `Value ${ appConfig.network.currency }` } { `Value ${ appConfig.network.currency.symbol }` }
</Link> </Link>
</Th> </Th>
<Th width="18%" isNumeric pr={ 5 }> <Th width="18%" isNumeric pr={ 5 }>
<Link onClick={ sort('fee') } display="flex" justifyContent="end"> <Link onClick={ sort('fee') } display="flex" justifyContent="end">
{ sorting === 'fee-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> } { sorting === 'fee-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> }
{ sorting === 'fee-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> } { sorting === 'fee-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> }
{ `Fee ${ appConfig.network.currency }` } { `Fee ${ appConfig.network.currency.symbol }` }
</Link> </Link>
</Th> </Th>
</Tr> </Tr>
......
...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { TransactionsResponse } from 'types/api/transaction'; import type { TransactionsResponse } from 'types/api/transaction';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
...@@ -14,7 +15,7 @@ import TxsSkeletonMobile from './TxsSkeletonMobile'; ...@@ -14,7 +15,7 @@ import TxsSkeletonMobile from './TxsSkeletonMobile';
const TxsValidated = () => { const TxsValidated = () => {
const fetch = useFetch(); const fetch = useFetch();
const { data, isLoading, isError } = const { data, isLoading, isError } =
useQuery<unknown, unknown, TransactionsResponse>([ 'transactions_validated' ], async() => fetch('/api/transactions/?filter=validated')); useQuery<unknown, unknown, TransactionsResponse>([ QueryKeys.transactionsValidated ], async() => fetch('/api/transactions/?filter=validated'));
if (isError) { if (isError) {
return <DataFetchAlert/>; return <DataFetchAlert/>;
......
...@@ -11,6 +11,7 @@ import { useForm, Controller } from 'react-hook-form'; ...@@ -11,6 +11,7 @@ import { useForm, Controller } from 'react-hook-form';
import type { WatchlistErrors } from 'types/api/account'; import type { WatchlistErrors } from 'types/api/account';
import type { TWatchlistItem } from 'types/client/account'; import type { TWatchlistItem } from 'types/client/account';
import { QueryKeys } from 'types/client/accountQueries';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import type { ErrorType } from 'lib/hooks/useFetch'; import type { ErrorType } from 'lib/hooks/useFetch';
...@@ -106,7 +107,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -106,7 +107,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
const { mutate } = useMutation(updateWatchlist, { const { mutate } = useMutation(updateWatchlist, {
onSuccess: () => { onSuccess: () => {
queryClient.refetchQueries([ 'watchlist' ]).then(() => { queryClient.refetchQueries([ QueryKeys.watchlist ]).then(() => {
onClose(); onClose();
setPending(false); setPending(false);
}); });
......
...@@ -8,7 +8,7 @@ import CheckboxInput from 'ui/shared/CheckboxInput'; ...@@ -8,7 +8,7 @@ import CheckboxInput from 'ui/shared/CheckboxInput';
// does it depend on the network? // does it depend on the network?
const NOTIFICATIONS = [ 'native', 'ERC-20', 'ERC-721' ] as const; const NOTIFICATIONS = [ 'native', 'ERC-20', 'ERC-721' ] as const;
const NOTIFICATIONS_NAMES = [ appConfig.network.currency, 'ERC-20', 'ERC-721, ERC-1155 (NFT)' ]; const NOTIFICATIONS_NAMES = [ appConfig.network.currency.symbol, 'ERC-20', 'ERC-721, ERC-1155 (NFT)' ];
type Props<Inputs extends FieldValues> = { type Props<Inputs extends FieldValues> = {
control: Control<Inputs>; control: Control<Inputs>;
......
...@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query'; ...@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { TWatchlistItem, TWatchlist } from 'types/client/account'; import type { TWatchlistItem, TWatchlist } from 'types/client/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -24,7 +25,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => { ...@@ -24,7 +25,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
}, [ data?.id, fetch ]); }, [ data?.id, fetch ]);
const onSuccess = useCallback(async() => { const onSuccess = useCallback(async() => {
queryClient.setQueryData([ 'watchlist' ], (prevData: TWatchlist | undefined) => { queryClient.setQueryData([ QueryKeys.watchlist ], (prevData: TWatchlist | undefined) => {
return prevData?.filter((item) => item.id !== data.id); return prevData?.filter((item) => item.id !== data.id);
}); });
}, [ data, queryClient ]); }, [ data, queryClient ]);
......
...@@ -25,7 +25,7 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => { ...@@ -25,7 +25,7 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
<HStack spacing={ 0 } fontSize="sm" h={ 6 } pl={ infoItemsPaddingLeft }> <HStack spacing={ 0 } fontSize="sm" h={ 6 } pl={ infoItemsPaddingLeft }>
{ appConfig.network.nativeTokenAddress && { appConfig.network.nativeTokenAddress &&
<TokenLogo hash={ appConfig.network.nativeTokenAddress } name={ appConfig.network.name } boxSize={ 4 } mr="10px"/> } <TokenLogo hash={ appConfig.network.nativeTokenAddress } name={ appConfig.network.name } boxSize={ 4 } mr="10px"/> }
<Text color={ mainTextColor }>{ `${ appConfig.network.currency } balance:${ nbsp }` + nativeBalance }</Text> <Text color={ mainTextColor }>{ `${ appConfig.network.currency.symbol } balance:${ nbsp }` + nativeBalance }</Text>
<Text variant="secondary">{ `${ nbsp }(${ nativeBalanceUSD })` }</Text> <Text variant="secondary">{ `${ nbsp }(${ nativeBalanceUSD })` }</Text>
</HStack> </HStack>
{ item.tokens_count && ( { item.tokens_count && (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment