/ src / modules / migration / MigrationListMobileItem.tsx
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  };