Commit 67311929 authored by tom's avatar tom

final part

parent bd79698a
...@@ -12,10 +12,13 @@ import type { ...@@ -12,10 +12,13 @@ import type {
AddressTokenTransferFilters, AddressTokenTransferFilters,
} from 'types/api/address'; } from 'types/api/address';
import type { BlocksResponse, BlockTransactionsResponse, Block, BlockFilters } from 'types/api/block'; import type { BlocksResponse, BlockTransactionsResponse, Block, BlockFilters } from 'types/api/block';
import type { ChartMarketResponse, ChartTransactionResponse } from 'types/api/charts';
import type { IndexingStatus } from 'types/api/indexingStatus';
import type { InternalTransactionsResponse } from 'types/api/internalTransaction'; import type { InternalTransactionsResponse } from 'types/api/internalTransaction';
import type { JsonRpcUrlResponse } from 'types/api/jsonRpcUrl';
import type { LogsResponse } from 'types/api/log'; import type { LogsResponse } from 'types/api/log';
import type { RawTracesResponse } from 'types/api/rawTrace'; import type { RawTracesResponse } from 'types/api/rawTrace';
import type { Stats, Charts } from 'types/api/stats'; import type { Stats, Charts, HomeStats } from 'types/api/stats';
import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer'; import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer';
import type { TransactionsResponseValidated, TransactionsResponsePending, Transaction } from 'types/api/transaction'; import type { TransactionsResponseValidated, TransactionsResponsePending, Transaction } from 'types/api/transaction';
import type { TTxsFilters } from 'types/api/txsFilters'; import type { TTxsFilters } from 'types/api/txsFilters';
...@@ -147,6 +150,31 @@ export const RESOURCES = { ...@@ -147,6 +150,31 @@ export const RESOURCES = {
filterFields: [ ], filterFields: [ ],
}, },
// HOMEPAGE
homepage_stats: {
path: '/api/v2/stats',
},
homepage_chart_txs: {
path: '/api/v2/stats/charts/transactions',
},
homepage_chart_market: {
path: '/api/v2/stats/charts/market',
},
homepage_blocks: {
path: '/api/v2/main-page/blocks',
},
homepage_txs: {
path: '/api/v2/main-page/transactions',
},
homepage_indexing_status: {
path: '/api/v2/main-page/indexing-status',
},
// CONFIG
config_json_rpc: {
path: '/api/v2/config/json-rpc-url',
},
// DEPRECATED // DEPRECATED
old_api: { old_api: {
path: '/api', path: '/api',
...@@ -190,6 +218,12 @@ Q extends 'private_tags_address' ? AddressTags : ...@@ -190,6 +218,12 @@ Q extends 'private_tags_address' ? AddressTags :
Q extends 'private_tags_tx' ? TransactionTags : Q extends 'private_tags_tx' ? TransactionTags :
Q extends 'api_keys' ? ApiKeys : Q extends 'api_keys' ? ApiKeys :
Q extends 'watchlist' ? Array<WatchlistAddress> : Q extends 'watchlist' ? Array<WatchlistAddress> :
Q extends 'homepage_stats' ? HomeStats :
Q extends 'homepage_chart_txs' ? ChartTransactionResponse :
Q extends 'homepage_chart_market' ? ChartMarketResponse :
Q extends 'homepage_blocks' ? Array<Block> :
Q extends 'homepage_txs' ? Array<Transaction> :
Q extends 'homepage_indexing_status' ? IndexingStatus :
Q extends 'stats_counters' ? Stats : Q extends 'stats_counters' ? Stats :
Q extends 'stats_charts' ? Charts : Q extends 'stats_charts' ? Charts :
Q extends 'blocks' ? BlocksResponse : Q extends 'blocks' ? BlocksResponse :
...@@ -210,6 +244,7 @@ Q extends 'address_internal_txs' ? AddressInternalTxsResponse : ...@@ -210,6 +244,7 @@ Q extends 'address_internal_txs' ? AddressInternalTxsResponse :
Q extends 'address_token_transfers' ? AddressTokenTransferResponse : Q extends 'address_token_transfers' ? AddressTokenTransferResponse :
Q extends 'address_blocks_validated' ? AddressBlocksValidatedResponse : Q extends 'address_blocks_validated' ? AddressBlocksValidatedResponse :
Q extends 'address_coin_balance' ? AddressCoinBalanceHistoryResponse : Q extends 'address_coin_balance' ? AddressCoinBalanceHistoryResponse :
Q extends 'config_json_rpc' ? JsonRpcUrlResponse :
never; never;
/* eslint-enable @typescript-eslint/indent */ /* eslint-enable @typescript-eslint/indent */
......
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/addresses/${ req.query.id }/blocks-validated${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/addresses/${ req.query.id }/coin-balance-history-by-day`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/addresses/${ req.query.id }/coin-balance-history${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/addresses/${ req.query.id }/counters`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/addresses/${ req.query.id }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/addresses/${ req.query.id }/internal-transactions${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/addresses/${ req.query.id }/token-balances`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/addresses/${ req.query.id }/token-transfers${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/addresses/${ req.query.id }/transactions${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/blocks/${ req.query.id }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/blocks/${ req.query.id }/transactions${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/blocks${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import handler from 'lib/api/handler';
const getUrl = () => {
return `/v2/config/json-rpc-url`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import handler from 'lib/api/handler';
const getUrl = () => '/v2/stats/charts/market';
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import handler from 'lib/api/handler';
const getUrl = () => '/v2/stats/charts/transactions';
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import handler from 'lib/api/handler';
const getUrl = () => '/v2/stats';
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import handler from 'lib/api/handler';
const getUrl = () => '/v2/main-page/blocks';
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import handler from 'lib/api/handler';
const getUrl = () => '/v2/main-page/indexing-status';
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import handler from 'lib/api/handler';
const getUrl = () => '/v2/main-page/transactions';
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/transactions/${ req.query.id }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/transactions/${ req.query.id }/internal-transactions`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/transactions/${ req.query.id }/logs`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/transactions/${ req.query.id }/raw-trace`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/transactions/${ req.query.id }/token-transfers${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
const searchParamsStr = getSearchParams(req);
return `/v2/transactions/${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
export default requestHandler;
// todo_tom DELETE
export enum QueryKeys {
homeStats='homeStats',
indexingStatus='indexingStatus',
stats='stats',
charts='stats',
chartsTxs = 'charts-txs',
chartsMarket = 'charts-market',
indexBlocks='indexBlocks',
indexTxs='indexTxs',
jsonRpcUrl='json-rpc-url',
}
import { Flex, Box, Text, Skeleton } from '@chakra-ui/react'; import { Flex, Box, Text, Skeleton } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { HomeStats } from 'types/api/stats'; import useApiQuery from 'lib/api/useApiQuery';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { nbsp } from 'lib/html-entities'; import { nbsp } from 'lib/html-entities';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
...@@ -18,12 +14,7 @@ interface Props { ...@@ -18,12 +14,7 @@ interface Props {
const BlocksTabSlot = ({ pagination, isPaginationVisible }: Props) => { const BlocksTabSlot = ({ pagination, isPaginationVisible }: Props) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const fetch = useFetch(); const statsQuery = useApiQuery('homepage_stats');
const statsQuery = useQuery<unknown, unknown, HomeStats>(
[ QueryKeys.homeStats ],
() => fetch('/node-api/home-stats'),
);
if (isMobile) { if (isMobile) {
return null; return null;
......
import { Alert, AlertIcon, AlertTitle, chakra } from '@chakra-ui/react'; import { Alert, AlertIcon, AlertTitle, chakra } from '@chakra-ui/react';
import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { SocketMessage } from 'lib/socket/types'; import type { SocketMessage } from 'lib/socket/types';
import type { IndexingStatus } from 'types/api/indexingStatus'; import type { IndexingStatus } from 'types/api/indexingStatus';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { nbsp, ndash } from 'lib/html-entities'; import { nbsp, ndash } from 'lib/html-entities';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
const IndexingAlert = ({ className }: { className?: string }) => { const IndexingAlert = ({ className }: { className?: string }) => {
const fetch = useFetch();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const { data } = useQuery<unknown, unknown, IndexingStatus>( const { data } = useApiQuery('homepage_indexing_status');
[ QueryKeys.indexingStatus ],
async() => await fetch(`/node-api/index/indexing-status`),
);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const handleBlocksIndexStatus: SocketMessage.BlocksIndexStatus['handler'] = React.useCallback((payload) => { const handleBlocksIndexStatus: SocketMessage.BlocksIndexStatus['handler'] = React.useCallback((payload) => {
queryClient.setQueryData([ QueryKeys.indexingStatus ], (prevData: IndexingStatus | undefined) => { queryClient.setQueryData(getResourceKey('homepage_indexing_status'), (prevData: IndexingStatus | undefined) => {
const newData = prevData ? { ...prevData } : {} as IndexingStatus; const newData = prevData ? { ...prevData } : {} as IndexingStatus;
newData.finished_indexing_blocks = payload.finished; newData.finished_indexing_blocks = payload.finished;
...@@ -46,7 +41,7 @@ const IndexingAlert = ({ className }: { className?: string }) => { ...@@ -46,7 +41,7 @@ const IndexingAlert = ({ className }: { className?: string }) => {
}); });
const handleIntermalTxsIndexStatus: SocketMessage.InternalTxsIndexStatus['handler'] = React.useCallback((payload) => { const handleIntermalTxsIndexStatus: SocketMessage.InternalTxsIndexStatus['handler'] = React.useCallback((payload) => {
queryClient.setQueryData([ QueryKeys.indexingStatus ], (prevData: IndexingStatus | undefined) => { queryClient.setQueryData(getResourceKey('homepage_indexing_status'), (prevData: IndexingStatus | undefined) => {
const newData = prevData ? { ...prevData } : {} as IndexingStatus; const newData = prevData ? { ...prevData } : {} as IndexingStatus;
newData.finished_indexing = payload.finished; newData.finished_indexing = payload.finished;
......
import { Box, Heading, Flex, Link, Text, VStack, Skeleton } from '@chakra-ui/react'; import { Box, Heading, Flex, Link, Text, VStack, Skeleton } from '@chakra-ui/react';
import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { AnimatePresence } from 'framer-motion'; import { AnimatePresence } from 'framer-motion';
import React from 'react'; import React from 'react';
import type { SocketMessage } from 'lib/socket/types'; import type { SocketMessage } from 'lib/socket/types';
import type { Block } from 'types/api/block'; import type { Block } from 'types/api/block';
import type { HomeStats } from 'types/api/stats';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch'; import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { nbsp } from 'lib/html-entities'; import { nbsp } from 'lib/html-entities';
import link from 'lib/link/link'; import link from 'lib/link/link';
...@@ -24,20 +22,13 @@ const BLOCK_MARGIN = 12; ...@@ -24,20 +22,13 @@ const BLOCK_MARGIN = 12;
const LatestBlocks = () => { const LatestBlocks = () => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const blocksMaxCount = isMobile ? 2 : 3; const blocksMaxCount = isMobile ? 2 : 3;
const fetch = useFetch(); const { data, isLoading, isError } = useApiQuery('homepage_blocks');
const { data, isLoading, isError } = useQuery<unknown, unknown, Array<Block>>(
[ QueryKeys.indexBlocks ],
async() => await fetch(`/node-api/index/blocks`),
);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const statsQueryResult = useQuery<unknown, unknown, HomeStats>( const statsQueryResult = useApiQuery('homepage_stats');
[ QueryKeys.homeStats ],
() => fetch('/node-api/home-stats'),
);
const handleNewBlockMessage: SocketMessage.NewBlock['handler'] = React.useCallback((payload) => { const handleNewBlockMessage: SocketMessage.NewBlock['handler'] = React.useCallback((payload) => {
queryClient.setQueryData([ QueryKeys.indexBlocks ], (prevData: Array<Block> | undefined) => { queryClient.setQueryData(getResourceKey('homepage_blocks'), (prevData: Array<Block> | undefined) => {
const newData = prevData ? [ ...prevData ] : []; const newData = prevData ? [ ...prevData ] : [];
......
import { Box, Heading, Flex, Link, Text, Skeleton } from '@chakra-ui/react'; import { Box, Heading, Flex, Link, Text, Skeleton } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { Transaction } from 'types/api/transaction'; import useApiQuery from 'lib/api/useApiQuery';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import link from 'lib/link/link'; import link from 'lib/link/link';
import TxsNewItemNotice from 'ui/txs/TxsNewItemNotice'; import TxsNewItemNotice from 'ui/txs/TxsNewItemNotice';
...@@ -16,11 +12,7 @@ import LatestTxsItemSkeleton from './LatestTxsItemSkeleton'; ...@@ -16,11 +12,7 @@ import LatestTxsItemSkeleton from './LatestTxsItemSkeleton';
const LatestTransactions = () => { const LatestTransactions = () => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const txsCount = isMobile ? 2 : 6; const txsCount = isMobile ? 2 : 6;
const fetch = useFetch(); const { data, isLoading, isError } = useApiQuery('homepage_txs');
const { data, isLoading, isError } = useQuery<unknown, unknown, Array<Transaction>>(
[ QueryKeys.indexTxs ],
async() => await fetch(`/node-api/index/txs`),
);
let content; let content;
......
import { Grid } from '@chakra-ui/react'; import { Grid } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { HomeStats } from 'types/api/stats';
import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import blockIcon from 'icons/block.svg'; import blockIcon from 'icons/block.svg';
import clockIcon from 'icons/clock-light.svg'; import clockIcon from 'icons/clock-light.svg';
import gasIcon from 'icons/gas.svg'; import gasIcon from 'icons/gas.svg';
import txIcon from 'icons/transactions.svg'; import txIcon from 'icons/transactions.svg';
import walletIcon from 'icons/wallet.svg'; import walletIcon from 'icons/wallet.svg';
import useFetch from 'lib/hooks/useFetch'; import useApiQuery from 'lib/api/useApiQuery';
import link from 'lib/link/link'; import link from 'lib/link/link';
import StatsGasPrices from './StatsGasPrices'; import StatsGasPrices from './StatsGasPrices';
...@@ -26,12 +22,7 @@ let itemsCount = 5; ...@@ -26,12 +22,7 @@ let itemsCount = 5;
!hasAvgBlockTime && itemsCount--; !hasAvgBlockTime && itemsCount--;
const Stats = () => { const Stats = () => {
const fetch = useFetch(); const { data, isLoading, isError } = useApiQuery('homepage_stats');
const { data, isLoading, isError } = useQuery<unknown, unknown, HomeStats>(
[ QueryKeys.homeStats ],
async() => await fetch(`/node-api/home-stats`),
);
if (isError) { if (isError) {
return null; return null;
......
import { Box, Flex, Icon, Skeleton, Text, Tooltip, useColorModeValue } from '@chakra-ui/react'; import { Box, Flex, Icon, Skeleton, Text, Tooltip, useColorModeValue } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { HomeStats } from 'types/api/stats';
import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import infoIcon from 'icons/info.svg'; import infoIcon from 'icons/info.svg';
import useFetch from 'lib/hooks/useFetch'; import useApiQuery from 'lib/api/useApiQuery';
import ChainIndicatorChartContainer from './ChainIndicatorChartContainer'; import ChainIndicatorChartContainer from './ChainIndicatorChartContainer';
import ChainIndicatorItem from './ChainIndicatorItem'; import ChainIndicatorItem from './ChainIndicatorItem';
...@@ -32,13 +28,8 @@ const ChainIndicators = () => { ...@@ -32,13 +28,8 @@ const ChainIndicators = () => {
const [ selectedIndicator, selectIndicator ] = React.useState(indicators[0]?.id); const [ selectedIndicator, selectIndicator ] = React.useState(indicators[0]?.id);
const indicator = indicators.find(({ id }) => id === selectedIndicator); const indicator = indicators.find(({ id }) => id === selectedIndicator);
const queryResult = useFetchChartData(indicator); const queryResult = useFetchChartData(indicator!);
const statsQueryResult = useApiQuery('homepage_stats');
const fetch = useFetch();
const statsQueryResult = useQuery<unknown, unknown, HomeStats>(
[ QueryKeys.homeStats ],
() => fetch('/node-api/home-stats'),
);
const bgColorDesktop = useColorModeValue('white', 'gray.900'); const bgColorDesktop = useColorModeValue('white', 'gray.900');
const bgColorMobile = useColorModeValue('white', 'black'); const bgColorMobile = useColorModeValue('white', 'black');
......
import type { ChartMarketResponse, ChartTransactionResponse } from 'types/api/charts';
import type { HomeStats } from 'types/api/stats'; import type { HomeStats } from 'types/api/stats';
import type { QueryKeys } from 'types/client/queries';
import type { TimeChartData } from 'ui/shared/chart/types'; import type { TimeChartData } from 'ui/shared/chart/types';
export type ChartsQueryKeys = QueryKeys.chartsTxs | QueryKeys.chartsMarket; import type { ResourcePayload } from 'lib/api/resources';
export type ChartsResources = 'homepage_chart_txs' | 'homepage_chart_market';
export type ChainIndicatorId = 'daily_txs' | 'coin_price' | 'market_cup'; export type ChainIndicatorId = 'daily_txs' | 'coin_price' | 'market_cup';
export interface TChainIndicator<Q extends ChartsQueryKeys> { export interface TChainIndicator<R extends ChartsResources> {
id: ChainIndicatorId; id: ChainIndicatorId;
title: string; title: string;
value: (stats: HomeStats) => string; value: (stats: HomeStats) => string;
icon: React.ReactNode; icon: React.ReactNode;
hint?: string; hint?: string;
api: { api: {
queryName: Q; resourceName: R;
path: string; dataFn: (response: ResourcePayload<R>) => TimeChartData;
dataFn: (response: ChartsResponse<Q>) => TimeChartData;
}; };
} }
export type ChartsResponse<Q extends ChartsQueryKeys> =
Q extends QueryKeys.chartsTxs ? ChartTransactionResponse :
Q extends QueryKeys.chartsMarket ? ChartMarketResponse :
never;
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { TChainIndicator, ChartsResponse, ChartsQueryKeys } from './types'; import type { TChainIndicator, ChartsResources } from './types';
import type { TimeChartData } from 'ui/shared/chart/types'; import type { TimeChartData } from 'ui/shared/chart/types';
import useFetch from 'lib/hooks/useFetch'; import useApiQuery from 'lib/api/useApiQuery';
type NotUndefined<T> = T extends undefined ? never : T; export default function useFetchChartData<R extends ChartsResources>(indicator: TChainIndicator<R>): UseQueryResult<TimeChartData> {
const queryResult = useApiQuery(indicator.api.resourceName, {
export default function useFetchChartData<Q extends ChartsQueryKeys>(indicator: TChainIndicator<Q> | undefined): UseQueryResult<TimeChartData> { queryOptions: { enabled: Boolean(indicator) },
const fetch = useFetch(); });
type ResponseType = ChartsResponse<NotUndefined<typeof indicator>['api']['queryName']>;
const queryResult = useQuery<unknown, unknown, ResponseType>(
[ indicator?.api.queryName ],
() => fetch(indicator?.api.path || ''),
{ enabled: Boolean(indicator) },
);
return React.useMemo(() => { return React.useMemo(() => {
return { return {
......
...@@ -2,7 +2,6 @@ import { Icon } from '@chakra-ui/react'; ...@@ -2,7 +2,6 @@ import { Icon } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { TChainIndicator } from '../types'; import type { TChainIndicator } from '../types';
import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import globeIcon from 'icons/globe.svg'; import globeIcon from 'icons/globe.svg';
...@@ -11,15 +10,14 @@ import { shortenNumberWithLetter } from 'lib/formatters'; ...@@ -11,15 +10,14 @@ import { shortenNumberWithLetter } from 'lib/formatters';
import { sortByDateDesc } from 'ui/shared/chart/utils/sorts'; import { sortByDateDesc } from 'ui/shared/chart/utils/sorts';
import TokenLogo from 'ui/shared/TokenLogo'; import TokenLogo from 'ui/shared/TokenLogo';
const dailyTxsIndicator: TChainIndicator<QueryKeys.chartsTxs> = { const dailyTxsIndicator: TChainIndicator<'homepage_chart_txs'> = {
id: 'daily_txs', id: 'daily_txs',
title: 'Daily transactions', title: 'Daily transactions',
value: (stats) => shortenNumberWithLetter(Number(stats.transactions_today), undefined, { maximumFractionDigits: 2 }), value: (stats) => shortenNumberWithLetter(Number(stats.transactions_today), undefined, { maximumFractionDigits: 2 }),
icon: <Icon as={ txIcon } boxSize={ 6 } bgColor="#56ACD1" borderRadius="base" color="white"/>, icon: <Icon as={ txIcon } boxSize={ 6 } bgColor="#56ACD1" borderRadius="base" color="white"/>,
hint: `The total daily number of transactions on the blockchain for the last month.`, hint: `The total daily number of transactions on the blockchain for the last month.`,
api: { api: {
queryName: QueryKeys.chartsTxs, resourceName: 'homepage_chart_txs',
path: '/node-api/home-stats/charts/transactions',
dataFn: (response) => ([ { dataFn: (response) => ([ {
items: response.chart_data items: response.chart_data
.map((item) => ({ date: new Date(item.date), value: item.tx_count })) .map((item) => ({ date: new Date(item.date), value: item.tx_count }))
...@@ -30,15 +28,14 @@ const dailyTxsIndicator: TChainIndicator<QueryKeys.chartsTxs> = { ...@@ -30,15 +28,14 @@ const dailyTxsIndicator: TChainIndicator<QueryKeys.chartsTxs> = {
}, },
}; };
const coinPriceIndicator: TChainIndicator<QueryKeys.chartsMarket> = { const coinPriceIndicator: TChainIndicator<'homepage_chart_market'> = {
id: 'coin_price', id: 'coin_price',
title: `${ appConfig.network.currency.symbol } price`, title: `${ appConfig.network.currency.symbol } price`,
value: (stats) => '$' + Number(stats.coin_price).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 }), value: (stats) => '$' + Number(stats.coin_price).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 }),
icon: <TokenLogo hash={ appConfig.network.currency.address || '' } name={ appConfig.network.currency.name } boxSize={ 6 }/>, icon: <TokenLogo hash={ appConfig.network.currency.address || '' } name={ appConfig.network.currency.name } boxSize={ 6 }/>,
hint: `${ appConfig.network.currency.symbol } token daily price in USD.`, hint: `${ appConfig.network.currency.symbol } token daily price in USD.`,
api: { api: {
queryName: QueryKeys.chartsMarket, resourceName: 'homepage_chart_market',
path: '/node-api/home-stats/charts/market',
dataFn: (response) => ([ { dataFn: (response) => ([ {
items: response.chart_data items: response.chart_data
.map((item) => ({ date: new Date(item.date), value: Number(item.closing_price) })) .map((item) => ({ date: new Date(item.date), value: Number(item.closing_price) }))
...@@ -49,7 +46,7 @@ const coinPriceIndicator: TChainIndicator<QueryKeys.chartsMarket> = { ...@@ -49,7 +46,7 @@ const coinPriceIndicator: TChainIndicator<QueryKeys.chartsMarket> = {
}, },
}; };
const marketPriceIndicator: TChainIndicator<QueryKeys.chartsMarket> = { const marketPriceIndicator: TChainIndicator<'homepage_chart_market'> = {
id: 'market_cup', id: 'market_cup',
title: 'Market cap', title: 'Market cap',
value: (stats) => '$' + shortenNumberWithLetter(Number(stats.market_cap), undefined, { maximumFractionDigits: 0 }), value: (stats) => '$' + shortenNumberWithLetter(Number(stats.market_cap), undefined, { maximumFractionDigits: 0 }),
...@@ -57,8 +54,7 @@ const marketPriceIndicator: TChainIndicator<QueryKeys.chartsMarket> = { ...@@ -57,8 +54,7 @@ const marketPriceIndicator: TChainIndicator<QueryKeys.chartsMarket> = {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
hint: 'The total market value of a cryptocurrency\'s circulating supply. It is analogous to the free-float capitalization in the stock market. Market Cap = Current Price x Circulating Supply.', hint: 'The total market value of a cryptocurrency\'s circulating supply. It is analogous to the free-float capitalization in the stock market. Market Cap = Current Price x Circulating Supply.',
api: { api: {
queryName: QueryKeys.chartsMarket, resourceName: 'homepage_chart_market',
path: '/node-api/home-stats/charts/market',
dataFn: (response) => ([ { dataFn: (response) => ([ {
items: response.chart_data items: response.chart_data
.map((item) => ({ date: new Date(item.date), value: Number(item.closing_price) * Number(response.available_supply) })) .map((item) => ({ date: new Date(item.date), value: Number(item.closing_price) * Number(response.available_supply) }))
......
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/jsonRpcUrl';
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 useApiQuery from 'lib/api/useApiQuery';
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';
...@@ -15,8 +12,6 @@ import FilterInput from 'ui/shared/FilterInput'; ...@@ -15,8 +12,6 @@ import FilterInput from 'ui/shared/FilterInput';
import useMarketplaceApps from '../apps/useMarketplaceApps'; import useMarketplaceApps from '../apps/useMarketplaceApps';
const Apps = () => { const Apps = () => {
const fetch = useFetch();
const { const {
isLoading, isLoading,
category, category,
...@@ -30,10 +25,7 @@ const Apps = () => { ...@@ -30,10 +25,7 @@ const Apps = () => {
handleFavoriteClick, handleFavoriteClick,
} = useMarketplaceApps(); } = useMarketplaceApps();
useQuery<unknown, unknown, JsonRpcUrlResponse>( useApiQuery('config_json_rpc');
[ 'json-rpc-url' ],
async() => await fetch(`/node-api/config/json-rpc-url`),
);
return ( return (
<> <>
......
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/jsonRpcUrl';
import type { AppItemOverview } from 'types/client/apps'; import type { AppItemOverview } from 'types/client/apps';
import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import useFetch from 'lib/hooks/useFetch'; import useApiQuery from 'lib/api/useApiQuery';
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';
...@@ -20,18 +17,15 @@ type Props = { ...@@ -20,18 +17,15 @@ type Props = {
const MarketplaceApp = ({ app, isLoading }: Props) => { const MarketplaceApp = ({ app, isLoading }: Props) => {
const [ isFrameLoading, setIsFrameLoading ] = useState(isLoading); const [ isFrameLoading, setIsFrameLoading ] = useState(isLoading);
const { colorMode } = useColorMode(); const { colorMode } = useColorMode();
const fetch = useFetch();
const ref = useRef<HTMLIFrameElement>(null); const ref = useRef<HTMLIFrameElement>(null);
const handleIframeLoad = useCallback(() => { const handleIframeLoad = useCallback(() => {
setIsFrameLoading(false); setIsFrameLoading(false);
}, []); }, []);
const { data: jsonRpcUrlResponse } = useQuery<unknown, unknown, JsonRpcUrlResponse>( const { data: jsonRpcUrlResponse } = useApiQuery('config_json_rpc', {
[ QueryKeys.jsonRpcUrl ], queryOptions: { refetchOnMount: false },
async() => await fetch(`/node-api/config/json-rpc-url`), });
{ refetchOnMount: false },
);
useEffect(() => { useEffect(() => {
if (app && !isFrameLoading) { if (app && !isFrameLoading) {
......
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