From 1af036200941ca6849d9cada33de3c286c791223 Mon Sep 17 00:00:00 2001 From: Samer Valente Date: Mon, 4 Dec 2023 23:19:18 -0300 Subject: [PATCH] add participants table --- src/components/NavBar/index.tsx | 12 +- .../Tokens/TokenTable/ParticipantsRow.tsx | 490 ++++++++++++++++++ .../Tokens/TokenTable/ParticipantsTable.tsx | 124 +++++ .../Tokens/TokenTable/mocked_participants.tsx | 292 +++++++++++ src/components/Tokens/state.ts | 9 + src/pages/Explore/index.tsx | 7 +- src/pages/Landing/index.tsx | 4 +- src/pages/Participants/index.tsx | 224 ++++++++ src/pages/Participants/redirects.tsx | 40 ++ src/pages/Pool/PoolCard.tsx | 7 +- src/pages/Pool/mocks.ts | 162 ++++++ src/pages/RouteDefinitions.tsx | 5 + src/pages/TokenDetails/index.tsx | 1 - 13 files changed, 1360 insertions(+), 17 deletions(-) create mode 100644 src/components/Tokens/TokenTable/ParticipantsRow.tsx create mode 100644 src/components/Tokens/TokenTable/ParticipantsTable.tsx create mode 100644 src/components/Tokens/TokenTable/mocked_participants.tsx create mode 100644 src/pages/Participants/index.tsx create mode 100644 src/pages/Participants/redirects.tsx diff --git a/src/components/NavBar/index.tsx b/src/components/NavBar/index.tsx index 89fe117d6..d98c4970a 100644 --- a/src/components/NavBar/index.tsx +++ b/src/components/NavBar/index.tsx @@ -19,7 +19,6 @@ import { useIsNavSearchInputVisible } from '../../nft/hooks/useIsNavSearchInputV import { Bag } from './Bag' import Blur from './Blur' import { ChainSelector } from './ChainSelector' -import { SearchBar } from './SearchBar' import * as styles from './style.css' const Nav = styled.nav` @@ -90,6 +89,9 @@ export const PageTabs = () => { Pools + + Participantes + {/* @@ -139,14 +141,10 @@ const Navbar = ({ blur }: { blur: boolean }) => { {...(isNavSearchInputVisible && { display: 'flex', })} - > - - + > - - - + {isNftPage && sellPageState !== ProfilePageStateType.LISTING && } {!isNftPage && ( diff --git a/src/components/Tokens/TokenTable/ParticipantsRow.tsx b/src/components/Tokens/TokenTable/ParticipantsRow.tsx new file mode 100644 index 000000000..8d893681a --- /dev/null +++ b/src/components/Tokens/TokenTable/ParticipantsRow.tsx @@ -0,0 +1,490 @@ +/* eslint-disable import/no-unused-modules */ +import { Trans } from '@lingui/macro' +import { InterfaceEventName } from '@uniswap/analytics-events' +import { sendAnalyticsEvent } from 'analytics' +import { CircleLogoImage } from 'components/AccountDrawer/MiniPortfolio/PortfolioLogo' +import { useInfoExplorePageEnabled } from 'featureFlags/flags/infoExplore' +import { SparklineMap, TopToken } from 'graphql/data/TopTokens' +import { supportedChainIdFromGQLChain, validateUrlChainParam } from 'graphql/data/util' +import { useAtomValue } from 'jotai/utils' +import { ForwardedRef, forwardRef } from 'react' +import { CSSProperties, ReactNode } from 'react' +import { Link, useParams } from 'react-router-dom' +import styled, { css } from 'styled-components' +import { BREAKPOINTS } from 'theme' +import { ClickableStyle } from 'theme/components' +import { NumberType, useFormatter } from 'utils/formatNumbers' + +import { + LARGE_MEDIA_BREAKPOINT, + MAX_WIDTH_MEDIA_BREAKPOINT, + MEDIUM_MEDIA_BREAKPOINT, + SMALL_MEDIA_BREAKPOINT, +} from '../constants' +import { LoadingBubble } from '../loading' +import { filterStringAtom, filterTimeAtom, ParticipantsSortMethod } from '../state' +import { DeltaArrow, DeltaText } from '../TokenDetails/Delta' + +const Cell = styled.div` + display: flex; + align-items: center; + justify-content: center; +` +const StyledTokenRow = styled.div<{ + first?: boolean + last?: boolean + $loading?: boolean +}>` + background-color: transparent; + display: grid; + font-size: 16px; + grid-template-columns: 1fr 7fr 4fr 4fr 4fr 4fr 5fr; + line-height: 24px; + max-width: ${MAX_WIDTH_MEDIA_BREAKPOINT}; + min-width: 390px; + ${({ first, last }) => css` + height: ${first || last ? '72px' : '64px'}; + padding-top: ${first ? '8px' : '0px'}; + padding-bottom: ${last ? '8px' : '0px'}; + `} + padding-left: 12px; + padding-right: 12px; + transition: ${({ + theme: { + transition: { duration, timing }, + }, + }) => css`background-color ${duration.medium} ${timing.ease}`}; + width: 100%; + transition-duration: ${({ theme }) => theme.transition.duration.fast}; + + &:hover { + ${({ $loading, theme }) => + !$loading && + css` + background-color: ${theme.deprecated_hoverDefault}; + `} + ${({ last }) => + last && + css` + border-radius: 0px 0px 8px 8px; + `} + } + + @media only screen and (max-width: ${MAX_WIDTH_MEDIA_BREAKPOINT}) { + grid-template-columns: 1fr 6.5fr 4.5fr 4.5fr 4.5fr 4.5fr 1.7fr; + } + + @media only screen and (max-width: ${LARGE_MEDIA_BREAKPOINT}) { + grid-template-columns: 1fr 7.5fr 4.5fr 4.5fr 4.5fr 1.7fr; + } + + @media only screen and (max-width: ${MEDIUM_MEDIA_BREAKPOINT}) { + grid-template-columns: 1fr 10fr 5fr 5fr 1.2fr; + } + + @media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) { + grid-template-columns: 2fr 3fr; + min-width: unset; + border-bottom: 0.5px solid ${({ theme }) => theme.surface2}; + + :last-of-type { + border-bottom: none; + } + } +` + +const ClickableContent = styled.div<{ gap?: number }>` + display: flex; + ${({ gap }) => gap && `gap: ${gap}px`}; + text-decoration: none; + color: ${({ theme }) => theme.neutral1}; + align-items: center; + cursor: pointer; +` +const ClickableName = styled(ClickableContent)` + gap: 12px; + max-width: 100%; +` +const StyledHeaderRow = styled(StyledTokenRow)` + border-bottom: 1px solid; + border-color: ${({ theme }) => theme.surface3}; + border-radius: 8px 8px 0px 0px; + color: ${({ theme }) => theme.neutral2}; + font-size: 14px; + height: 48px; + line-height: 16px; + padding: 0px 12px; + width: 100%; + justify-content: center; + + &:hover { + background-color: transparent; + } + + @media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) { + justify-content: space-between; + } +` + +const ListNumberCell = styled(Cell)<{ header: boolean }>` + color: ${({ theme }) => theme.neutral2}; + min-width: 32px; + font-size: 14px; + + @media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) { + display: none; + } +` +const DataCell = styled(Cell)<{ sortable: boolean }>` + justify-content: flex-end; + min-width: 80px; + user-select: ${({ sortable }) => (sortable ? 'none' : 'unset')}; + transition: ${({ + theme: { + transition: { duration, timing }, + }, + }) => css`background-color ${duration.medium} ${timing.ease}`}; +` +const TvlCell = styled(DataCell)` + padding-right: 8px; + @media only screen and (max-width: ${MEDIUM_MEDIA_BREAKPOINT}) { + display: none; + } +` +const NameCell = styled(Cell)` + justify-content: flex-start; + padding: 0px 8px; + min-width: 240px; + gap: 8px; + + @media only screen and (max-width: ${BREAKPOINTS.xs}px) { + min-width: 200px; + } +` +const PriceCell = styled(DataCell)` + padding-right: 8px; +` +const PercentChangeCell = styled(DataCell)` + padding-right: 8px; + @media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) { + display: none; + } +` +const PercentChangeInfoCell = styled(Cell)` + display: none; + + @media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) { + display: flex; + gap: 3px; + justify-content: flex-end; + color: ${({ theme }) => theme.neutral2}; + font-size: 12px; + line-height: 16px; + } +` +const PriceInfoCell = styled(Cell)` + justify-content: flex-end; + flex: 1; + + @media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) { + flex-direction: column; + align-items: flex-end; + } +` + +const HeaderCellWrapper = styled.span<{ onClick?: () => void }>` + align-items: center; + cursor: ${({ onClick }) => (onClick ? 'pointer' : 'unset')}; + display: flex; + gap: 4px; + justify-content: flex-end; + width: 100%; + + &:hover { + ${ClickableStyle} + } +` +const SparkLineCell = styled(Cell)` + padding: 0px 24px; + min-width: 120px; + + @media only screen and (max-width: ${MAX_WIDTH_MEDIA_BREAKPOINT}) { + display: none; + } +` +const SparkLine = styled(Cell)` + width: 124px; + height: 42px; +` +const StyledLink = styled(Link)` + text-decoration: none; +` +const TokenInfoCell = styled(Cell)` + gap: 8px; + line-height: 24px; + font-size: 16px; + max-width: inherit; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + @media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) { + justify-content: flex-start; + flex-direction: column; + gap: 0px; + width: max-content; + font-weight: 535; + } +` +const TokenName = styled.div` + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 100%; +` +const TokenSymbol = styled(Cell)` + color: ${({ theme }) => theme.neutral2}; + text-transform: uppercase; + + @media only screen and (max-width: ${SMALL_MEDIA_BREAKPOINT}) { + font-size: 12px; + height: 16px; + justify-content: flex-start; + width: 100%; + } +` +const VolumeCell = styled(DataCell)` + padding-right: 8px; + @media only screen and (max-width: ${LARGE_MEDIA_BREAKPOINT}) { + display: none; + } +` +const SmallLoadingBubble = styled(LoadingBubble)` + width: 25%; +` +const MediumLoadingBubble = styled(LoadingBubble)` + width: 65%; +` +const LongLoadingBubble = styled(LoadingBubble)` + width: 90%; +` +const IconLoadingBubble = styled(LoadingBubble)` + border-radius: 50%; + width: 24px; +` +export const SparkLineLoadingBubble = styled(LongLoadingBubble)` + height: 4px; +` + +const InfoIconContainer = styled.div` + width: 16px; + margin-left: 2px; + display: flex; + align-items: center; + cursor: help; +` + +export const HEADER_DESCRIPTIONS: Record = { + [ParticipantsSortMethod.PRICE]: undefined, + [ParticipantsSortMethod.PERCENT_CHANGE]: undefined, + [ParticipantsSortMethod.TOTAL_VALUE_LOCKED]: ( + + Total value locked (TVL) is the aggregate amount of the asset available across all T-DREX liquidity pools. + + ), + [ParticipantsSortMethod.FULLY_DILUTED_VALUATION]: ( + + Fully diluted valuation (FDV) is the market capitalization of an asset if maximum token supply were in + circulation. + + ), + [ParticipantsSortMethod.VOLUME]: ( + Volume is the amount of the asset that has been traded on T-DREX during the selected time frame. + ), +} + +/* Get singular header cell for header row */ +function HeaderCell({ + category, +}: { + category: ParticipantsSortMethod // TODO: change this to make it work for trans +}) { + return {category} +} + +/* Token Row: skeleton row component */ +function TokenRow({ + header, + listNumber, + tokenInfo, + price, + percentChange, + tvl, + volume, + sparkLine, + ...rest +}: { + first?: boolean + header: boolean + listNumber: ReactNode + $loading?: boolean + tvl: ReactNode + price: ReactNode + percentChange: ReactNode + sparkLine?: ReactNode + tokenInfo: ReactNode + volume: ReactNode + last?: boolean + style?: CSSProperties +}) { + const rowCells = ( + <> + {listNumber} + {tokenInfo} + + {price} + + + {percentChange} + + + {tvl} + + {sparkLine} + + ) + if (header) return {rowCells} + return {rowCells} +} + +/* Header Row: top header row component for table */ +export function HeaderRow() { + return ( + Nome do participante} + price={} + percentChange={} + tvl={} + volume={} + sparkLine={null} + /> + ) +} + +/* Loading State: row component with loading bubbles */ +export function LoadingRow(props: { first?: boolean; last?: boolean }) { + return ( + } + $loading + tokenInfo={ + <> + + + + } + price={} + percentChange={} + tvl={} + volume={} + sparkLine={} + {...props} + /> + ) +} + +interface LoadedRowProps { + tokenListIndex: number + tokenListLength: number + token: NonNullable | any + sparklineMap?: SparklineMap | null + sortRank?: number | null +} + +/* Loaded State: row component with token information */ +export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef) => { + const { formatFiatPrice, formatNumber, formatDelta } = useFormatter() + + const { tokenListIndex, tokenListLength, token, sortRank } = props + const filterString = useAtomValue(filterStringAtom) + + const filterNetwork = validateUrlChainParam(useParams<{ chainName?: string }>().chainName?.toUpperCase()) + const chainId = supportedChainIdFromGQLChain(filterNetwork) + const timePeriod = useAtomValue(filterTimeAtom) + const delta = token.market?.pricePercentChange?.value + const formattedDelta = formatDelta(delta) + + const exploreTokenSelectedEventProperties = { + chain_id: chainId, + token_address: token.address, + token_symbol: token.symbol, + token_list_index: tokenListIndex, + token_list_rank: sortRank, + token_list_length: tokenListLength, + time_frame: timePeriod, + search_token_address_input: filterString, + } + + // A simple 0 price indicates the price is not currently available from the api + const price = token.market?.price?.value === 0 ? '-' : formatFiatPrice({ price: token.market?.price?.value }) + + const isInfoExplorePageEnabled = useInfoExplorePageEnabled() + + // TODO: currency logo sizing mobile (32px) vs. desktop (24px) + return ( +
+ + sendAnalyticsEvent(InterfaceEventName.EXPLORE_TOKEN_ROW_CLICKED, exploreTokenSelectedEventProperties) + } + > + + + + {token.name} + {token.symbol} + + + } + price={ + + + {token.profile} + + + {formattedDelta} + + + + } + percentChange={ + + + + } + tvl={{token.localCurrency}} + volume={ + + {formatNumber({ + input: token.market?.volume?.value, + type: NumberType.FiatTokenStats, + })} + + } + first={tokenListIndex === 0} + last={tokenListIndex === tokenListLength - 1} + /> + +
+ ) +}) + +LoadedRow.displayName = 'LoadedRow' diff --git a/src/components/Tokens/TokenTable/ParticipantsTable.tsx b/src/components/Tokens/TokenTable/ParticipantsTable.tsx new file mode 100644 index 000000000..4a6658c64 --- /dev/null +++ b/src/components/Tokens/TokenTable/ParticipantsTable.tsx @@ -0,0 +1,124 @@ +/* eslint-disable import/no-unused-modules */ +import { Trans } from '@lingui/macro' +import { PAGE_SIZE, useTopTokens } from 'graphql/data/TopTokens' +import { validateUrlChainParam } from 'graphql/data/util' +import { ReactNode, useState } from 'react' +import { AlertTriangle } from 'react-feather' +import { useParams } from 'react-router-dom' +import styled from 'styled-components' + +import { MAX_WIDTH_MEDIA_BREAKPOINT } from '../constants' +import { mocked_participants } from './mocked_participants' +import { HeaderRow, LoadedRow, LoadingRow } from './ParticipantsRow' + +const GridContainer = styled.div` + display: flex; + flex-direction: column; + max-width: ${MAX_WIDTH_MEDIA_BREAKPOINT}; + background-color: ${({ theme }) => theme.surface1}; + + margin-left: auto; + margin-right: auto; + border-radius: 12px; + justify-content: center; + align-items: center; + border: 1px solid ${({ theme }) => theme.surface3}; +` + +const TokenDataContainer = styled.div` + display: flex; + flex-direction: column; + gap: 4px; + height: 100%; + width: 100%; +` + +const NoTokenDisplay = styled.div` + display: flex; + justify-content: center; + width: 100%; + height: 60px; + color: ${({ theme }) => theme.neutral2}; + font-size: 16px; + font-weight: 535; + align-items: center; + padding: 0px 28px; + gap: 8px; +` + +function NoTokensState({ message }: { message: ReactNode }) { + return ( + + + {message} + + ) +} + +const LoadingRows = ({ rowCount }: { rowCount: number }) => ( + <> + {Array(rowCount) + .fill(null) + .map((_, index) => { + return + })} + +) + +function LoadingTokenTable({ rowCount = PAGE_SIZE }: { rowCount?: number }) { + return ( + + + + + + + ) +} + +export default function ParticipantsTable() { + const chainName = validateUrlChainParam(useParams<{ chainName?: string }>().chainName) + const [setLoadingTokens] = useState(false) + const { tokens: originalTokens, tokenSortRank, loadingTokens, sparklines } = useTopTokens(chainName) + const tokens = mocked_participants + + /* loading and error state */ + + if (loadingTokens && !tokens) { + return + } else if (!tokens) { + return ( + + + An error occurred loading tokens. Please try again. + + } + /> + ) + } else if (tokens?.length === 0) { + return No tokens found} /> + } else { + return ( + + + + {tokens.map( + (token, index) => + token?.address && ( + + ) + )} + + + ) + } +} diff --git a/src/components/Tokens/TokenTable/mocked_participants.tsx b/src/components/Tokens/TokenTable/mocked_participants.tsx new file mode 100644 index 000000000..32a2b0da9 --- /dev/null +++ b/src/components/Tokens/TokenTable/mocked_participants.tsx @@ -0,0 +1,292 @@ +/* eslint-disable import/no-unused-modules */ +export const mocked_participants = [ + { + __typename: 'Token', + id: 'VG9rZW46RVRIRVJFVU1fMHg4MzkwYTFkYTA3ZTM3NmVmN2FkZDRiZTg1OWJhNzRmYjgzYWEwMmQ1', + name: 'Tesouro Nacional', + profile: 'Administrador', + countryImg: 'https://i.im.ge/2023/12/04/C4zQBT.image-76.png', + standard: 'ERC20', + symbol: 'TN', + chain: 'ETHEREUM', + address: '0x8390a1da07e376ef7add4be859ba74fb83aa02d5', + localCurrency: 'BRL', + market: { + id: 'VG9rZW5NYXJrZXQ6RVRIRVJFVU1fMHg4MzkwYTFEQTA3RTM3NmVmN2FEZDRCZTg1OUJBNzRGYjgzYUEwMkQ1X1VTRA==', + price: { + __typename: 'Amount', + id: 'QW1vdW50OjAuMDE3Mzk4MjkwODU3OTY4MzM2X1VTRA==', + value: 166.1, + currency: 'USD', + }, + pricePercentChange: { + __typename: 'Amount', + id: 'QW1vdW50OjQxLjE0OTY0MjkxOTUzMDg3Nl9VU0Q=', + currency: 'USD', + value: 41.149642919530876, + }, + totalValueLocked: { + __typename: 'Amount', + id: 'QW1vdW50OjQwMzg3MDIuNjkxNDM1NTM4X1VTRA==', + value: 4038702.691435538, + currency: 'USD', + }, + volume: { + __typename: 'Amount', + id: 'QW1vdW50OjE5NDQ3OTA3LjE1ODg0NjJfVVNE', + value: 19447907.1588462, + currency: 'USD', + }, + __typename: 'TokenMarket', + }, + project: { + id: 'VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4ODM5MGExZGEwN2UzNzZlZjdhZGQ0YmU4NTliYTc0ZmI4M2FhMDJkNV9Hcm9r', + logoUrl: 'https://i.im.ge/2023/12/05/CeEbdr.WhatsApp-Image-2023-12-04-at-21-53-33.jpg', + __typename: 'TokenProject', + description: + 'The "Prefixed Treasury 2026" is an investment with maturity on 01/01/2026, yielding R$1,000 per security at maturity. It is ideal for medium-term investments without semi-annual interest, and can be redeemed in advance at market value.', + }, + }, + { + id: 'VG9rZW46RVRIRVJFVU1fMHgxYmJmMjVlNzFlYzQ4Yjg0ZDc3MzgwOWI0YmE1NWI2ZjRiZTk0NmZi', + name: 'Bradesco', + profile: 'Comprador', + chain: 'ETHEREUM', + address: '0x1BBf25e71EC48B84d773809B4bA55B6F4bE946Fb', + countryImg: 'https://i.im.ge/2023/12/04/C4zQBT.image-76.png', + localCurrency: 'BRL', + symbol: 'BRAD', + standard: 'ERC20', + market: { + id: 'VG9rZW5NYXJrZXQ6RVRIRVJFVU1fMHgxQkJmMjVlNzFFQzQ4Qjg0ZDc3MzgwOUI0YkE1NUI2RjRiRTk0NkZiX1VTRA==', + totalValueLocked: { + id: 'QW1vdW50OjIxMzI0OTYyLjA4NzkwNjY4X1VTRA==', + value: 2.132496208790668e7, + currency: 'USD', + __typename: 'Amount', + }, + price: { + id: 'QW1vdW50OjAuMzgyNzY1MDM0Mjg3OTA4MTVfVVNE', + value: 5.2, + currency: 'USD', + __typename: 'Amount', + }, + pricePercentChange: { + id: 'QW1vdW50Oi03LjQyNjcxNTE0NTI5OTEwN19VU0Q=', + currency: 'USD', + value: -7.426715145299107, + __typename: 'Amount', + }, + volume: { + id: 'QW1vdW50OjIxNjc1My4yNjMwNzk2NzMwNV9VU0Q=', + value: 216753.26307967305, + currency: 'USD', + __typename: 'Amount', + }, + __typename: 'TokenMarket', + }, + project: { + id: 'VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4MWJiZjI1ZTcxZWM0OGI4NGQ3NzM4MDliNGJhNTViNmY0YmU5NDZmYl9Wb3c=', + logoUrl: 'https://i.im.ge/2023/12/05/CeCRG8.WhatsApp-Image-2023-12-04-at-21-49-58.jpg', + __typename: 'TokenProject', + }, + __typename: 'Token', + }, + { + id: 'VG9rZW46RVRIRVJFVU1fMHgyMjYwZmFjNWU1NTQyYTc3M2FhNDRmYmNmZWRmN2MxOTNiYzJjNTk5', + name: 'Banco do Brasil', + chain: 'ETHEREUM', + profile: 'Criador do Pool', + countryImg: 'https://i.im.ge/2023/12/04/C4zQBT.image-76.png', + address: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', + symbol: 'BB', + standard: 'ERC20', + localCurrency: 'BRL', + market: { + id: 'VG9rZW5NYXJrZXQ6RVRIRVJFVU1fMHgyMjYwRkFDNUU1NTQyYTc3M0FhNDRmQkNmZURmN0MxOTNiYzJDNTk5X1VTRA==', + totalValueLocked: { + id: 'QW1vdW50OjE3NDY2Mjg2MC41MjI3NjUzN19VU0Q=', + value: 1.7466286052276537e8, + currency: 'USD', + __typename: 'Amount', + }, + price: { + id: 'QW1vdW50OjM3MjgwLjgxNjgzNDI1ODg0X1VTRA==', + value: 2877.98, + currency: 'USD', + __typename: 'Amount', + }, + pricePercentChange: { + id: 'QW1vdW50Oi0xLjE1NDE4MzAxMTkyODgyN19VU0Q=', + currency: 'USD', + value: -1.154183011928827, + __typename: 'Amount', + }, + volume: { + id: 'QW1vdW50OjE5NzQ4NjY3LjI1Mjg5OTE3X1VTRA==', + value: 1.974866725289917e7, + currency: 'USD', + __typename: 'Amount', + }, + __typename: 'TokenMarket', + }, + project: { + id: 'VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4MjI2MGZhYzVlNTU0MmE3NzNhYTQ0ZmJjZmVkZjdjMTkzYmMyYzU5OV9XcmFwcGVkIEJpdGNvaW4=', + logoUrl: 'https://i.im.ge/2023/12/05/CeE3Jm.WhatsApp-Image-2023-12-04-at-21-49-58-1.jpg', + __typename: 'TokenProject', + description: + "This title expires on 03/01/2029. Recommended for those who want to make medium-term investments Title with daily profitability linked to the economy's interest rate (Selic rate). This means that if the Selic rate increases, your profitability increases and if the Selic rate decreases, your profitability decreases. As it does not pay half-yearly interest, it is more interesting for those who can let their money earn until the investment matures.", + }, + __typename: 'Token', + }, + { + __typename: 'Token', + id: 'VG9rZW46RVRIRVJFVU1fMHg1MTQ5MTA3NzFhZjljYTY1NmFmODQwZGZmODNlODI2NGVjZjk4NmNh', + standard: 'ERC20', + symbol: 'ITAU', + name: 'Banco do Itaú', + profile: 'Gerador de liquidez', + slug: 'tesouro-prefixado-2029', + localCurrency: 'BRL', + countryImg: 'https://i.im.ge/2023/12/04/C4zQBT.image-76.png', + address: '0x514910771af9ca656af840dff83e8264ecf986ca', + chain: 'ETHEREUM', + market: { + id: 'VG9rZW5NYXJrZXQ6RVRIRVJFVU1fMHg1MTQ5MTA3NzFBRjlDYTY1NmFmODQwZGZmODNFODI2NEVjRjk4NkNBX1VTRA==', + price: { + __typename: 'Amount', + id: 'QW1vdW50OjE0LjY2NzE3Njg1Njk2OTI5Ml9VU0Q=', + value: 120.78, + currency: 'USD', + }, + pricePercentChange: { + __typename: 'Amount', + id: 'QW1vdW50Oi0wLjgyOTgwMjYzMzU5Mjg5NjdfVVNE', + currency: 'USD', + value: -0.8298026335928967, + }, + totalValueLocked: { + __typename: 'Amount', + id: 'QW1vdW50OjI5NjU5MjI1Ljc0MTIyOTcxN19VU0Q=', + value: 29659225.741229717, + currency: 'USD', + }, + volume: { + __typename: 'Amount', + id: 'QW1vdW50OjE2MzUzMzE3LjA0MzEwMTMxX1VTRA==', + value: 16353317.04310131, + currency: 'USD', + }, + __typename: 'TokenMarket', + }, + project: { + id: 'VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4NTE0OTEwNzcxYWY5Y2E2NTZhZjg0MGRmZjgzZTgyNjRlY2Y5ODZjYV9DaGFpbmxpbms', + logoUrl: 'https://i.im.ge/2023/12/05/CeExEf.WhatsApp-Image-2023-12-04-at-21-49-58-2.jpg', + __typename: 'TokenProject', + standard: 'ERC20', + symbol: 'ETH', + description: + 'This title expires on 01/01/2029. Recommended for those who want to make medium-term investments. Prefixed title, that is, at the time of purchase, you already know exactly how much you will receive in the future (always R$1,000 per unit of title). It is more interesting for those who can let their money earn until the investment matures, as it does not pay half-yearly interest. In case of early redemption, the National Treasury guarantees its repurchase at market values.', + }, + }, + { + __typename: 'Token', + id: 'VG9rZW46RVRIRVJFVU1fMHg1MTQ5MTA3NzFhZjljYTY1NmFmODQwZGZmODNlODI2NGVjZjk4NmNh', + standard: 'ERC20', + symbol: 'ANC', + name: 'ANCAP', + profile: 'Comprador', + slug: 'tesouro-prefixado-2029', + localCurrency: 'ARS', + countryImg: 'https://i.im.ge/2023/11/27/CTwFfS.argentina-icon.png', + address: '0x514910771af9ca656af840dff83e8264ecf986ca', + chain: 'ETHEREUM', + market: { + id: 'VG9rZW5NYXJrZXQ6RVRIRVJFVU1fMHg1MTQ5MTA3NzFBRjlDYTY1NmFmODQwZGZmODNFODI2NEVjRjk4NkNBX1VTRA==', + price: { + __typename: 'Amount', + id: 'QW1vdW50OjE0LjY2NzE3Njg1Njk2OTI5Ml9VU0Q=', + value: 120.78, + currency: 'USD', + }, + pricePercentChange: { + __typename: 'Amount', + id: 'QW1vdW50Oi0wLjgyOTgwMjYzMzU5Mjg5NjdfVVNE', + currency: 'USD', + value: -0.8298026335928967, + }, + totalValueLocked: { + __typename: 'Amount', + id: 'QW1vdW50OjI5NjU5MjI1Ljc0MTIyOTcxN19VU0Q=', + value: 29659225.741229717, + currency: 'USD', + }, + volume: { + __typename: 'Amount', + id: 'QW1vdW50OjE2MzUzMzE3LjA0MzEwMTMxX1VTRA==', + value: 16353317.04310131, + currency: 'USD', + }, + __typename: 'TokenMarket', + }, + project: { + id: 'VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4NTE0OTEwNzcxYWY5Y2E2NTZhZjg0MGRmZjgzZTgyNjRlY2Y5ODZjYV9DaGFpbmxpbms', + logoUrl: 'https://i.im.ge/2023/12/05/Cebc4G.ob-thqUt-400x400.jpg', + __typename: 'TokenProject', + standard: 'ERC20', + symbol: 'ETH', + description: + 'This title expires on 01/01/2029. Recommended for those who want to make medium-term investments. Prefixed title, that is, at the time of purchase, you already know exactly how much you will receive in the future (always R$1,000 per unit of title). It is more interesting for those who can let their money earn until the investment matures, as it does not pay half-yearly interest. In case of early redemption, the National Treasury guarantees its repurchase at market values.', + }, + }, + { + __typename: 'Token', + id: 'VG9rZW46RVRIRVJFVU1fMHg1MTQ5MTA3NzFhZjljYTY1NmFmODQwZGZmODNlODI2NGVjZjk4NmNh', + standard: 'ERC20', + symbol: 'ANC', + name: 'Bancolômbia', + profile: 'Vendedor', + slug: 'tesouro-prefixado-2029', + localCurrency: 'COP', + countryImg: 'https://i.im.ge/2023/12/04/C4zXyL.image-83.png', + address: '0x514910771af9ca656af840dff83e8264ecf986ca', + chain: 'ETHEREUM', + market: { + id: 'VG9rZW5NYXJrZXQ6RVRIRVJFVU1fMHg1MTQ5MTA3NzFBRjlDYTY1NmFmODQwZGZmODNFODI2NEVjRjk4NkNBX1VTRA==', + price: { + __typename: 'Amount', + id: 'QW1vdW50OjE0LjY2NzE3Njg1Njk2OTI5Ml9VU0Q=', + value: 120.78, + currency: 'USD', + }, + pricePercentChange: { + __typename: 'Amount', + id: 'QW1vdW50Oi0wLjgyOTgwMjYzMzU5Mjg5NjdfVVNE', + currency: 'USD', + value: -0.8298026335928967, + }, + totalValueLocked: { + __typename: 'Amount', + id: 'QW1vdW50OjI5NjU5MjI1Ljc0MTIyOTcxN19VU0Q=', + value: 29659225.741229717, + currency: 'USD', + }, + volume: { + __typename: 'Amount', + id: 'QW1vdW50OjE2MzUzMzE3LjA0MzEwMTMxX1VTRA==', + value: 16353317.04310131, + currency: 'USD', + }, + __typename: 'TokenMarket', + }, + project: { + id: 'VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4NTE0OTEwNzcxYWY5Y2E2NTZhZjg0MGRmZjgzZTgyNjRlY2Y5ODZjYV9DaGFpbmxpbms', + logoUrl: 'https://i.im.ge/2023/12/05/CebbYL.images.jpg', + __typename: 'TokenProject', + standard: 'ERC20', + symbol: 'ETH', + description: + 'This title expires on 01/01/2029. Recommended for those who want to make medium-term investments. Prefixed title, that is, at the time of purchase, you already know exactly how much you will receive in the future (always R$1,000 per unit of title). It is more interesting for those who can let their money earn until the investment matures, as it does not pay half-yearly interest. In case of early redemption, the National Treasury guarantees its repurchase at market values.', + }, + }, +] diff --git a/src/components/Tokens/state.ts b/src/components/Tokens/state.ts index e79f0a884..bdfc38a7c 100644 --- a/src/components/Tokens/state.ts +++ b/src/components/Tokens/state.ts @@ -1,3 +1,4 @@ +/* eslint-disable import/no-unused-modules */ import { TimePeriod } from 'graphql/data/util' import { atom, useAtom } from 'jotai' import { atomWithReset } from 'jotai/utils' @@ -11,6 +12,14 @@ export enum TokenSortMethod { VOLUME = 'Volume', } +export enum ParticipantsSortMethod { + FULLY_DILUTED_VALUATION = 'FDV', + PRICE = 'Perfil', + PERCENT_CHANGE = 'País', + TOTAL_VALUE_LOCKED = 'Moeda local', + VOLUME = 'Volume', +} + export const filterStringAtom = atomWithReset('') export const filterTimeAtom = atom(TimePeriod.DAY) export const sortMethodAtom = atom(TokenSortMethod.VOLUME) diff --git a/src/pages/Explore/index.tsx b/src/pages/Explore/index.tsx index eb9b4908f..f910151a7 100644 --- a/src/pages/Explore/index.tsx +++ b/src/pages/Explore/index.tsx @@ -5,9 +5,6 @@ import { Trace } from 'analytics' import { AutoRow } from 'components/Row' import { MAX_WIDTH_MEDIA_BREAKPOINT, MEDIUM_MEDIA_BREAKPOINT } from 'components/Tokens/constants' import { filterStringAtom } from 'components/Tokens/state' -import NetworkFilter from 'components/Tokens/TokenTable/NetworkFilter' -import SearchBar from 'components/Tokens/TokenTable/SearchBar' -import TimeSelector from 'components/Tokens/TokenTable/TimeSelector' import TokenTable from 'components/Tokens/TokenTable/TokenTable' import { MouseoverTooltip } from 'components/Tooltip' import { useInfoExplorePageEnabled } from 'featureFlags/flags/infoExplore' @@ -215,7 +212,7 @@ const Explore = ({ initialTab }: { initialTab?: ExploreTab }) => { })} )} - {isInfoExplorePageEnabled ? ( + {/* {isInfoExplorePageEnabled ? ( @@ -235,7 +232,7 @@ const Explore = ({ initialTab }: { initialTab?: ExploreTab }) => { - )} + )} */} {isInfoExplorePageEnabled ? : } diff --git a/src/pages/Landing/index.tsx b/src/pages/Landing/index.tsx index d8e9aa543..40324ecde 100644 --- a/src/pages/Landing/index.tsx +++ b/src/pages/Landing/index.tsx @@ -365,8 +365,8 @@ export default function Landing() { Buy, sell, and explore assets ) : ( - Resolvemos o problema de liquidez e flexibilidade dos títulos públicos federais, permitindo o acesso - de empresas de qualquer lugar do mundo e de outros países. + Resolvemos o problema de liquidez e flexibilidade para aquisição de títulos públicos federais, + permitindo o acesso para instituições de qualquer lugar do mundo. )} diff --git a/src/pages/Participants/index.tsx b/src/pages/Participants/index.tsx new file mode 100644 index 000000000..a87003773 --- /dev/null +++ b/src/pages/Participants/index.tsx @@ -0,0 +1,224 @@ +/* eslint-disable import/no-unused-modules */ +import { Trans } from '@lingui/macro' +import { BrowserEvent, InterfaceElementName, InterfacePageName, SharedEventName } from '@uniswap/analytics-events' +import { TraceEvent } from 'analytics' +import { Trace } from 'analytics' +import { AutoRow } from 'components/Row' +import { MAX_WIDTH_MEDIA_BREAKPOINT, MEDIUM_MEDIA_BREAKPOINT } from 'components/Tokens/constants' +import { filterStringAtom } from 'components/Tokens/state' +import ParticipantsTable from 'components/Tokens/TokenTable/ParticipantsTable' +import TokenTable from 'components/Tokens/TokenTable/TokenTable' +import { MouseoverTooltip } from 'components/Tooltip' +import { useInfoExplorePageEnabled } from 'featureFlags/flags/infoExplore' +import { useResetAtom } from 'jotai/utils' +import { useEffect, useMemo, useState } from 'react' +import { useLocation, useNavigate } from 'react-router-dom' +import styled, { css } from 'styled-components' +import { ThemedText } from 'theme/components' + +import { useExploreParams } from './redirects' + +const ExploreContainer = styled.div` + width: 100%; + min-width: 320px; + padding: 68px 12px 0px; + + @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) { + padding-top: 48px; + } + + @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) { + padding-top: 20px; + } +` +const TitleContainer = styled.div` + margin-bottom: 32px; + max-width: ${MAX_WIDTH_MEDIA_BREAKPOINT}; + margin-left: auto; + margin-right: auto; + display: flex; +` +const NavWrapper = styled.div<{ isInfoExplorePageEnabled: boolean }>` + display: flex; + max-width: ${MAX_WIDTH_MEDIA_BREAKPOINT}; + margin: 0 auto; + margin-bottom: ${({ isInfoExplorePageEnabled }) => (isInfoExplorePageEnabled ? '16px' : '20px')}; + color: ${({ theme }) => theme.neutral3}; + flex-direction: row; + + @media only screen and (max-width: ${MEDIUM_MEDIA_BREAKPOINT}) { + flex-direction: column; + gap: 8px; + } + + ${({ isInfoExplorePageEnabled }) => + isInfoExplorePageEnabled && + css` + @media screen and (max-width: ${({ theme }) => `${theme.breakpoint.lg}px`}) { + flex-direction: column; + gap: 16px; + } + `}; +` +const TabBar = styled(AutoRow)` + gap: 24px; + @media screen and (max-width: ${({ theme }) => theme.breakpoint.md}px) { + gap: 16px; + } +` +const TabItem = styled(ThemedText.HeadlineMedium)<{ active?: boolean }>` + align-items: center; + color: ${({ theme, active }) => (active ? theme.neutral1 : theme.neutral2)}; + cursor: pointer; + transition: ${({ theme }) => `${theme.transition.duration.medium} ${theme.transition.timing.ease} color`}; +` +const FiltersContainer = styled.div<{ isInfoExplorePageEnabled: boolean }>` + display: flex; + gap: 8px; + height: 40px; + + @media only screen and (max-width: ${MEDIUM_MEDIA_BREAKPOINT}) { + ${({ isInfoExplorePageEnabled }) => !isInfoExplorePageEnabled && 'order: 2;'} + } + + @media screen and (max-width: ${({ theme }) => theme.breakpoint.md}px) { + ${({ isInfoExplorePageEnabled }) => isInfoExplorePageEnabled && 'justify-content: space-between;'} + } +` +const DropdownFilterContainer = styled(FiltersContainer)<{ isInfoExplorePageEnabled: boolean }>` + ${({ isInfoExplorePageEnabled }) => + isInfoExplorePageEnabled + ? css` + @media screen and (max-width: ${({ theme }) => theme.breakpoint.md}px) { + justify-content: flex-start; + } + ` + : css` + @media only screen and (max-width: ${MEDIUM_MEDIA_BREAKPOINT}) { + justify-content: flex-start; + } + `}; +` +const SearchContainer = styled(FiltersContainer)<{ isInfoExplorePageEnabled: boolean }>` + ${({ isInfoExplorePageEnabled }) => !isInfoExplorePageEnabled && 'margin-left: 8px;'} + width: 100%; + + @media only screen and (max-width: ${MEDIUM_MEDIA_BREAKPOINT}) { + ${({ isInfoExplorePageEnabled }) => !isInfoExplorePageEnabled && 'order: 1; margin: 0px;'} + } + + @media screen and (max-width: ${({ theme }) => theme.breakpoint.md}px) { + ${({ isInfoExplorePageEnabled }) => isInfoExplorePageEnabled && 'justify-content: flex-end;'} + } +` +export enum ExploreTab { + Tokens = 'tokens', + Pools = 'pools', + Transactions = 'transactions', +} + +interface Page { + title: React.ReactNode + key: ExploreTab + component: () => JSX.Element + loggingElementName: string +} +const Pages: Array = [ + { + title: Tokens, + key: ExploreTab.Tokens, + component: TokenTable, + loggingElementName: InterfaceElementName.EXPLORE_TOKENS_TAB, + }, + { + title: Pools, + key: ExploreTab.Pools, + component: TokenTable, + loggingElementName: InterfaceElementName.EXPLORE_POOLS_TAB, + }, + { + title: Transactions, + key: ExploreTab.Transactions, + component: TokenTable, + loggingElementName: InterfaceElementName.EXPLORE_TRANSACTIONS_TAB, + }, +] + +const Explore = ({ initialTab }: { initialTab?: ExploreTab }) => { + const resetFilterString = useResetAtom(filterStringAtom) + const location = useLocation() + const navigate = useNavigate() + + const initialKey: number = useMemo(() => { + const key = initialTab && Pages.findIndex((page) => page.key === initialTab) + if (!key || key === -1) return 0 + return key + }, [initialTab]) + const [currentTab, setCurrentTab] = useState(initialKey) + const isInfoExplorePageEnabled = useInfoExplorePageEnabled() + + // to allow backward navigation between tabs + const { tab } = useExploreParams() + useEffect(() => { + const tabIndex = Pages.findIndex((page) => page.key === tab) + if (tabIndex !== -1) { + setCurrentTab(tabIndex) + } + }, [tab]) + + useEffect(() => { + resetFilterString() + }, [location, resetFilterString]) + + const { component: Page, key: currentKey } = Pages[currentTab] + + return ( + + + {/* TODO(WEB-2749 & WEB-2750): add graphs to explore page */} + {!isInfoExplorePageEnabled && ( + + This table contains the top tokens by Uniswap volume, sorted based on your input.} + placement="bottom" + > + + Participantes + + + + )} + + {isInfoExplorePageEnabled && ( + + {Pages.map(({ title, loggingElementName, key }, index) => { + const handleNavItemClick = () => { + setCurrentTab(index) + navigate(`/explore/${key}`) + } + return ( + + + {title} + + + ) + })} + + )} + + {isInfoExplorePageEnabled ? : } + + + ) +} + +export default Explore diff --git a/src/pages/Participants/redirects.tsx b/src/pages/Participants/redirects.tsx new file mode 100644 index 000000000..13db1a80f --- /dev/null +++ b/src/pages/Participants/redirects.tsx @@ -0,0 +1,40 @@ +/* eslint-disable import/no-unused-modules */ +import { Navigate, useParams } from 'react-router-dom' + +import Explore, { ExploreTab } from '.' + +// useParams struggles to distinguish between /explore/:chainId and /explore/:tab +export function useExploreParams(): { + tab?: ExploreTab + chainName?: string + tokenAddress?: string +} { + const { tab, chainName, tokenAddress } = useParams<{ tab: string; chainName: string; tokenAddress: string }>() + const exploreTabs = Object.values(ExploreTab) + if (tab && !chainName && exploreTabs.includes(tab as ExploreTab)) { + // /explore/:tab + return { tab: tab as ExploreTab, chainName: undefined, tokenAddress } + } else if (tab && !chainName) { + // /explore/:chainName + return { tab: ExploreTab.Tokens, chainName: tab, tokenAddress } + } else if (!tab && !chainName) { + // legacy /tokens + return { tab: ExploreTab.Tokens, chainName: undefined, tokenAddress: undefined } + } else { + // /explore/:tab/:chainName + return { tab: tab as ExploreTab, chainName, tokenAddress } + } +} +export default function RedirectExplore() { + const { tab, chainName, tokenAddress } = useExploreParams() + if (tab && chainName && tokenAddress) { + return + } else if (chainName && tokenAddress) { + return + } else if (tab && chainName) { + return + } else if (chainName) { + return + } + return +} diff --git a/src/pages/Pool/PoolCard.tsx b/src/pages/Pool/PoolCard.tsx index dd73fc4c7..ca56ca2cd 100644 --- a/src/pages/Pool/PoolCard.tsx +++ b/src/pages/Pool/PoolCard.tsx @@ -20,6 +20,7 @@ const SqueezedPoolPairs = ({ firstPair, secondPair }: { firstPair: string; secon const PoolCardsContainer = styled.div` display: grid; + justify-content: center; grid-template-columns: 1fr; gap: 20px; @@ -28,7 +29,7 @@ const PoolCardsContainer = styled.div` } @media (min-width: 1200px) { - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(4, 1fr); } ` @@ -158,6 +159,7 @@ const PoolCardFooter = styled.div` ` export default function PoolCards({ activePoolType }: { activePoolType: PoolsType }) { + console.log(activePoolType) const pools = activePoolType !== 'all' ? pools_mock.filter((pool) => pool.public_title_infos.type === activePoolType) : pools_mock @@ -184,7 +186,7 @@ export default function PoolCards({ activePoolType }: { activePoolType: PoolsTyp
{pool.APR}% - +
${pool.liquidity}M @@ -194,6 +196,7 @@ export default function PoolCards({ activePoolType }: { activePoolType: PoolsTyp

{pool.public_title_infos.description}

+
))} diff --git a/src/pages/Pool/mocks.ts b/src/pages/Pool/mocks.ts index e44d54a12..8811a11b4 100644 --- a/src/pages/Pool/mocks.ts +++ b/src/pages/Pool/mocks.ts @@ -55,6 +55,168 @@ const pools_mock = [ liquidity: 1.7, APR: 23, }, + { + id: 4, + public_title_infos: { + id: 1, + name: 'TESOURO PREFIXADO 2026', + type: 'ltn', + icon: 'https://i.im.ge/2023/11/27/CQmBj4.Group-11.png', + description: + 'O "Tesouro Prefixado 2026"é um investimento com vencimento em 01/01/2026, rendendo R$ 1.000 por título no vencimento. É ideal para investimentos de médio prazo sem juros semestrais, e pode ser resgatado antecipadamente pelo valor de mercado.', + }, + cbdc_infos: { + id: 1, + name: 'Hong Kong', + icon: 'https://i.im.ge/2023/12/05/Cec8cC.image-83.png', + }, + liquidity: 1.2, + APR: 32, + }, + { + id: 5, + public_title_infos: { + id: 1, + name: 'TESOURO PREFIXADO 2029', + type: 'ltn', + icon: 'https://i.im.ge/2023/11/27/CQm4OD.Group-14.png', + description: + 'O "Tesouro Prefixado 2029" é um título que vence em 01/01/2029. Indicado para aqueles que querem realizar investimentos de médio prazo. Título prefixado, ou seja, no momento da compra, você já sabe exatamente quanto irá receber no futuro.', + }, + cbdc_infos: { + id: 1, + name: 'Japão', + icon: 'https://i.im.ge/2023/12/05/Cec8cC.image-83.png', + }, + liquidity: 1.4, + APR: 25, + }, + { + id: 6, + public_title_infos: { + id: 1, + name: 'TESOURO SELIC 2026', + type: 'ltf', + icon: 'https://i.im.ge/2023/11/27/CQmGWC.Group-12.png', + description: + 'Investimento com vencimento em 01/03/2026. Indicado para aqueles que querem realizar investimentos de médio prazo Título com rentabilidade diária vinculada à taxa de juros da economia (taxa Selic).', + }, + cbdc_infos: { + id: 1, + name: 'Real Digital', + icon: 'https://i.im.ge/2023/12/04/C4zlzG.image-74.png', + }, + liquidity: 1.7, + APR: 23, + }, + { + id: 7, + public_title_infos: { + id: 1, + name: 'TESOURO PREFIXADO 2026', + type: 'ltn', + icon: 'https://i.im.ge/2023/11/27/CQmBj4.Group-11.png', + description: + 'O "Tesouro Prefixado 2026"é um investimento com vencimento em 01/01/2026, rendendo R$ 1.000 por título no vencimento. É ideal para investimentos de médio prazo sem juros semestrais, e pode ser resgatado antecipadamente pelo valor de mercado.', + }, + cbdc_infos: { + id: 1, + name: 'Hong Kong', + icon: 'https://i.im.ge/2023/12/04/C4zosc.image-69.png', + }, + liquidity: 1.2, + APR: 32, + }, + { + id: 8, + public_title_infos: { + id: 1, + name: 'TESOURO PREFIXADO 2029', + type: 'ltn', + icon: 'https://i.im.ge/2023/11/27/CQm4OD.Group-14.png', + description: + 'O "Tesouro Prefixado 2029" é um título que vence em 01/01/2029. Indicado para aqueles que querem realizar investimentos de médio prazo. Título prefixado, ou seja, no momento da compra, você já sabe exatamente quanto irá receber no futuro.', + }, + cbdc_infos: { + id: 1, + name: 'Japão', + icon: 'https://i.im.ge/2023/12/04/C4zlzG.image-74.png', + }, + liquidity: 1.4, + APR: 25, + }, + { + id: 9, + public_title_infos: { + id: 1, + name: 'TESOURO SELIC 2026', + type: 'ltf', + icon: 'https://i.im.ge/2023/11/27/CQmGWC.Group-12.png', + description: + 'Investimento com vencimento em 01/03/2026. Indicado para aqueles que querem realizar investimentos de médio prazo Título com rentabilidade diária vinculada à taxa de juros da economia (taxa Selic).', + }, + cbdc_infos: { + id: 1, + name: 'Real Digital', + icon: 'https://i.im.ge/2023/12/04/C4zosc.image-69.png', + }, + liquidity: 1.7, + APR: 23, + }, + { + id: 10, + public_title_infos: { + id: 1, + name: 'TESOURO PREFIXADO 2026', + type: 'ltn', + icon: 'https://i.im.ge/2023/11/27/CQmBj4.Group-11.png', + description: + 'O "Tesouro Prefixado 2026"é um investimento com vencimento em 01/01/2026, rendendo R$ 1.000 por título no vencimento. É ideal para investimentos de médio prazo sem juros semestrais, e pode ser resgatado antecipadamente pelo valor de mercado.', + }, + cbdc_infos: { + id: 1, + name: 'Hong Kong', + icon: 'https://i.im.ge/2023/12/04/C4zosc.image-69.png', + }, + liquidity: 1.2, + APR: 32, + }, + { + id: 11, + public_title_infos: { + id: 1, + name: 'TESOURO PREFIXADO 2029', + type: 'ltn', + icon: 'https://i.im.ge/2023/11/27/CQm4OD.Group-14.png', + description: + 'O "Tesouro Prefixado 2029" é um título que vence em 01/01/2029. Indicado para aqueles que querem realizar investimentos de médio prazo. Título prefixado, ou seja, no momento da compra, você já sabe exatamente quanto irá receber no futuro.', + }, + cbdc_infos: { + id: 1, + name: 'Japão', + icon: 'https://i.im.ge/2023/12/04/C4zosc.image-69.png', + }, + liquidity: 1.4, + APR: 25, + }, + { + id: 12, + public_title_infos: { + id: 1, + name: 'TESOURO SELIC 2026', + type: 'ltf', + icon: 'https://i.im.ge/2023/11/27/CQmGWC.Group-12.png', + description: + 'Investimento com vencimento em 01/03/2026. Indicado para aqueles que querem realizar investimentos de médio prazo Título com rentabilidade diária vinculada à taxa de juros da economia (taxa Selic).', + }, + cbdc_infos: { + id: 1, + name: 'Real Digital', + icon: 'https://i.im.ge/2023/12/04/C4zlzG.image-74.png', + }, + liquidity: 1.7, + APR: 23, + }, ] // eslint-disable-next-line import/no-unused-modules diff --git a/src/pages/RouteDefinitions.tsx b/src/pages/RouteDefinitions.tsx index 0ff735ad1..5b56d96d4 100644 --- a/src/pages/RouteDefinitions.tsx +++ b/src/pages/RouteDefinitions.tsx @@ -32,6 +32,7 @@ const RemoveLiquidity = lazy(() => import('pages/RemoveLiquidity')) const RemoveLiquidityV3 = lazy(() => import('pages/RemoveLiquidity/V3')) const TokenDetails = lazy(() => import('pages/TokenDetails')) const Vote = lazy(() => import('pages/Vote')) +const Participants = lazy(() => import('pages/Participants')) // this is the same svg defined in assets/images/blue-loader.svg // it is defined here because the remote asset may not have had time to load when this file is executing @@ -114,6 +115,10 @@ export const routes: RouteDefinition[] = [ getElement: () => , enabled: (args) => Boolean(args.infoExplorePageEnabled), }), + createRouteDefinition({ + path: '/participants', + getElement: () => , + }), createRouteDefinition({ path: '/explore/tokens/:chainName/:tokenAddress', getElement: () => , diff --git a/src/pages/TokenDetails/index.tsx b/src/pages/TokenDetails/index.tsx index 60ccf49d2..c25b02c07 100644 --- a/src/pages/TokenDetails/index.tsx +++ b/src/pages/TokenDetails/index.tsx @@ -1,6 +1,5 @@ import TokenDetails from 'components/Tokens/TokenDetails' import { TokenDetailsPageSkeleton } from 'components/Tokens/TokenDetails/Skeleton' -import TokenDetailsV2 from 'components/Tokens/TokenDetails/v2' import { NATIVE_CHAIN_ID } from 'constants/tokens' import { useTokenPriceQuery, useTokenQuery } from 'graphql/data/__generated__/types-and-hooks' import { TimePeriod, toHistoryDuration, validateUrlChainParam } from 'graphql/data/util'