Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions features/earn/shared/v2/vault-card/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './vault-card';
export * from './legacy-vault-card';
170 changes: 170 additions & 0 deletions features/earn/shared/v2/vault-card/legacy-vault-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import React from 'react';
import { Button } from '@lidofinance/lido-ui';

import {
CardWrapper,
CardOverlayLink,
CardHeader,
CardHeaderContent,
CardTitle,
CardDescription,
CardStats,
StatItem,
StatLabel,
StatValue,
CardDivider,
CardCta,
VaultIconWrapper,
CardTitleBadge,
ChevronsUpIcon,
StyledTooltip,
BadgeStyled,
TitleTextStyled,
} from './styles';
import { LocalLink } from 'shared/components/local-link';
import { EARN_PATH } from 'consts/urls';
import { EARN_VAULT_DEPOSIT_SLUG } from 'features/earn/consts';
import { FormatPercent } from 'shared/formatters/format-percent';
import { FormatLargeAmount } from 'shared/formatters/format-large-amount';
import { FormatToken } from 'shared/formatters/format-token';
import { Badge } from 'features/earn/shared/badge';
import { getTokenDecimals } from 'utils/token-decimals';
import { useConfig } from 'config/use-config';
import { InlineLoader } from '../../inline-loader';
import { VaultTip } from '../../vault-tip';

type VaultStats = {
tvl?: number | null;
apx?: number | null;
apxLabel: string;
isLoading?: boolean;
apxHint?: React.ReactNode;
};

type LegacyVaultPosition = {
sharesBalance?: bigint;
sharesSymbol: string;
isLoading?: boolean;
};

type LegacyVaultCardProps = {
title: string;
description?: string;
urlSlug: string;
stats: VaultStats;
ctaLabel: string;
position?: LegacyVaultPosition;
variant?: 'eth' | 'usd' | 'default';
illustration?: React.ReactNode;
depositLinkCallback?: () => void;
protectedBadgeTooltipText?: React.ReactNode;
};

export const LegacyVaultCard: React.FC<LegacyVaultCardProps> = ({
title,
description,
urlSlug,
stats,
position,
ctaLabel,
variant = 'default',
illustration,
depositLinkCallback,
protectedBadgeTooltipText,
}) => {
const isDeprecated = useConfig().externalConfig.earnVaults.find(
(vault) => vault.name === urlSlug,
)?.deprecated;

const depositHref = `${EARN_PATH}/${urlSlug}/${EARN_VAULT_DEPOSIT_SLUG}`;

return (
<CardWrapper $variant={variant} data-testid={`${urlSlug}-vault-card`}>
<CardOverlayLink
as={LocalLink}
href={depositHref}
onClick={depositLinkCallback}
data-testid={'open-vault-btn'}
aria-label={title}
/>
<CardHeader>
<CardHeaderContent>
<CardTitle>
<TitleTextStyled>{title}</TitleTextStyled>
{protectedBadgeTooltipText && (
<BadgeStyled>
<Badge
text="PROTECTED"
tooltipText={protectedBadgeTooltipText}
/>
</BadgeStyled>
)}
{isDeprecated && (
<StyledTooltip
title="Vault users can upgrade their tokens to the new unified EarnETH vault without withdrawal or downtime in rewards."
placement="bottom"
>
<CardTitleBadge variant="gradient" icon={<ChevronsUpIcon />}>
{' '}
Upgrading
</CardTitleBadge>
</StyledTooltip>
)}
</CardTitle>
<CardDescription>{description}</CardDescription>
</CardHeaderContent>
<VaultIconWrapper>{illustration}</VaultIconWrapper>
</CardHeader>
<CardDivider />
<CardStats>
<StatItem data-testid="apx-value">
<StatLabel>
{stats.apxLabel}
<VaultTip
placement="bottomLeft"
style={{ position: 'relative', zIndex: 20 }}
>
{stats.apxHint}
</VaultTip>
</StatLabel>
<StatValue $accent>
<InlineLoader isLoading={stats.isLoading} width={70}>
<FormatPercent value={stats.apx} decimals="percent" />
</InlineLoader>
</StatValue>
</StatItem>
<StatItem data-testid="tvl-value">
<StatLabel>TVL</StatLabel>
<StatValue>
<InlineLoader isLoading={stats.isLoading} width={70}>
<FormatLargeAmount amount={stats.tvl} />
</InlineLoader>
</StatValue>
</StatItem>
{!!position?.sharesBalance && (
<StatItem>
<StatLabel>My position</StatLabel>
<StatValue>
<InlineLoader width={32} isLoading={position.isLoading}>
<FormatToken
trimEllipsis
symbol={position.sharesSymbol}
decimals={getTokenDecimals(position.sharesSymbol)}
amount={position.sharesBalance}
fallback="—"
/>
</InlineLoader>
</StatValue>
</StatItem>
)}
</CardStats>
<CardCta>
<LocalLink href={depositHref} onClick={depositLinkCallback}>
<Button fullwidth variant="translucent">
{ctaLabel}
</Button>
</LocalLink>
</CardCta>
</CardWrapper>
);
};
11 changes: 11 additions & 0 deletions features/earn/shared/v2/vault-card/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,17 @@ export const StatValueIcon = styled.span`
height: 24px;
`;

export const StatSubValue = styled.span`
color: var(--lido-color-textSecondary);
font-size: ${({ theme }) => theme.fontSizesMap.xs}px;
font-weight: 400;
line-height: 24px;

${({ theme }) => theme.mediaQueries.md} {
display: none;
}
`;

export const CardCta = styled.div`
margin-top: 32px;
`;
Expand Down
42 changes: 26 additions & 16 deletions features/earn/shared/v2/vault-card/vault-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
VaultIconWrapper,
CardTitleBadge,
ChevronsUpIcon,
StatValueIcon,
StyledTooltip,
BadgeStyled,
TitleTextStyled,
Expand Down Expand Up @@ -45,12 +44,11 @@ type VaultStats = {
};

type VaultPosition = {
balance?: bigint;
claimable?: bigint;
pending?: Array<{ tokenSymbol: string; amount: bigint }>;
sharesBalance?: bigint;
sharesSymbol: string;
baseAmount?: bigint;
baseSymbol: string;
isLoading?: boolean;
symbol: string;
icon?: React.ReactNode;
};

type VaultCardProps = {
Expand Down Expand Up @@ -137,7 +135,7 @@ export const VaultCard: React.FC<VaultCardProps> = ({
<StatLabel>
{stats.apxLabel}
<VaultTip
placement="bottom"
placement="bottomLeft"
style={{ position: 'relative', zIndex: 20 }}
>
{stats.apxHint}
Expand All @@ -157,22 +155,34 @@ export const VaultCard: React.FC<VaultCardProps> = ({
</InlineLoader>
</StatValue>
</StatItem>
{!!position?.balance && (
{!!position?.sharesBalance && (
<StatItem>
<StatLabel>My position</StatLabel>
<StatLabel>
My deposit
<VaultTip
placement="bottomLeft"
style={{ position: 'relative', zIndex: 20 }}
>
You hold{' '}
<FormatToken
trimEllipsis
amount={position.sharesBalance}
symbol={position.sharesSymbol}
decimals={getTokenDecimals(position.sharesSymbol)}
/>
. Shown in {position.baseSymbol} at current conversion rates.
</VaultTip>
</StatLabel>
<StatValue>
<InlineLoader width={32} isLoading={position.isLoading}>
<FormatToken
trimEllipsis
symbol={position.symbol}
decimals={getTokenDecimals(position.symbol)}
amount={position.balance}
symbol={position.baseSymbol}
decimals={getTokenDecimals(position.baseSymbol)}
amount={position.baseAmount}
fallback="—"
data-testid={`${position.symbol}-position-amount`}
data-testid={`${position.sharesSymbol}-position-amount`}
/>
{position.icon && (
<StatValueIcon>{position.icon}</StatValueIcon>
)}
</InlineLoader>
</StatValue>
</StatItem>
Expand Down
32 changes: 28 additions & 4 deletions features/earn/shared/v2/vault-page/content/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,24 @@ export const TopSectionDescription = styled.p`
export const TopSectionStatsRow = styled.div`
display: flex;
gap: ${({ theme }) => theme.spaceMap.md}px;
max-width: 300px;

${({ theme }) => theme.mediaQueries.md} {
flex-direction: column;
}
`;

export const TopSectionStatItem = styled.div`
display: flex;
flex-direction: column;
flex: 0 0 160px;
gap: 4px;

&:first-child {
flex: 1;
${({ theme }) => theme.mediaQueries.md} {
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
flex: unset;
gap: ${({ theme }) => theme.spaceMap.sm}px;
}
`;

Expand All @@ -91,6 +99,22 @@ export const TopSectionStatLabel = styled.span`
line-height: 24px;
`;

export const TopSectionStatValueGroup = styled.div`
display: flex;
flex-direction: column;

${({ theme }) => theme.mediaQueries.md} {
align-items: flex-end;
}
`;

export const TopSectionStatSubValue = styled.span`
color: var(--lido-color-textSecondary);
font-size: ${({ theme }) => theme.fontSizesMap.xs}px;
font-weight: 400;
line-height: 24px;
`;

export const TopSectionStatValue = styled.span<{ $accent?: boolean }>`
font-weight: 700;
font-size: ${({ theme }) => theme.fontSizesMap.lg}px;
Expand All @@ -99,7 +123,7 @@ export const TopSectionStatValue = styled.span<{ $accent?: boolean }>`
$accent ? 'var(--lido-color-success)' : 'var(--lido-color-text)'};

${({ theme }) => theme.mediaQueries.md} {
font-size: ${({ theme }) => theme.fontSizesMap.sm}px;
font-size: ${({ theme }) => theme.fontSizesMap.xs}px;
line-height: 24px;
}
`;
Loading
Loading