From 4b812893a434e7ac50b14eeac0ef43f851ccaf3f Mon Sep 17 00:00:00 2001 From: Jared Vu Date: Thu, 21 Nov 2024 10:47:18 -0800 Subject: [PATCH] feat(fee-tier): Add card to display fee tier bonus (#1316) --- package.json | 2 +- pnpm-lock.yaml | 8 ++-- src/hooks/useSubaccount.tsx | 1 + src/pages/portfolio/Fees.tsx | 85 +++++++++++++++++++++++++++++------- 4 files changed, 75 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 0de0267e3..9222ac64b 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@datadog/browser-logs": "^5.23.3", "@dydxprotocol/v4-abacus": "1.13.34", "@dydxprotocol/v4-client-js": "1.12.2", - "@dydxprotocol/v4-localization": "^1.1.250", + "@dydxprotocol/v4-localization": "^1.1.251", "@dydxprotocol/v4-proto": "^7.0.0-dev.0", "@funkit/connect": "^3.4.9", "@emotion/is-prop-valid": "^1.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec66b99bd..09679f59a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,8 +36,8 @@ dependencies: specifier: 1.12.2 version: 1.12.2 '@dydxprotocol/v4-localization': - specifier: ^1.1.250 - version: 1.1.250 + specifier: ^1.1.251 + version: 1.1.251 '@dydxprotocol/v4-proto': specifier: ^7.0.0-dev.0 version: 7.0.0-dev.0 @@ -3320,8 +3320,8 @@ packages: - utf-8-validate dev: false - /@dydxprotocol/v4-localization@1.1.250: - resolution: {integrity: sha512-C3gZlYb4NBwDAU1z+1XB5M61+3NcTLR9HFqXcK77bBdhvGG85oSc2SaWUAMP9bRapCus6CEzODM56lIc36Ct+Q==} + /@dydxprotocol/v4-localization@1.1.251: + resolution: {integrity: sha512-chx83BUl1fgc2Gtp8FeMArkhAfB0/Ti9SNm0grYZYzYN87d+E3poYLvtWZkjDw4+WrnKFGTvMnc/EDlzYzcvSg==} dev: false /@dydxprotocol/v4-proto@7.0.0-dev.0: diff --git a/src/hooks/useSubaccount.tsx b/src/hooks/useSubaccount.tsx index bf0f5683d..a7b97ef28 100644 --- a/src/hooks/useSubaccount.tsx +++ b/src/hooks/useSubaccount.tsx @@ -1093,6 +1093,7 @@ const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: LocalWall // affiliates registerAffiliate, + referredBy: referredBy?.affiliateAddress, // vaults getVaultAccountInfo, diff --git a/src/pages/portfolio/Fees.tsx b/src/pages/portfolio/Fees.tsx index f81d2aa93..66734254c 100644 --- a/src/pages/portfolio/Fees.tsx +++ b/src/pages/portfolio/Fees.tsx @@ -1,6 +1,7 @@ import { useCallback, useMemo } from 'react'; import { Nullable } from '@dydxprotocol/v4-abacus'; +import { DoubleArrowUpIcon } from '@radix-ui/react-icons'; import { shallowEqual } from 'react-redux'; import styled from 'styled-components'; import tw from 'twin.macro'; @@ -11,6 +12,8 @@ import { FEE_DECIMALS } from '@/constants/numbers'; import { useBreakpoints } from '@/hooks/useBreakpoints'; import { useStringGetter } from '@/hooks/useStringGetter'; +import { useSubaccount } from '@/hooks/useSubaccount'; +import { useURLConfigs } from '@/hooks/useURLConfigs'; import breakpoints from '@/styles/breakpoints'; import { layoutMixins } from '@/styles/layoutMixins'; @@ -18,6 +21,7 @@ import { layoutMixins } from '@/styles/layoutMixins'; import { AttachedExpandingSection } from '@/components/ContentSection'; import { ContentSectionHeader } from '@/components/ContentSectionHeader'; import { Details } from '@/components/Details'; +import { Link } from '@/components/Link'; import { Output, OutputType } from '@/components/Output'; import { ColumnDef, Table } from '@/components/Table'; import { Tag, TagSize } from '@/components/Tag'; @@ -27,6 +31,8 @@ import { useAppSelector } from '@/state/appTypes'; import { getFeeTiers } from '@/state/configsSelectors'; import { isTruthy } from '@/lib/isTruthy'; +import { MustBigNumber } from '@/lib/numbers'; +import { truncateAddress } from '@/lib/wallet'; const MARKET_SHARE_PERCENTAGE_FRACTION_DIGITS = 1; @@ -41,6 +47,8 @@ export const Fees = () => { const userFeeTier = useAppSelector(getUserFeeTier, shallowEqual); const userStats = useAppSelector(getUserStats, shallowEqual); const feeTiers = useAppSelector(getFeeTiers, shallowEqual); + const { referredBy } = useSubaccount(); + const { affiliateProgramFaq } = useURLConfigs(); const volume = useMemo(() => { if (userStats.makerVolume30D !== undefined && userStats.takerVolume30D !== undefined) { @@ -49,6 +57,11 @@ export const Fees = () => { return null; }, [userStats]); + const hasReceivedFeeTierBonus = + userFeeTier === '3' && + referredBy !== undefined && + MustBigNumber(volume).lt(feeTiers?.[2]?.volume ?? 0); + const AdditionalConditions = useCallback( (conditions: { totalShare: Nullable; @@ -93,21 +106,58 @@ export const Fees = () => { {isNotTablet && }
- <$FeesDetails - layout="grid" - items={[ - { - key: 'volume', - label: ( - <$CardLabel> - {stringGetter({ key: STRING_KEYS.TRAILING_VOLUME })} - {stringGetter({ key: STRING_KEYS._30D })} - - ), - value: , - }, - ]} - /> +
+ <$FeesDetails + layout="grid" + hasReceivedFeeTierBonus={hasReceivedFeeTierBonus} + items={[ + { + key: 'volume', + label: ( + <$CardLabel> + {stringGetter({ key: STRING_KEYS.TRAILING_VOLUME })} + {stringGetter({ key: STRING_KEYS._30D })} + + ), + value: , + }, + hasReceivedFeeTierBonus && { + key: 'bonus', + label: ( + <$CardLabel> + {stringGetter({ + key: STRING_KEYS.YOUR_FEE_TIER, + params: { + TIER: ( + + {userFeeTier}{' '} + + + ), + }, + })} + + ), + value: ( + + {stringGetter({ + key: STRING_KEYS.GIFTED_FEE_TIER_BONUS, + params: { + AFFILIATE: truncateAddress(referredBy), + }, + })}{' '} + + {stringGetter({ key: STRING_KEYS.LEARN_MORE })} → + + + ), + }, + ].filter(isTruthy)} + /> +
<$FeeTable label={stringGetter({ key: STRING_KEYS.FEE_TIERS })} @@ -230,8 +280,9 @@ const $AdditionalConditionsText = styled.span` } `; -const $FeesDetails = styled(Details)` +const $FeesDetails = styled(Details)<{ hasReceivedFeeTierBonus?: boolean }>` gap: 1rem; + --details-grid-numColumns: ${({ hasReceivedFeeTierBonus }) => (hasReceivedFeeTierBonus ? 2 : 1)}; @media ${breakpoints.notTablet} { margin: 0 1.25rem; @@ -244,6 +295,7 @@ const $FeesDetails = styled(Details)` > div { max-width: 16rem; + align-content: normal; gap: 1rem; @@ -271,6 +323,7 @@ const $TextRow = styled.div` `; const $CardLabel = styled($TextRow)` + height: 1.5rem; font: var(--font-small-book); color: var(--color-text-1);