/ src / modules / reserve-overview / graphs / ApyGraphContainer.tsx
ApyGraphContainer.tsx
  1  import { Trans } from '@lingui/macro';
  2  import { Box, Button, CircularProgress, Typography } from '@mui/material';
  3  import { ParentSize } from '@visx/responsive';
  4  import { useState } from 'react';
  5  import type { ComputedReserveData } from 'src/hooks/app-data-provider/useAppDataProvider';
  6  import { ReserveRateTimeRange, useReserveRatesHistory } from 'src/hooks/useReservesHistory';
  7  import { MarketDataType } from 'src/utils/marketsAndNetworksConfig';
  8  
  9  import { ESupportedTimeRanges } from '../TimeRangeSelector';
 10  import { ApyGraph, PlaceholderChart } from './ApyGraph';
 11  import { GraphLegend } from './GraphLegend';
 12  import { GraphTimeRangeSelector } from './GraphTimeRangeSelector';
 13  
 14  type Field = 'liquidityRate' | 'variableBorrowRate';
 15  
 16  type Fields = { name: Field; color: string; text: string }[];
 17  
 18  type ApyGraphContainerKey = 'supply' | 'borrow';
 19  
 20  type ApyGraphContainerProps = {
 21    graphKey: ApyGraphContainerKey;
 22    reserve: ComputedReserveData;
 23    currentMarketData: MarketDataType;
 24  };
 25  
 26  /**
 27   * NOTES:
 28   * This may not be named accurately.
 29   * This container uses the same graph but with different fields, so we use a 'graphKey' to determine which to show
 30   * This likely may need to be turned into two different container components if the graphs become wildly different.
 31   * This graph gets its data via an external API call, thus having loading/error states
 32   */
 33  export const ApyGraphContainer = ({
 34    graphKey,
 35    reserve,
 36    currentMarketData,
 37  }: ApyGraphContainerProps): JSX.Element => {
 38    const [selectedTimeRange, setSelectedTimeRange] = useState<ReserveRateTimeRange>(
 39      ESupportedTimeRanges.OneMonth
 40    );
 41  
 42    const CHART_HEIGHT = 155;
 43    const CHART_HEIGHT_LOADING_FIX = 3;
 44    let reserveAddress = '';
 45    if (reserve) {
 46      if (currentMarketData.v3) {
 47        reserveAddress = `${reserve.underlyingAsset}${currentMarketData.addresses.LENDING_POOL_ADDRESS_PROVIDER}${currentMarketData.chainId}`;
 48      } else {
 49        reserveAddress = `${reserve.underlyingAsset}${currentMarketData.addresses.LENDING_POOL_ADDRESS_PROVIDER}`;
 50      }
 51    }
 52    const { data, loading, error, refetch } = useReserveRatesHistory(
 53      reserveAddress,
 54      selectedTimeRange
 55    );
 56  
 57    // Supply fields
 58    const supplyFields: Fields = [{ name: 'liquidityRate', color: '#2EBAC6', text: 'Supply APR' }];
 59  
 60    // Borrow fields
 61    const borrowFields: Fields = [
 62      {
 63        name: 'variableBorrowRate',
 64        color: '#B6509E',
 65        text: 'Borrow APR, variable',
 66      },
 67    ];
 68  
 69    const fields = graphKey === 'supply' ? supplyFields : borrowFields;
 70  
 71    const graphLoading = (
 72      <Box
 73        sx={{
 74          height: CHART_HEIGHT + CHART_HEIGHT_LOADING_FIX,
 75          width: 'auto',
 76          display: 'flex',
 77          flexDirection: 'column',
 78          alignItems: 'center',
 79          justifyContent: 'center',
 80        }}
 81      >
 82        <CircularProgress size={20} sx={{ mb: 2, opacity: 0.5 }} />
 83        <Typography variant="subheader1" color="text.muted">
 84          <Trans>Loading data...</Trans>
 85        </Typography>
 86      </Box>
 87    );
 88  
 89    const graphError = (
 90      <Box
 91        sx={{
 92          height: CHART_HEIGHT + CHART_HEIGHT_LOADING_FIX,
 93          width: 'auto',
 94          display: 'flex',
 95          flexDirection: 'column',
 96          alignItems: 'center',
 97          justifyContent: 'center',
 98        }}
 99      >
100        <Typography variant="subheader1">
101          <Trans>Something went wrong</Trans>
102        </Typography>
103        <Typography variant="caption" sx={{ mb: 3 }}>
104          <Trans>Data couldn&apos;t be fetched, please reload graph.</Trans>
105        </Typography>
106        <Button variant="outlined" color="primary" onClick={refetch}>
107          <Trans>Reload</Trans>
108        </Button>
109      </Box>
110    );
111  
112    return (
113      <Box sx={{ mt: 10, mb: 4 }}>
114        <Box
115          sx={{
116            display: 'flex',
117            alignItems: 'center',
118            justifyContent: 'space-between',
119            mb: 4,
120          }}
121        >
122          <GraphLegend labels={fields} />
123          <GraphTimeRangeSelector
124            disabled={loading || error}
125            timeRange={selectedTimeRange}
126            onTimeRangeChanged={setSelectedTimeRange}
127          />
128        </Box>
129        {loading && graphLoading}
130        {error && graphError}
131        {!loading && !error && (
132          <ParentSize>
133            {({ width }) =>
134              data.length > 0 ? (
135                <ApyGraph
136                  width={width}
137                  height={CHART_HEIGHT}
138                  data={data}
139                  fields={fields}
140                  selectedTimeRange={selectedTimeRange}
141                  avgFieldName={graphKey === 'supply' ? 'liquidityRate' : 'variableBorrowRate'}
142                />
143              ) : (
144                /* Placeholder chart in the case where there is no rate data available yet */
145                <PlaceholderChart height={CHART_HEIGHT} width={width} />
146              )
147            }
148          </ParentSize>
149        )}
150      </Box>
151    );
152  };