diff --git a/packages/atlas/src/components/HotCreatorTokens/HotCreatorTokens.tsx b/packages/atlas/src/components/HotCreatorTokens/HotCreatorTokens.tsx new file mode 100644 index 0000000000..55f69ea959 --- /dev/null +++ b/packages/atlas/src/components/HotCreatorTokens/HotCreatorTokens.tsx @@ -0,0 +1,184 @@ +import styled from '@emotion/styled' +import BN from 'bn.js' +import { useMemo } from 'react' + +import { useGetMostInteractedEntityByTypeQuery } from '@/api/queries/__generated__/admin.generated' +import { useGetHotAndColdTokensQuery } from '@/api/queries/__generated__/creatorTokens.generated' +import { SvgEmptyStateIllustration } from '@/assets/illustrations' +import { JoyTokenIcon } from '@/components/JoyTokenIcon' +import { NumberFormat } from '@/components/NumberFormat' +import { Section } from '@/components/Section/Section' +import { TableProps } from '@/components/Table' +import { RightAlignedHeader } from '@/components/Table/Table.styles' +import { Text } from '@/components/Text' +import { SkeletonLoader } from '@/components/_loaders/SkeletonLoader' +import { absoluteRoutes } from '@/config/routes' +import { useMediaMatch } from '@/hooks/useMediaMatch' +import { sendUserInteraction } from '@/utils/interactions' + +import { PercentageChangeIndicator } from '../PercentageChangeIndicator' +import { + JoyAmountWrapper, + SkeletonChannelContainer, + StyledTable, +} from '../TopSellingChannelsTable/TopSellingChannelsTable.styles' +import { TokenInfo } from '../_crt/CrtPortfolioTable' + +const getColumns = (interval: number): TableProps['columns'] => [ + { + Header: '', + accessor: 'index', + width: 1, + }, + { + Header: 'TOKEN', + accessor: 'token', + width: 5, + }, + { + Header: () => PRICE % {interval}D, + accessor: 'priceChange', + width: 4, + }, + { + Header: () => PRICE, + accessor: 'price', + width: 4, + }, +] + +const tableEmptyState = { + title: 'No tokens found', + description: 'No top moves have been found.', + icon: , +} + +export const HotCreatorTokens = ({ interval, tableTitle }: { interval: number; tableTitle: string }) => { + const { data: topInteractedTokens } = useGetMostInteractedEntityByTypeQuery({ + variables: { + period: interval, + type: 'MarketplaceTokenEntry', + }, + }) + const { data, loading } = useGetHotAndColdTokensQuery({ + variables: { + periodDays: interval, + limit: 10, + where: { + id_in: topInteractedTokens?.getTopInteractedEnities.map((entity) => entity.entityId), + }, + }, + }) + + const columns = getColumns(interval) + const { tokensWithPriceChange: _tokensWithPriceChange } = data ?? {} + const tokensWithPriceChange = _tokensWithPriceChange?.filter((token) => token.pricePercentageChange != 0) + + const lgMatch = useMediaMatch('lg') + const mappedData = useMemo(() => { + return loading + ? Array.from({ length: 10 }, () => ({ + index: null, + token: ( + + + + + ), + weeklyPriceChange: ( + + + + ), + price: ( + + + + ), + channelId: null, + })) + : tokensWithPriceChange?.map((data, index) => ({ + index: ( + + #{index + 1}{' '} + + ), + price: ( + + } + variant="t200-strong" + as="p" + value={new BN(data.creatorToken.lastPrice ?? 0)} + margin={{ left: 1 }} + format="short" + withDenomination + denominationAlign="right" + /> + + ), + priceChange: ( + + + + ), + token: ( + + ), + channelId: data.creatorToken.channel?.channel.id, + })) ?? [] + }, [tokensWithPriceChange, loading]) + + if (!loading && !tokensWithPriceChange) { + return null + } + + return ( +
{ + if (tokensWithPriceChange?.[idx].creatorToken.id) { + sendUserInteraction('MarketplaceTokenEntry', tokensWithPriceChange[idx].creatorToken.id).catch( + () => undefined + ) + } + }} + getRowTo={(idx) => { + return absoluteRoutes.viewer.channel(mappedData[idx].channelId ?? '', { tab: 'Token' }) + }} + interactive + />, + ], + }} + /> + ) +} + +const IndexText = styled(Text)` + margin-left: -4px; +` diff --git a/packages/atlas/src/components/HotCreatorTokens/index.ts b/packages/atlas/src/components/HotCreatorTokens/index.ts new file mode 100644 index 0000000000..cbd51dc8c8 --- /dev/null +++ b/packages/atlas/src/components/HotCreatorTokens/index.ts @@ -0,0 +1 @@ +export * from './HotCreatorTokens' diff --git a/packages/atlas/src/components/TopCrtMovers/TopCrtMovers.tsx b/packages/atlas/src/components/TopCrtMovers/TopCrtMovers.tsx index 226debc010..67778a0d93 100644 --- a/packages/atlas/src/components/TopCrtMovers/TopCrtMovers.tsx +++ b/packages/atlas/src/components/TopCrtMovers/TopCrtMovers.tsx @@ -1,6 +1,6 @@ import styled from '@emotion/styled' import BN from 'bn.js' -import { useMemo } from 'react' +import { useMemo, useState } from 'react' import { useGetHotAndColdTokensQuery } from '@/api/queries/__generated__/creatorTokens.generated' import { SvgEmptyStateIllustration } from '@/assets/illustrations' @@ -53,13 +53,17 @@ const tableEmptyState = { } export const TopMovingTokens = ({ interval, tableTitle }: { interval: number; tableTitle: string }) => { + const [orderDesc, setOrderDesc] = useState(true) const { data, loading } = useGetHotAndColdTokensQuery({ variables: { periodDays: interval, + priceDesc: orderDesc, + limit: 10, }, }) const columns = getColumns(interval) - const { hotAndColdTokens } = data ?? {} + const { tokensWithPriceChange: _tokensWithPriceChange } = data ?? {} + const tokensWithPriceChange = _tokensWithPriceChange?.filter((token) => token.pricePercentageChange != 0) const lgMatch = useMediaMatch('lg') const mappedData = useMemo(() => { @@ -84,7 +88,7 @@ export const TopMovingTokens = ({ interval, tableTitle }: { interval: number; ta ), channelId: null, })) - : hotAndColdTokens?.map((data, index) => ({ + : tokensWithPriceChange?.map((data, index) => ({ index: ( #{index + 1}{' '} @@ -119,9 +123,9 @@ export const TopMovingTokens = ({ interval, tableTitle }: { interval: number; ta ), channelId: data.creatorToken.channel?.channel.id, })) ?? [] - }, [hotAndColdTokens, loading]) + }, [tokensWithPriceChange, loading]) - if (!loading && !hotAndColdTokens) { + if (!loading && !tokensWithPriceChange) { return null } @@ -132,6 +136,24 @@ export const TopMovingTokens = ({ interval, tableTitle }: { interval: number; ta type: 'title', title: tableTitle, }, + sort: { + type: 'toggle-button', + toggleButtonOptionTypeProps: { + onChange: (val) => setOrderDesc(val), + value: orderDesc, + type: 'options', + options: [ + { + label: 'Winners', + value: true, + }, + { + label: 'Losers', + value: false, + }, + ], + }, + }, }} contentProps={{ type: 'grid', @@ -149,8 +171,8 @@ export const TopMovingTokens = ({ interval, tableTitle }: { interval: number; ta data={mappedData} doubleColumn={lgMatch} onRowClick={(idx) => { - if (hotAndColdTokens?.[idx].creatorToken.id) { - sendUserInteraction('MarketplaceTokenEntry', hotAndColdTokens[idx].creatorToken.id).catch( + if (tokensWithPriceChange?.[idx].creatorToken.id) { + sendUserInteraction('MarketplaceTokenEntry', tokensWithPriceChange[idx].creatorToken.id).catch( () => undefined ) } diff --git a/packages/atlas/src/components/TopVolumeTokens/TopVolumeTokens.tsx b/packages/atlas/src/components/TopVolumeTokens/TopVolumeTokens.tsx index 15c8a6ba80..a79292abc1 100644 --- a/packages/atlas/src/components/TopVolumeTokens/TopVolumeTokens.tsx +++ b/packages/atlas/src/components/TopVolumeTokens/TopVolumeTokens.tsx @@ -34,7 +34,7 @@ const COLUMNS: TableProps['columns'] = [ width: 5, }, { - Header: () => 7D Volume, + Header: () => 30D Volume, accessor: 'ammVolume', width: 4, }, @@ -50,6 +50,8 @@ export const TopVolumeTokens = () => { const { data, loading } = useGetTopSellingTokensQuery({ variables: { periodDays: 30, + volumeDesc: true, + limit: 10, }, }) const { topSellingToken } = data ?? {} diff --git a/packages/atlas/src/components/_crt/AllTokensSection/AllTokensSection.tsx b/packages/atlas/src/components/_crt/AllTokensSection/AllTokensSection.tsx index fc5d9098ed..5e8170cf46 100644 --- a/packages/atlas/src/components/_crt/AllTokensSection/AllTokensSection.tsx +++ b/packages/atlas/src/components/_crt/AllTokensSection/AllTokensSection.tsx @@ -44,8 +44,8 @@ export const AllTokensSection = () => { cumulativeRevenue, ammVolume, liquidity, - weeklyLiqChange, - lastDayPriceChange, + liquidityChange, + priceChange, marketCap, channelId, }) => ({ @@ -61,8 +61,8 @@ export const AllTokensSection = () => { tokenTitle: symbol ?? 'N/A', ammVolume: new BN(ammVolume ?? 0), liquidity: liquidity ?? 0, - weeklyLiqChange: +(weeklyLiqChange ?? 0), - lastDayPriceChange: +(lastDayPriceChange ?? 0), + liquidityChange: +(liquidityChange ?? 0), + priceChange: +(priceChange ?? 0), }) ) ?? [] const currentSortingTableColumn = Object.entries(sortMappings).find(([, mapping]) => mapping.includes(orderBy)) diff --git a/packages/atlas/src/components/_crt/MarketplaceCrtTable/MarketplaceCrtTable.tsx b/packages/atlas/src/components/_crt/MarketplaceCrtTable/MarketplaceCrtTable.tsx index f6e37c83ca..eb7c3c4d68 100644 --- a/packages/atlas/src/components/_crt/MarketplaceCrtTable/MarketplaceCrtTable.tsx +++ b/packages/atlas/src/components/_crt/MarketplaceCrtTable/MarketplaceCrtTable.tsx @@ -33,9 +33,9 @@ export const tableLoadingData = Array.from({ length: 10 }, () => ({ const COLUMNS: TableProps['columns'] = [ { Header: 'Token', accessor: 'token', width: 2 }, { Header: 'Date created', accessor: 'createdAt', width: 2 }, - { Header: 'Price % 24h', accessor: 'dailyPriceChange', width: 2 }, + { Header: 'Price % 30d', accessor: 'priceChange', width: 2 }, { Header: 'Price', accessor: 'price', width: 2 }, - { Header: 'Liq % 7d', accessor: 'liquidityChange', width: 2 }, + { Header: 'Liq % 30d', accessor: 'liquidityChange', width: 2 }, { Header: 'Liquidity', accessor: 'liquidity', width: 2 }, { Header: 'Tranding vol.', accessor: 'tradingVolume', width: 2 }, { Header: 'Status', accessor: 'status', width: 1 }, @@ -54,9 +54,9 @@ export type MarketplaceToken = { totalRevenue: BN holdersNum: number channelId: string - lastDayPriceChange: number + priceChange: number ammVolume: BN - weeklyLiqChange: number + liquidityChange: number liquidity: number lastPrice: BN } @@ -86,9 +86,9 @@ export const MarketplaceCrtTable = ({ data, emptyState, isLoading, ...tableProps {formatDate(row.createdAt)} ), - dailyPriceChange: ( + priceChange: ( - + ), price: ( @@ -102,7 +102,7 @@ export const MarketplaceCrtTable = ({ data, emptyState, isLoading, ...tableProps ), liquidityChange: ( - + ), liquidity: (