MigrationListMobileItem.tsx
1 import { ExclamationCircleIcon } from '@heroicons/react/outline'; 2 import { ArrowNarrowRightIcon, CheckIcon } from '@heroicons/react/solid'; 3 import { Trans } from '@lingui/macro'; 4 import CheckRoundedIcon from '@mui/icons-material/CheckRounded'; 5 import { Box, Button, SvgIcon, Typography, useTheme } from '@mui/material'; 6 import { IncentivesCard } from 'src/components/incentives/IncentivesCard'; 7 import { MigrationDisabledTooltip } from 'src/components/infoTooltips/MigrationDisabledTooltip'; 8 import { IsolatedEnabledBadge } from 'src/components/isolationMode/IsolatedBadge'; 9 import { ListColumn } from 'src/components/lists/ListColumn'; 10 import { ListItem } from 'src/components/lists/ListItem'; 11 import { FormattedNumber } from 'src/components/primitives/FormattedNumber'; 12 import { ROUTES } from 'src/components/primitives/Link'; 13 import { NoData } from 'src/components/primitives/NoData'; 14 import { Row } from 'src/components/primitives/Row'; 15 import { TokenIcon } from 'src/components/primitives/TokenIcon'; 16 import { ComputedUserReserveData } from 'src/hooks/app-data-provider/useAppDataProvider'; 17 import { useRootStore } from 'src/store/root'; 18 import { MigrationDisabled, V3Rates } from 'src/store/v3MigrationSelectors'; 19 import { useShallow } from 'zustand/shallow'; 20 21 import { MigrationListItemToggler } from './MigrationListItemToggler'; 22 import { StETHMigrationWarning } from './StETHMigrationWarning'; 23 24 interface MigrationListMobileItemProps { 25 checked: boolean; 26 amount: string; 27 amountInUSD: string; 28 onCheckboxClick: () => void; 29 disabled?: MigrationDisabled; 30 enabledAsCollateral?: boolean; 31 canBeEnforced?: boolean; 32 enableAsCollateral?: () => void; 33 isIsolated?: boolean; 34 enteringIsolation: boolean; 35 borrowApyType?: string; 36 userReserve: ComputedUserReserveData; 37 v3Rates?: V3Rates; 38 showCollateralToggle?: boolean; 39 isSupplyList: boolean; 40 } 41 42 export const MigrationListMobileItem = ({ 43 checked, 44 amount, 45 amountInUSD, 46 onCheckboxClick, 47 enabledAsCollateral, 48 disabled, 49 enableAsCollateral, 50 isIsolated, 51 enteringIsolation, 52 borrowApyType, 53 userReserve, 54 v3Rates, 55 showCollateralToggle, 56 isSupplyList, 57 }: MigrationListMobileItemProps) => { 58 const v2APY = borrowApyType 59 ? userReserve.reserve.variableBorrowAPY 60 : userReserve.reserve.supplyAPY; 61 const v2Incentives = borrowApyType 62 ? userReserve.reserve.vIncentivesData 63 : userReserve.reserve.aIncentivesData; 64 const v3APY = borrowApyType ? v3Rates?.variableBorrowAPY || '-1' : v3Rates?.supplyAPY || '-1'; 65 const v3Incentives = borrowApyType 66 ? v3Rates?.vIncentivesData || [] 67 : v3Rates?.aIncentivesData || []; 68 69 const [currentMarket, currentMarketData] = useRootStore( 70 useShallow((store) => [store.currentMarket, store.currentMarketData]) 71 ); 72 const theme = useTheme(); 73 const baseColorSecondary = disabled === undefined ? 'text.secondary' : 'text.muted'; 74 const baseColorPrimary = disabled === undefined ? 'text.primary' : 'text.muted'; 75 76 const loadingRates = v3Rates?.ltv === undefined && v3Rates?.liquidationThreshold === undefined; 77 78 return ( 79 <ListItem sx={{ display: 'flex', flexDirection: 'column', pl: 0 }}> 80 <Box 81 sx={{ 82 display: 'flex', 83 alignItems: 'center', 84 width: '100%', 85 pb: 2, 86 pt: 2.5, 87 }} 88 > 89 <ListColumn align="center" maxWidth={48} minWidth={48}> 90 <Box 91 sx={(theme) => ({ 92 border: `2px solid ${ 93 disabled !== undefined 94 ? theme.palette.action.disabled 95 : theme.palette.text.secondary 96 }`, 97 background: 98 disabled !== undefined 99 ? theme.palette.background.disabled 100 : checked 101 ? theme.palette.text.secondary 102 : theme.palette.background.paper, 103 width: 16, 104 height: 16, 105 borderRadius: '2px', 106 '&:hover': { 107 cursor: disabled !== undefined ? 'not-allowed' : 'pointer', 108 }, 109 display: 'flex', 110 alignItems: 'center', 111 justifyContent: 'center', 112 })} 113 onClick={disabled !== undefined ? undefined : onCheckboxClick} 114 > 115 {disabled === undefined && ( 116 <SvgIcon sx={{ fontSize: '14px', color: 'background.paper' }}> 117 <CheckIcon /> 118 </SvgIcon> 119 )} 120 </Box> 121 </ListColumn> 122 123 <ListColumn align="left"> 124 <Row> 125 <TokenIcon symbol={userReserve.reserve.iconSymbol} fontSize="large" /> 126 127 <Box sx={{ pl: '12px', overflow: 'hidden', display: 'flex' }}> 128 <Typography variant="subheader1" color={baseColorPrimary} noWrap sx={{ pr: 1 }}> 129 {userReserve.reserve.symbol} 130 </Typography> 131 {disabled !== undefined && ( 132 <MigrationDisabledTooltip 133 dashboardLink={ROUTES.dashboard + '/?marketName=' + currentMarket + '_v3'} 134 marketName={currentMarketData.marketTitle} 135 warningType={disabled} 136 isolatedV3={enteringIsolation} 137 /> 138 )} 139 </Box> 140 </Row> 141 </ListColumn> 142 </Box> 143 144 <Box sx={{ width: '100%', display: 'flex', flexDirection: 'column', gap: 2, pb: 4, pl: 12 }}> 145 <Box sx={{ display: 'flex', justifyContent: 'space-between' }}> 146 <Typography variant="description" color={baseColorSecondary}> 147 <Trans>Current v2 Balance</Trans> 148 </Typography> 149 <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}> 150 <Box sx={{ display: 'flex', alignItems: 'flex-end', mb: 0.5 }}> 151 <FormattedNumber value={amount} variant="secondary14" color={baseColorPrimary} /> 152 </Box> 153 <FormattedNumber 154 value={amountInUSD} 155 variant="secondary12" 156 color={baseColorSecondary} 157 symbolsColor={baseColorSecondary} 158 symbol="USD" 159 /> 160 </Box> 161 </Box> 162 163 <Box 164 sx={{ 165 display: 'flex', 166 alignItems: 'center', 167 justifyContent: 'space-between', 168 }} 169 > 170 <Typography variant="description" color={baseColorSecondary}> 171 <Trans>APY change</Trans> 172 </Typography> 173 174 <Box sx={{ display: 'flex' }}> 175 <IncentivesCard 176 value={v2APY} 177 symbol={userReserve.reserve.symbol} 178 incentives={v2Incentives} 179 variant="main14" 180 color={baseColorPrimary} 181 market={currentMarket} 182 /> 183 <SvgIcon sx={{ px: 1.5 }}> 184 <ArrowNarrowRightIcon 185 fontSize="14px" 186 color={ 187 disabled === undefined ? theme.palette.text.secondary : theme.palette.text.muted 188 } 189 /> 190 </SvgIcon> 191 <IncentivesCard 192 value={v3APY} 193 symbol={userReserve.reserve.symbol} 194 incentives={v3Incentives} 195 variant="main14" 196 color={baseColorPrimary} 197 market={currentMarket} 198 /> 199 </Box> 200 </Box> 201 202 {!!enableAsCollateral && ( 203 <Box 204 sx={{ 205 display: 'flex', 206 justifyContent: 'space-between', 207 alignItems: 'center', 208 }} 209 > 210 <Typography variant="description" color={baseColorSecondary}> 211 <Trans>Collateral change</Trans> 212 </Typography> 213 214 <Box sx={{ display: 'flex', alignItems: 'center' }}> 215 {userReserve.usageAsCollateralEnabledOnUser && 216 userReserve.reserve.reserveLiquidationThreshold !== '0' ? ( 217 <CheckRoundedIcon fontSize="small" color="success" /> 218 ) : ( 219 <NoData variant="main14" color={baseColorSecondary} /> 220 )} 221 222 <SvgIcon sx={{ px: 1.5 }}> 223 <ArrowNarrowRightIcon 224 fontSize="14px" 225 color={ 226 disabled === undefined ? theme.palette.text.secondary : theme.palette.text.muted 227 } 228 /> 229 </SvgIcon> 230 231 {showCollateralToggle ? ( 232 <MigrationListItemToggler 233 enableAsCollateral={enableAsCollateral} 234 enabledAsCollateral={enabledAsCollateral} 235 /> 236 ) : !enabledAsCollateral ? ( 237 <NoData variant="main14" color={baseColorSecondary} /> 238 ) : isIsolated ? ( 239 <Box 240 sx={{ 241 display: 'flex', 242 flexDirection: 'column', 243 justifyContent: 'center', 244 alignItems: 'center', 245 }} 246 > 247 <SvgIcon sx={{ color: 'warning.main', fontSize: '20px' }}> 248 <ExclamationCircleIcon /> 249 </SvgIcon> 250 <IsolatedEnabledBadge /> 251 </Box> 252 ) : ( 253 <CheckRoundedIcon fontSize="small" color="success" /> 254 )} 255 </Box> 256 </Box> 257 )} 258 259 {!!borrowApyType && ( 260 <Box 261 sx={{ 262 display: 'flex', 263 alignItems: 'center', 264 justifyContent: 'space-between', 265 }} 266 > 267 <Typography variant="description" color={baseColorSecondary}> 268 <Trans>APY type change</Trans> 269 </Typography> 270 <Box sx={{ display: 'flex' }}> 271 <Button 272 variant="outlined" 273 size="small" 274 sx={{ width: '50px', background: 'white' }} 275 disabled 276 > 277 <Typography variant="buttonS" color={baseColorPrimary}> 278 {borrowApyType} 279 </Typography> 280 </Button> 281 <SvgIcon sx={{ px: 1.5 }}> 282 <ArrowNarrowRightIcon 283 fontSize="14px" 284 color={ 285 disabled === undefined ? theme.palette.text.secondary : theme.palette.text.muted 286 } 287 /> 288 </SvgIcon> 289 <Button 290 variant="outlined" 291 size="small" 292 sx={{ width: '50px', background: 'white' }} 293 disabled 294 > 295 <Typography variant="buttonS" color={baseColorPrimary}> 296 Variable 297 </Typography> 298 </Button> 299 </Box> 300 </Box> 301 )} 302 303 {isSupplyList && ( 304 <Box 305 sx={{ 306 display: 'flex', 307 alignItems: 'center', 308 justifyContent: 'space-between', 309 }} 310 > 311 <Typography variant="description" color={baseColorSecondary}> 312 <Trans>Max LTV</Trans> 313 </Typography> 314 315 <Box sx={{ display: 'flex' }}> 316 {loadingRates ? ( 317 <NoData variant="main14" color="text.secondary" /> 318 ) : ( 319 <> 320 <FormattedNumber 321 value={userReserve.reserve.formattedBaseLTVasCollateral} 322 percent 323 variant="main14" 324 color={baseColorPrimary} 325 /> 326 <SvgIcon sx={{ px: 1.5 }}> 327 <ArrowNarrowRightIcon 328 fontSize="14px" 329 color={ 330 disabled === undefined 331 ? theme.palette.text.secondary 332 : theme.palette.text.muted 333 } 334 /> 335 </SvgIcon> 336 <FormattedNumber 337 value={v3Rates?.ltv || 0} 338 percent 339 variant="main14" 340 color={baseColorPrimary} 341 /> 342 </> 343 )} 344 </Box> 345 </Box> 346 )} 347 348 {!isSupplyList && ( 349 <Box 350 sx={{ 351 display: 'flex', 352 alignItems: 'center', 353 justifyContent: 'space-between', 354 }} 355 > 356 <Typography variant="description" color={baseColorSecondary}> 357 <Trans>Liquidation threshold</Trans> 358 </Typography> 359 360 <Box sx={{ display: 'flex' }}> 361 {loadingRates ? ( 362 <NoData variant="main14" color="text.secondary" /> 363 ) : ( 364 <> 365 <FormattedNumber 366 value={userReserve.reserve.formattedReserveLiquidationThreshold} 367 percent 368 variant="main14" 369 color={baseColorPrimary} 370 /> 371 <SvgIcon sx={{ px: 1.5 }}> 372 <ArrowNarrowRightIcon 373 fontSize="14px" 374 color={ 375 disabled === undefined 376 ? theme.palette.text.secondary 377 : theme.palette.text.muted 378 } 379 /> 380 </SvgIcon> 381 <FormattedNumber 382 value={v3Rates?.liquidationThreshold || 0} 383 percent 384 variant="main14" 385 color={baseColorPrimary} 386 /> 387 </> 388 )} 389 </Box> 390 </Box> 391 )} 392 </Box> 393 {userReserve.reserve.symbol === 'stETH' && ( 394 <Box sx={{ pl: '16px', width: '100%' }}> 395 <StETHMigrationWarning 396 v2Price={userReserve.reserve.priceInUSD} 397 v2Amount={amount} 398 v3Price={v3Rates?.priceInUSD} 399 /> 400 </Box> 401 )} 402 </ListItem> 403 ); 404 };