/ src / modules / reserve-overview / Gho / GhoPieChartContainer.tsx
GhoPieChartContainer.tsx
  1  import { Trans } from '@lingui/macro';
  2  import {
  3    Box,
  4    Stack,
  5    Table,
  6    TableBody,
  7    TableCell,
  8    tableCellClasses,
  9    TableContainer,
 10    TableHead,
 11    TableRow,
 12    Typography,
 13    useMediaQuery,
 14    useTheme,
 15  } from '@mui/material';
 16  import { FormattedNumber } from 'src/components/primitives/FormattedNumber';
 17  
 18  import { GhoPieChart, PieChartData } from './GhoPieChart';
 19  
 20  export interface GhoPieChartContainer {
 21    borrowAmount: number | null;
 22    discountableAmount: number | null;
 23    baseRate: number;
 24    discountedAmountRate: number;
 25    rateAfterDiscount: number;
 26  }
 27  
 28  export const GhoPieChartContainer = ({
 29    borrowAmount,
 30    discountableAmount,
 31    baseRate,
 32    discountedAmountRate,
 33    rateAfterDiscount,
 34  }: GhoPieChartContainer) => {
 35    const { breakpoints } = useTheme();
 36    const downToXsm = useMediaQuery(breakpoints.down('xsm'));
 37  
 38    const amountAtDiscount = discountableAmount || 0;
 39    const amountThatExceedsDiscount = Math.max(0, (borrowAmount || 0) - amountAtDiscount);
 40  
 41    const chartData = [
 42      {
 43        name: 'amountThatExceedsDiscount',
 44        value: amountThatExceedsDiscount,
 45        color: '#B3C7F9',
 46      },
 47      {
 48        name: 'amountAtDiscount',
 49        value: amountAtDiscount,
 50        color: '#C9B3F9',
 51      },
 52    ];
 53  
 54    if (downToXsm) {
 55      return (
 56        <GhoPieChartMobile
 57          chartData={chartData}
 58          rateAfterDiscount={rateAfterDiscount}
 59          baseRate={baseRate}
 60          amountAtDiscount={amountAtDiscount}
 61          discountedAmountRate={discountedAmountRate}
 62          amountThatExceedsDiscount={amountThatExceedsDiscount}
 63        />
 64      );
 65    } else {
 66      return (
 67        <GhoPieChartDesktop
 68          chartData={chartData}
 69          rateAfterDiscount={rateAfterDiscount}
 70          baseRate={baseRate}
 71          amountAtDiscount={amountAtDiscount}
 72          discountedAmountRate={discountedAmountRate}
 73          amountThatExceedsDiscount={amountThatExceedsDiscount}
 74        />
 75      );
 76    }
 77  };
 78  
 79  interface GhoPieChartProps {
 80    rateAfterDiscount: number;
 81    chartData: PieChartData[];
 82    amountAtDiscount: number;
 83    discountedAmountRate: number;
 84    amountThatExceedsDiscount: number;
 85    baseRate: number;
 86  }
 87  
 88  const GhoPieChartDesktop = ({
 89    rateAfterDiscount,
 90    chartData,
 91    amountAtDiscount,
 92    discountedAmountRate,
 93    amountThatExceedsDiscount,
 94    baseRate,
 95  }: GhoPieChartProps) => {
 96    const theme = useTheme();
 97  
 98    return (
 99      <Stack
100        direction="column"
101        sx={{
102          position: 'relative',
103          background: theme.palette.background.surface2,
104          minWidth: '306px',
105          height: '320px',
106          justifyContent: 'space-between',
107          alignItems: 'center',
108          borderRadius: 2,
109          py: 4,
110          px: 6,
111        }}
112      >
113        <Stack alignItems="center" gap={1} sx={{ position: 'absolute', top: 65 }}>
114          <Typography variant="subheader2">Borrow APY</Typography>
115          <FormattedNumber
116            variant="h1"
117            symbolsColor="text.primary"
118            percent
119            value={rateAfterDiscount}
120            visibleDecimals={2}
121          />
122        </Stack>
123        <GhoPieChart data={chartData} width={156} height={156} />
124        <Box>
125          <PieChartLegend
126            amountAtDiscount={amountAtDiscount}
127            discountedAmountRate={discountedAmountRate}
128            amountThatExceedsDiscount={amountThatExceedsDiscount}
129            baseRate={baseRate}
130          />
131        </Box>
132      </Stack>
133    );
134  };
135  
136  const GhoPieChartMobile = ({
137    rateAfterDiscount,
138    chartData,
139    amountAtDiscount,
140    discountedAmountRate,
141    amountThatExceedsDiscount,
142    baseRate,
143  }: GhoPieChartProps) => {
144    const theme = useTheme();
145  
146    return (
147      <Stack
148        direction="column"
149        sx={{
150          position: 'relative',
151          height: '280px',
152          background: theme.palette.background.surface2,
153          alignItems: 'center',
154          borderRadius: 2,
155          px: 4,
156          pt: 2,
157          mb: 2,
158        }}
159      >
160        <Stack alignItems="center" gap={1} sx={{ position: 'absolute', top: 58 }}>
161          <Typography variant="subheader2">Borrow APY</Typography>
162          <FormattedNumber
163            variant="h1"
164            symbolsColor="text.primary"
165            percent
166            value={rateAfterDiscount}
167            visibleDecimals={2}
168          />
169        </Stack>
170        <GhoPieChart data={chartData} width={156} height={156} />
171        <Box sx={{ width: '100%' }}>
172          <PieChartLegend
173            amountAtDiscount={amountAtDiscount}
174            discountedAmountRate={discountedAmountRate}
175            amountThatExceedsDiscount={amountThatExceedsDiscount}
176            baseRate={baseRate}
177          />
178        </Box>
179      </Stack>
180    );
181  };
182  
183  interface PieChartLegendProps {
184    amountAtDiscount: number;
185    discountedAmountRate: number;
186    amountThatExceedsDiscount: number;
187    baseRate: number;
188  }
189  
190  const PieChartLegend = ({
191    amountAtDiscount,
192    discountedAmountRate,
193    amountThatExceedsDiscount,
194    baseRate,
195  }: PieChartLegendProps) => {
196    return (
197      <TableContainer>
198        <Table size="small">
199          <TableHead>
200            <TableRow
201              sx={{
202                [`& .${tableCellClasses.root}`]: {
203                  py: 2,
204                  lineHeight: 0,
205                },
206              }}
207            >
208              <TableCell align="left" sx={{ pl: 0 }}>
209                <Typography variant="helperText">
210                  <Trans>Borrow balance</Trans>
211                </Typography>
212              </TableCell>
213              <TableCell align="right">
214                <Typography variant="helperText">
215                  <Trans>Amount</Trans>
216                </Typography>
217              </TableCell>
218              <TableCell align="right" sx={{ pr: 0 }}>
219                <Typography variant="helperText">APY</Typography>
220              </TableCell>
221            </TableRow>
222          </TableHead>
223          <TableBody>
224            <TableRow
225              sx={{
226                pt: 8,
227                [`& .${tableCellClasses.root}`]: {
228                  borderBottom: 'none',
229                  pt: 3,
230                  pb: 2,
231                },
232              }}
233            >
234              <TableCell align="left" sx={{ pl: 0, py: 1 }}>
235                <Stack direction="row" alignItems="center" gap={1}>
236                  <Box
237                    sx={{
238                      background: '#C9B3F9',
239                      width: '6px',
240                      height: '6px',
241                      borderRadius: '50%',
242                    }}
243                  />
244                  <Typography variant="caption">
245                    <Trans>At a discount</Trans>
246                  </Typography>
247                </Stack>
248              </TableCell>
249              <TableCell align="right">
250                <FormattedNumber variant="subheader2" value={amountAtDiscount} align="right" />
251              </TableCell>
252              <TableCell sx={{ pr: 0 }} align="right">
253                <FormattedNumber
254                  variant="subheader2"
255                  value={discountedAmountRate}
256                  percent
257                  visibleDecimals={2}
258                />
259              </TableCell>
260            </TableRow>
261            <TableRow
262              sx={{
263                [`& .${tableCellClasses.root}`]: {
264                  borderBottom: 'none',
265                },
266              }}
267            >
268              <TableCell align="left" sx={{ pl: 0 }}>
269                <Stack direction="row" alignItems="center" gap={1}>
270                  <Box
271                    sx={{
272                      background: '#B3C7F9',
273                      width: '6px',
274                      height: '6px',
275                      borderRadius: '50%',
276                      flexShrink: 0,
277                    }}
278                  />
279                  <Typography variant="caption">
280                    <Trans>Exceeds the discount</Trans>
281                  </Typography>
282                </Stack>
283              </TableCell>
284              <TableCell align="right">
285                <FormattedNumber
286                  variant="subheader2"
287                  visibleDecimals={2}
288                  value={amountThatExceedsDiscount}
289                />
290              </TableCell>
291              <TableCell sx={{ pr: 0 }} align="right">
292                <FormattedNumber variant="subheader2" value={baseRate} percent />
293              </TableCell>
294            </TableRow>
295          </TableBody>
296        </Table>
297      </TableContainer>
298    );
299  };