Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: markets page watchlist #7795

Merged
merged 5 commits into from
Sep 25, 2024
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
7 changes: 6 additions & 1 deletion src/assets/translations/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -2591,8 +2591,13 @@
"markets": {
"recommended": "Recommended",
"watchlist": "My Watchlist",
"categoriesTabTitle": "Categories",
"marketsBody": "Nunc vel efficitur ligula, vel sagittis est. Morbi et sapien a ligula venenatis consequat.",
"watchlistEmpty": {
"emptyTitle": "No assets in Watchlist",
"emptyBody": "It appears you haven't starred any assets just yet. Start adding assets to your watchlist now to track them!"
},
"emptyTitle": "No assets found",
"emptyBody": "No assets were found with the current filter. Try adjusting your selected chain to see more assets.",
"categories": {
"oneClickDefiAssets": {
"title": "One Click DeFi Assets"
Expand Down
1 change: 1 addition & 0 deletions src/components/AssetHeader/AssetHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export const AssetHeader: React.FC<AssetHeaderProps> = ({ assetId, accountId })
{name} {`(${symbol}${asset.id ? ` ${middleEllipsis(asset.id)}` : ''})`}
</Heading>

<WatchAssetButton assetId={assetId} />
kaladinlight marked this conversation as resolved.
Show resolved Hide resolved
<IconButton
as={Link}
isExternal
Expand Down
14 changes: 7 additions & 7 deletions src/components/AssetHeader/WatchAssetButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ type WatchAssetButtonProps = {
export const WatchAssetButton: React.FC<WatchAssetButtonProps> = ({ assetId }) => {
const appDispatch = useAppDispatch()
const isAssetIdWatched = useAppSelector(state => selectIsAssetIdWatched(state, assetId))
const handleToggleWatchAsset = useCallback(() => {
if (isAssetIdWatched) {
appDispatch(preferences.actions.removeWatchedAssetId(assetId))
} else {
appDispatch(preferences.actions.addWatchedAssetId(assetId))
}
}, [appDispatch, assetId, isAssetIdWatched])
const handleToggleWatchAsset: React.MouseEventHandler<HTMLButtonElement> = useCallback(
e => {
e.stopPropagation()
kaladinlight marked this conversation as resolved.
Show resolved Hide resolved
appDispatch(preferences.actions.toggleWatchedAssetId(assetId))
},
[appDispatch, assetId],
)
return (
<IconButton
onClick={handleToggleWatchAsset}
Expand Down
20 changes: 3 additions & 17 deletions src/pages/Markets/MarketsHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ export const MarketsHeader = () => {
path: '/markets/watchlist',
color: 'blue',
},
{
label: 'markets.categoriesTabTitle',
path: '/markets/categories',
color: 'blue',
},
]
}, [])

Expand All @@ -43,15 +38,6 @@ export const MarketsHeader = () => {
history.location.pathname.match(/\/markets\/category\/(?<category>[\w]+)/)?.groups?.category,
[history.location.pathname],
)
const headingCopy = useMemo(() => {
if (maybeCategory) return `markets.categories.${maybeCategory}.title`
return 'navBar.markets'
}, [maybeCategory])

const subtitleCopy = useMemo(() => {
if (maybeCategory) return `markets.categories.${maybeCategory}.subtitle`
return 'markets.marketsBody'
}, [maybeCategory])

return (
<>
Expand All @@ -61,7 +47,7 @@ export const MarketsHeader = () => {
<PageBackButton onBack={handleBack} />
</PageHeader.Left>
<PageHeader.Middle>
<PageHeader.Title>{translate(headingCopy)}</PageHeader.Title>
<PageHeader.Title>{translate('navBar.markets')}</PageHeader.Title>
</PageHeader.Middle>
</PageHeader>
</Display.Mobile>
Expand All @@ -77,8 +63,8 @@ export const MarketsHeader = () => {
>
<Display.Desktop>
<Stack>
<Heading>{translate(headingCopy)}</Heading>
<Text color='text.subtle' translation={subtitleCopy} />
<Heading>{translate('navBar.markets')}</Heading>
<Text color='text.subtle' translation='markets.marketsBody' />
</Stack>
</Display.Desktop>
</Container>
Expand Down
10 changes: 7 additions & 3 deletions src/pages/Markets/MarketsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import { Redirect, Route, Switch, useRouteMatch } from 'react-router'
import { Redirect, Route, Switch, useHistory, useRouteMatch } from 'react-router'

import { Category } from './Category'
import { Recommended } from './Recommended'
import { WatchList } from './Watchlist'

export const MarketsPage = () => {
const { path } = useRouteMatch()
const history = useHistory()

return (
<Switch>
<Switch location={history.location}>
<Route exact path={`${path}`}>
<Redirect to={`${path}/recommended`} />
</Route>
<Route exact path={`${path}/recommended`}>
<Recommended />
</Route>
<Route exact path={`${path}/watchlist`}>
<WatchList />
</Route>
<Route exact path={`${path}/category/:category`}>
<Category />
</Route>
<Route path={`${path}/watchlist`}></Route>
</Switch>
)
}
47 changes: 47 additions & 0 deletions src/pages/Markets/Watchlist.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Box } from '@chakra-ui/react'
import type { ChainId } from '@shapeshiftoss/caip'
import { useCallback, useMemo } from 'react'
import { useTranslate } from 'react-polyglot'
import { Main } from 'components/Layout/Main'
import { SEO } from 'components/Layout/Seo'
import { selectWatchedAssetIds } from 'state/slices/preferencesSlice/selectors'
import { useAppSelector } from 'state/store'

import { AssetsGrid } from './components/AssetsGrid'
import { MarketsRow } from './components/MarketsRow'
import { MarketsHeader } from './MarketsHeader'

const containerPaddingX = { base: 4, xl: 0 }

export const WatchList: React.FC = () => {
const translate = useTranslate()
const headerComponent = useMemo(() => <MarketsHeader />, [])

const watchedAssetIds = useAppSelector(selectWatchedAssetIds)

const component = useCallback(
(selectedChainId: ChainId | undefined) => (
<AssetsGrid
assetIds={watchedAssetIds}
selectedChainId={selectedChainId}
isLoading={false}
limit={undefined}
/>
),
[watchedAssetIds],
)

const body = useMemo(
() => <MarketsRow supportedChainIds={undefined}>{component}</MarketsRow>,
[component],
)

return (
<Main headerComponent={headerComponent} isSubPage>
<SEO title={translate('navBar.markets')} />
<Box py={4} px={containerPaddingX}>
{body}
</Box>
</Main>
)
}
4 changes: 3 additions & 1 deletion src/pages/Markets/components/AssetCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Box, Button, Card, CardBody, Flex, Text } from '@chakra-ui/react'
import type { AssetId } from '@shapeshiftoss/caip'
import { useCallback } from 'react'
import { Amount } from 'components/Amount/Amount'
import { WatchAssetButton } from 'components/AssetHeader/WatchAssetButton'
import { AssetIcon } from 'components/AssetIcon'
import { bnOrZero } from 'lib/bignumber/bignumber'
import { selectAssetById, selectMarketDataByAssetIdUserCurrency } from 'state/slices/selectors'
Expand All @@ -27,7 +28,7 @@ export const AssetCard: React.FC<AssetCardProps> = ({ assetId, onClick }) => {
as={Flex}
flexDirection='column'
justifyContent='space-between'
p={4}
p={2}
width='100%'
height='100%'
>
Expand All @@ -41,6 +42,7 @@ export const AssetCard: React.FC<AssetCardProps> = ({ assetId, onClick }) => {
{asset.symbol}
</Text>
</Box>
<WatchAssetButton assetId={assetId} />
</Flex>
<Box textAlign='left'>
<Amount.Fiat value={marketData.price} fontWeight='bold' fontSize='2xl' />
Expand Down
25 changes: 23 additions & 2 deletions src/pages/Markets/components/AssetsGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type { AssetId, ChainId } from '@shapeshiftoss/caip'
import { ethAssetId, fromAssetId } from '@shapeshiftoss/caip'
import noop from 'lodash/noop'
import { useCallback, useMemo } from 'react'
import { RiExchangeFundsLine } from 'react-icons/ri'
import { useHistory } from 'react-router'
import { ResultsEmpty } from 'components/ResultsEmpty'

import { AssetCard } from './AssetCard'
import { CardWithSparkline } from './CardWithSparkline'
Expand All @@ -16,19 +18,21 @@ const colSpanSx = { base: 1, md: 2 }

const rowSpanSparklineSx = { base: 1, md: 2 }

const emptyIcon = <RiExchangeFundsLine color='pink.200' />

export const AssetsGrid: React.FC<{
assetIds: AssetId[]
selectedChainId?: ChainId
isLoading: boolean
limit: number
limit: number | undefined
}> = ({ assetIds, selectedChainId, limit, isLoading }) => {
const history = useHistory()
const filteredAssetIds = useMemo(
() =>
(selectedChainId
? assetIds.filter(assetId => fromAssetId(assetId).chainId === selectedChainId)
: assetIds
).slice(0, limit - 1),
).slice(0, limit && limit - 1),
[assetIds, limit, selectedChainId],
)

Expand All @@ -52,6 +56,23 @@ export const AssetsGrid: React.FC<{
</Grid>
)

if (!filteredAssetIds.length)
return (
<ResultsEmpty
title={
history.location.pathname === '/markets/watchlist'
? 'markets.watchlistEmpty.emptyTitle'
: 'markets.emptyTitle'
}
body={
history.location.pathname === '/markets/watchlist'
? 'markets.watchlistEmpty.emptyBody'
: 'markets.emptyBody'
}
icon={emptyIcon}
/>
)

return (
<Grid templateRows={gridTemplateRowsSx} gridTemplateColumns={gridTemplateColumnSx} gap={4}>
{filteredAssetIds.map((assetId, index) =>
Expand Down
42 changes: 23 additions & 19 deletions src/pages/Markets/components/CardWithSparkline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { bnOrZero } from '@shapeshiftoss/utils'
import noop from 'lodash/noop'
import { useCallback } from 'react'
import { Amount } from 'components/Amount/Amount'
import { WatchAssetButton } from 'components/AssetHeader/WatchAssetButton'
import { AssetIcon } from 'components/AssetIcon'
import { ParsedHtml } from 'components/ParsedHtml/ParsedHtml'
import { PriceChart } from 'components/PriceChart/PriceChart'
Expand Down Expand Up @@ -44,26 +45,29 @@ export const CardWithSparkline: React.FC<{
height='100%'
>
<Box>
<Flex alignItems='center' justifyContent='space-between' flexWrap='wrap' mb={4}>
<Flex align='center' mb={2}>
<AssetIcon pairProps={assetPairProps} assetId={assetId} size='md' mr={3} />
<Box textAlign='left'>
<Text fontWeight='bold' fontSize='lg'>
{asset.name}
</Text>
<Text fontSize='sm' color='gray.500'>
{asset.symbol}
</Text>
</Box>
</Flex>
<Amount.Fiat value={marketData.price} fontWeight='bold' fontSize='2xl' />
<Flex align='center' mt={1}>
<Amount.Percent
autoColor
value={bnOrZero(changePercent24Hr).times(0.01).toString()}
fontWeight='medium'
/>
<Flex width='100%' justify='space-between' mt={4}>
<Flex alignItems='center' justifyContent='space-between' flexWrap='wrap' mb={4}>
<Flex align='center' mb={2}>
<AssetIcon pairProps={assetPairProps} assetId={assetId} size='md' mr={3} />
<Box textAlign='left'>
<Text fontWeight='bold' fontSize='lg'>
{asset.name}
</Text>
<Text fontSize='sm' color='gray.500'>
{asset.symbol}
</Text>
<Amount.Fiat value={marketData.price} fontWeight='bold' fontSize='2xl' />
<Flex align='center' mt={1}>
<Amount.Percent
autoColor
value={bnOrZero(changePercent24Hr).times(0.01).toString()}
fontWeight='medium'
/>
</Flex>
</Box>
</Flex>
</Flex>
<WatchAssetButton assetId={assetId} />
</Flex>
<Box mb={4} overflow='hidden' textAlign='left'>
<Text
Expand Down
4 changes: 3 additions & 1 deletion src/pages/Markets/components/LpCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import type { AssetId } from '@shapeshiftoss/caip'
import { useCallback, useMemo } from 'react'
import { Amount } from 'components/Amount/Amount'
import { WatchAssetButton } from 'components/AssetHeader/WatchAssetButton'
import { AssetIcon } from 'components/AssetIcon'
import { Text } from 'components/Text'
import { bnOrZero } from 'lib/bignumber/bignumber'
Expand Down Expand Up @@ -49,7 +50,7 @@ export const LpCard: React.FC<LpCardProps> = ({ assetId, apy, volume24H, onClick
as={Flex}
flexDirection='column'
justifyContent='space-between'
p={4}
p={2}
width='100%'
height='100%'
>
Expand Down Expand Up @@ -81,6 +82,7 @@ export const LpCard: React.FC<LpCardProps> = ({ assetId, apy, volume24H, onClick
</CText>
</Tooltip>
</Box>
<WatchAssetButton assetId={assetId} />
</Flex>
<Flex justify='space-between'>
<Box textAlign='left'>
Expand Down
7 changes: 7 additions & 0 deletions src/pages/Markets/components/LpGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { ethAssetId, fromAssetId } from '@shapeshiftoss/caip'
import { useQuery } from '@tanstack/react-query'
import { noop } from 'lodash'
import { useCallback, useEffect, useMemo } from 'react'
import { RiExchangeFundsLine } from 'react-icons/ri'
import { useHistory } from 'react-router'
import { ResultsEmpty } from 'components/ResultsEmpty'
import { opportunitiesApi } from 'state/slices/opportunitiesSlice/opportunitiesApiSlice'
import { thorchainSaversOpportunityIdsResolver } from 'state/slices/opportunitiesSlice/resolvers/thorchainsavers'
import { DefiProvider, DefiType } from 'state/slices/opportunitiesSlice/types'
Expand All @@ -20,6 +22,8 @@ const gridTemplateRowsSx = { base: 'minmax(0, 1fr)', md: 'repeat(2, 1fr)' }
const colSpanSparklineSx = { base: 1, md: 3 }
const colSpanSx = { base: 1, md: 2 }

const emptyIcon = <RiExchangeFundsLine color='pink.200' />

export const LpGrid: React.FC<{
assetIds: AssetId[]
selectedChainId?: ChainId
Expand Down Expand Up @@ -60,6 +64,9 @@ export const LpGrid: React.FC<{
)
}

if (!filteredAssetIds.length)
return <ResultsEmpty title='markets.emptyTitle' body='markets.emptyBody' icon={emptyIcon} />

return (
<Grid templateRows={gridTemplateRowsSx} gridTemplateColumns={gridTemplateColumnSx} gap={4}>
{filteredAssetIds.map((assetId, index) => {
Expand Down
12 changes: 7 additions & 5 deletions src/pages/Markets/components/MarketsRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import { useAppSelector } from 'state/store'
import type { MARKETS_CATEGORIES } from '../constants'

type RowProps = {
title: string
title?: string
subtitle?: string
supportedChainIds: ChainId[] | undefined
category: MARKETS_CATEGORIES
category?: MARKETS_CATEGORIES
children: (selectedChainId: ChainId | undefined) => React.ReactNode
}

Expand Down Expand Up @@ -52,9 +52,11 @@ export const MarketsRow: React.FC<RowProps> = ({
{isCategoryRoute && (
<IconButton variant='ghost' aria-label='back' onClick={handleBack} icon={backIcon} />
)}
<Heading size='md' mb={1}>
<Link to={`/markets/category/${category}`}>{title}</Link>
</Heading>
{category && title && (
<Heading size='md' mb={1}>
<Link to={`/markets/category/${category}`}>{title}</Link>
</Heading>
)}
</Flex>
{subtitle && (
<Text fontSize='sm' color='gray.500'>
Expand Down
Loading