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 };