Skip to content

Commit

Permalink
feat: markets category route
Browse files Browse the repository at this point in the history
  • Loading branch information
gomesalexandre committed Sep 25, 2024
1 parent 4e04b1e commit 4a722a1
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 24 deletions.
47 changes: 47 additions & 0 deletions src/pages/Markets/Category.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Box } from '@chakra-ui/react'
import { useMemo } from 'react'
import { useTranslate } from 'react-polyglot'
import { useParams } from 'react-router'
import { Main } from 'components/Layout/Main'
import { SEO } from 'components/Layout/Seo'

import { MarketsRow } from './components/MarketsRow'
import type { MARKETS_CATEGORIES } from './constants'
import { useRows } from './hooks/useRows'
import { MarketsHeader } from './MarketsHeader'

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

const ASSETS_LIMIT = 100

export const Category: React.FC = () => {
const params: { category: MARKETS_CATEGORIES } = useParams()
const translate = useTranslate()
const headerComponent = useMemo(() => <MarketsHeader />, [])

const allRows = useRows({ limit: ASSETS_LIMIT })
const row = allRows[params.category]

const body = useMemo(
() => (
<MarketsRow
title={row.title}
subtitle={row.subtitle}
supportedChainIds={row.supportedChainIds}
category={row.category}
>
{row.component}
</MarketsRow>
),
[row.category, row.component, row.subtitle, row.supportedChainIds, row.title],
)

return (
<Main headerComponent={headerComponent} isSubPage>
<SEO title={translate('navBar.markets')} />
<Box py={4} px={containerPaddingX}>
{body}
</Box>
</Main>
)
}
45 changes: 35 additions & 10 deletions src/pages/Markets/MarketsHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ export const MarketsHeader = () => {
history.push('/explore')
}, [history])

const maybeCategory = useMemo(
() =>
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 (
<>
<Display.Mobile>
Expand All @@ -46,20 +61,30 @@ export const MarketsHeader = () => {
<PageBackButton onBack={handleBack} />
</PageHeader.Left>
<PageHeader.Middle>
<PageHeader.Title>{translate('navBar.markets')}</PageHeader.Title>
<PageHeader.Title>{translate(headingCopy)}</PageHeader.Title>
</PageHeader.Middle>
</PageHeader>
</Display.Mobile>
<Stack mb={4}>
<Container maxWidth='container.4xl' px={containerPadding} pt={containerPaddingTop} pb={4}>
<Display.Desktop>
<Stack>
<Heading>{translate('navBar.markets')}</Heading>
<Text color='text.subtle' translation='markets.marketsBody' />
</Stack>
</Display.Desktop>
</Container>
<TabMenu items={NavItems} />
{!maybeCategory && (
// Don't show tabs and heading when on a single category view
<>
<Container
maxWidth='container.4xl'
px={containerPadding}
pt={containerPaddingTop}
pb={4}
>
<Display.Desktop>
<Stack>
<Heading>{translate(headingCopy)}</Heading>
<Text color='text.subtle' translation={subtitleCopy} />
</Stack>
</Display.Desktop>
</Container>
<TabMenu items={NavItems} />
</>
)}
</Stack>
</>
)
Expand Down
3 changes: 2 additions & 1 deletion src/pages/Markets/MarketsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Redirect, Route, Switch, useRouteMatch } from 'react-router'

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

export const MarketsPage = () => {
Expand All @@ -14,7 +15,7 @@ export const MarketsPage = () => {
<Recommended />
</Route>
<Route exact path={`${path}/category/:category`}>
<Recommended />
<Category />
</Route>
<Route path={`${path}/watchlist`}></Route>
</Switch>
Expand Down
7 changes: 4 additions & 3 deletions src/pages/Markets/Recommended.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTranslate } from 'react-polyglot'
import { Main } from 'components/Layout/Main'
import { SEO } from 'components/Layout/Seo'

import { LpRow } from './components/Row'
import { MarketsRow } from './components/MarketsRow'
import { useRows } from './hooks/useRows'
import { MarketsHeader } from './MarketsHeader'

Expand All @@ -21,14 +21,15 @@ export const Recommended: React.FC = () => {
const body = useMemo(
() =>
Object.values(rows).map((row, i) => (
<LpRow
<MarketsRow
key={i}
title={row.title}
subtitle={row.subtitle}
supportedChainIds={row.supportedChainIds}
category={row.category}
>
{row.component}
</LpRow>
</MarketsRow>
)),
[rows],
)
Expand Down
76 changes: 76 additions & 0 deletions src/pages/Markets/components/MarketsRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ArrowBackIcon } from '@chakra-ui/icons'
import { Box, Flex, Heading, IconButton, Text } from '@chakra-ui/react'
import type { ChainId } from '@shapeshiftoss/caip'
import { KnownChainIds } from '@shapeshiftoss/types'
import { useMemo, useState } from 'react'
import { Link, useHistory, useParams } from 'react-router-dom'
import { ChainDropdown } from 'components/ChainDropdown/ChainDropdown'
import { selectFeatureFlag } from 'state/slices/selectors'
import { useAppSelector } from 'state/store'

import type { MARKETS_CATEGORIES } from '../constants'

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

const backIcon = <ArrowBackIcon />

export const MarketsRow: React.FC<RowProps> = ({
title,
subtitle,
supportedChainIds,
children,
category,
}) => {
const params: { category?: MARKETS_CATEGORIES } = useParams()
const history = useHistory()
const handleBack = history.goBack
const isCategoryRoute = params.category
const [selectedChainId, setSelectedChainId] = useState<ChainId | undefined>(undefined)
const isArbitrumNovaEnabled = useAppSelector(state => selectFeatureFlag(state, 'ArbitrumNova'))

const chainIds = useMemo(() => {
if (!supportedChainIds)
return Object.values(KnownChainIds).filter(chainId => {
if (!isArbitrumNovaEnabled && chainId === KnownChainIds.ArbitrumNovaMainnet) return false
return true
})

return supportedChainIds
}, [isArbitrumNovaEnabled, supportedChainIds])

return (
<Box mb={8}>
<Flex justify='space-between' align='center' mb={4}>
<Box me={4}>
<Flex direction='row'>
{isCategoryRoute && (
<IconButton variant='ghost' aria-label='back' onClick={handleBack} icon={backIcon} />
)}
<Heading size='md' mb={1}>
<Link to={`/markets/category/${category}`}>{title}</Link>
</Heading>
</Flex>
{subtitle && (
<Text fontSize='sm' color='gray.500'>
{subtitle}
</Text>
)}
</Box>
<ChainDropdown
chainIds={chainIds}
chainId={selectedChainId}
onClick={setSelectedChainId}
showAll
includeBalance
/>
</Flex>
{children(selectedChainId)}
</Box>
)
}
22 changes: 12 additions & 10 deletions src/pages/Markets/hooks/useRows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export const useRows = ({ limit }: { limit: number }) => {
() => ({
[MARKETS_CATEGORIES.TRADING_VOLUME]: {
category: MARKETS_CATEGORIES.TRADING_VOLUME,
title: translate('markets.categories.tradingVolume.title'),
subtitle: translate('markets.categories.tradingVolume.subtitle'),
title: translate(`markets.categories.${MARKETS_CATEGORIES.TRADING_VOLUME}.title`),
subtitle: translate(`markets.categories.${MARKETS_CATEGORIES.TRADING_VOLUME}.subtitle`),
component: (selectedChainId: ChainId | undefined) => (
<AssetsGrid
assetIds={highestVolumeData?.ids ?? []}
Expand All @@ -58,8 +58,8 @@ export const useRows = ({ limit }: { limit: number }) => {
},
[MARKETS_CATEGORIES.MARKET_CAP]: {
category: MARKETS_CATEGORIES.MARKET_CAP,
title: translate('markets.categories.marketCap.title'),
subtitle: translate('markets.categories.marketCap.subtitle'),
title: translate(`markets.categories.${MARKETS_CATEGORIES.MARKET_CAP}.title`),
subtitle: translate(`markets.categories.${MARKETS_CATEGORIES.MARKET_CAP}.subtitle`),
component: (selectedChainId: ChainId | undefined) => (
<AssetsGrid
assetIds={marketCapData?.ids ?? []}
Expand All @@ -71,8 +71,10 @@ export const useRows = ({ limit }: { limit: number }) => {
},
[MARKETS_CATEGORIES.TRENDING]: {
category: MARKETS_CATEGORIES.TRENDING,
title: translate('markets.categories.trending.title'),
subtitle: translate('markets.categories.trending.subtitle', { percentage: '10' }),
title: translate(`markets.categories.${MARKETS_CATEGORIES.TRENDING}.title`),
subtitle: translate(`markets.categories.${MARKETS_CATEGORIES.TRENDING}.subtitle`, {
percentage: '10',
}),
component: (selectedChainId: ChainId | undefined) => (
<AssetsGrid
assetIds={trendingData?.ids ?? []}
Expand All @@ -84,7 +86,7 @@ export const useRows = ({ limit }: { limit: number }) => {
},
[MARKETS_CATEGORIES.TOP_MOVERS]: {
category: MARKETS_CATEGORIES.TOP_MOVERS,
title: translate('markets.categories.topMovers.title'),
title: translate(`markets.categories.${MARKETS_CATEGORIES.TOP_MOVERS}.title`),
component: (selectedChainId: ChainId | undefined) => (
<AssetsGrid
assetIds={topMoversData?.ids ?? []}
Expand All @@ -96,7 +98,7 @@ export const useRows = ({ limit }: { limit: number }) => {
},
[MARKETS_CATEGORIES.RECENTLY_ADDED]: {
category: MARKETS_CATEGORIES.RECENTLY_ADDED,
title: translate('markets.categories.recentlyAdded.title'),
title: translate(`markets.categories.${MARKETS_CATEGORIES.RECENTLY_ADDED}.title`),
// TODO(gomes): loading state when implemented
component: (selectedChainId: ChainId | undefined) => (
<AssetsGrid
Expand All @@ -109,15 +111,15 @@ export const useRows = ({ limit }: { limit: number }) => {
},
[MARKETS_CATEGORIES.ONE_CLICK_DEFI]: {
category: MARKETS_CATEGORIES.ONE_CLICK_DEFI,
title: translate('markets.categories.oneClickDefiAssets.title'),
title: translate(`markets.categories.${MARKETS_CATEGORIES.ONE_CLICK_DEFI}.title`),
component: (selectedChainId: ChainId | undefined) => (
<OneClickDefiAssets selectedChainId={selectedChainId} limit={limit} />
),
supportedChainIds: allPortalsAssets?.chainIds,
},
[MARKETS_CATEGORIES.THORCHAIN_DEFI]: {
category: MARKETS_CATEGORIES.THORCHAIN_DEFI,
title: translate('markets.categories.thorchainDefi.title'),
title: translate(`markets.categories.${MARKETS_CATEGORIES.THORCHAIN_DEFI}.title`),
component: (selectedChainId: ChainId | undefined) => (
<ThorchainAssets selectedChainId={selectedChainId} limit={limit} />
),
Expand Down

0 comments on commit 4a722a1

Please sign in to comment.