Commit 28b59628 authored by tom's avatar tom

Merge branch 'main' of github.com:blockscout/frontend into client-api-calls

parents e62dd630 c8e95452
......@@ -80,6 +80,11 @@ export interface AddressCoinBalanceHistoryResponse {
};
}
export type AddressCoinBalanceHistoryChart = Array<{
date: string;
value: string;
}>
export interface AddressBlocksValidatedResponse {
items: Array<Block>;
next_page_params: {
......
......@@ -69,7 +69,7 @@ const AddressCoinBalance = ({ addressQuery }: Props) => {
return (
<>
{ socketAlert && <SocketAlert mb={ 6 }/> }
<AddressCoinBalanceChart/>
<AddressCoinBalanceChart addressQuery={ addressQuery }/>
<AddressCoinBalanceHistory query={ coinBalanceQuery }/>
</>
);
......
import { Box } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import BigNumber from 'bignumber.js';
import React from 'react';
const AddressCoinBalanceChart = () => {
// chart will be added after stats feature is finalized
return <Box p={ 4 } borderColor="gray.200" borderRadius="md" borderWidth="1px">Here will be coin balance chart</Box>;
import type { Address, AddressCoinBalanceHistoryChart } from 'types/api/address';
import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config';
import useFetch from 'lib/hooks/useFetch';
import ChartWidget from 'ui/shared/chart/ChartWidget';
interface Props {
addressQuery: UseQueryResult<Address>;
}
const AddressCoinBalanceChart = ({ addressQuery }: Props) => {
const fetch = useFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, AddressCoinBalanceHistoryChart>(
[ QueryKeys.addressCoinBalanceHistoryByDay, addressQuery.data?.hash ],
async() => fetch(`/node-api/addresses/${ addressQuery.data?.hash }/coin-balance-history-by-day`,
), {
enabled: Boolean(addressQuery.data?.hash),
});
const items = React.useMemo(() => data?.map(({ date, value }) => ({
date: new Date(date),
value: BigNumber(value).div(10 ** appConfig.network.currency.decimals).toNumber(),
})), [ data ]);
return (
<ChartWidget
chartHeight="200px"
title="Balances"
items={ items }
isLoading={ isLoading || isError }
/>
);
};
export default AddressCoinBalanceChart;
export default React.memo(AddressCoinBalanceChart);
......@@ -16,13 +16,14 @@ import FullscreenChartModal from './FullscreenChartModal';
type Props = {
items?: Array<TimeChartItem>;
title: string;
description: string;
description?: string;
isLoading: boolean;
chartHeight?: string;
}
const DOWNLOAD_IMAGE_SCALE = 5;
const ChartWidget = ({ items, title, description, isLoading }: Props) => {
const ChartWidget = ({ items, title, description, isLoading, chartHeight }: Props) => {
const ref = useRef<HTMLDivElement>(null);
const [ isFullscreen, setIsFullscreen ] = useState(false);
const [ isZoomResetInitial, setIsZoomResetInitial ] = React.useState(true);
......@@ -78,7 +79,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
}, [ title ]);
if (isLoading) {
return <ChartWidgetSkeleton/>;
return <ChartWidgetSkeleton hasDescription={ Boolean(description) } chartHeight={ chartHeight }/>;
}
if (items) {
......@@ -105,6 +106,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
{ title }
</Text>
{ description && (
<Text
mb={ 1 }
gridColumn={ 1 }
......@@ -114,6 +116,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
>
{ description }
</Text>
) }
<Tooltip label="Reset zoom">
<IconButton
......@@ -170,6 +173,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
</Menu>
</Grid>
<Box h={ chartHeight || 'auto' }>
<ChartWidgetGraph
items={ items }
onZoom={ handleZoom }
......@@ -177,6 +181,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
title={ title }
/>
</Box>
</Box>
<FullscreenChartModal
isOpen={ isFullscreen }
......@@ -192,4 +197,4 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
return null;
};
export default ChartWidget;
export default React.memo(ChartWidget);
......@@ -22,7 +22,7 @@ interface Props {
isZoomResetInitial: boolean;
}
const CHART_MARGIN = { bottom: 20, left: 30, right: 20, top: 10 };
const CHART_MARGIN = { bottom: 20, left: 40, right: 20, top: 10 };
const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title }: Props) => {
const isMobile = useIsMobile();
......@@ -31,10 +31,9 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
const overlayRef = React.useRef<SVGRectElement>(null);
const chartId = useMemo(() => `chart-${ title.split(' ').join('') }`, [ title ]);
const [ range, setRange ] = React.useState<[ number, number ]>([ 0, Infinity ]);
const { innerWidth, innerHeight } = useChartSize(ref.current, CHART_MARGIN);
const { width, height, innerWidth, innerHeight } = useChartSize(ref.current, CHART_MARGIN);
const displayedData = useMemo(() => items.slice(range[0], range[1]).map((d) =>
({ ...d, date: new Date(d.date) })), [ items, range ]);
const displayedData = useMemo(() => items.slice(range[0], range[1]), [ items, range ]);
const chartData = [ { items: items, name: 'Value', color } ];
const { yTickFormat, xScale, yScale } = useTimeChartController({
......@@ -55,9 +54,9 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
}, [ isZoomResetInitial ]);
return (
<svg width="100%" height="100%" ref={ ref } cursor="pointer" id={ chartId }>
<svg width={ width || '100%' } height={ height || 'auto' } ref={ ref } cursor="pointer" id={ chartId } opacity={ width ? 1 : 0 }>
<g transform={ `translate(${ CHART_MARGIN?.left || 0 },${ CHART_MARGIN?.top || 0 })` } opacity={ innerWidth ? 1 : 0 }>
<g transform={ `translate(${ CHART_MARGIN?.left || 0 },${ CHART_MARGIN?.top || 0 })` }>
<ChartGridLine
type="horizontal"
scale={ yScale }
......
import { Box, Skeleton } from '@chakra-ui/react';
import React from 'react';
const ChartWidgetSkeleton = () => {
interface Props {
hasDescription: boolean;
chartHeight?: string;
}
const ChartWidgetSkeleton = ({ hasDescription, chartHeight }: Props) => {
return (
<Box
height="235px"
paddingY={{ base: 3, lg: 4 }}
>
<Skeleton w="75%" h="24px" mb={ 1 }/>
<Skeleton w="50%" h="18px" mb={ 5 }/>
<Skeleton w="75%" h="24px"/>
{ hasDescription && <Skeleton w="50%" h="18px" mt={ 1 }/> }
<Skeleton w="100%" h="150px"/>
<Skeleton w="100%" h={ chartHeight || '150px' } mt={ 5 }/>
</Box>
);
};
......
......@@ -10,7 +10,7 @@ import ChartWidgetGraph from './ChartWidgetGraph';
type Props = {
isOpen: boolean;
title: string;
description: string;
description?: string;
items: Array<TimeChartItem>;
onClose: () => void;
}
......@@ -56,6 +56,7 @@ const FullscreenChartModal = ({
{ title }
</Heading>
{ description && (
<Text
gridColumn={ 1 }
as="p"
......@@ -64,6 +65,7 @@ const FullscreenChartModal = ({
>
{ description }
</Text>
) }
{ !isZoomResetInitial && (
<Button
......
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