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