Skip to content

Commit

Permalink
Implement cross-network search
Browse files Browse the repository at this point in the history
  • Loading branch information
csillag committed May 24, 2023
1 parent b54fe4f commit 7a2d0fa
Show file tree
Hide file tree
Showing 28 changed files with 630 additions and 280 deletions.
13 changes: 2 additions & 11 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import React from 'react'
import { Preview } from '@storybook/react'
import { defaultTheme } from '../src/styles/theme'
import { ThemeProvider } from '@mui/material/styles'
import CssBaseline from '@mui/material/CssBaseline'
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'
import '../src/locales/i18n'
import { withDefaultTheme } from '../src/app/components/ThemeByNetwork'

const preview: Preview = {
decorators: [
Story => (
<ThemeProvider theme={defaultTheme}>
<CssBaseline />
<Story />
</ThemeProvider>
),
],
decorators: [Story => withDefaultTheme(<Story />)],
parameters: {
controls: {
matchers: {
Expand Down
10 changes: 6 additions & 4 deletions src/app/components/AppendMobileSearch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { styled, useTheme } from '@mui/material/styles'
import Box from '@mui/material/Box'
import { Search } from '../Search'
import useMediaQuery from '@mui/material/useMediaQuery'
import { NetworkOrGlobal } from '../../../types/network'
import { Network } from '../../../types/network'

interface AppendMobileSearchProps {
action?: ReactNode
Expand Down Expand Up @@ -33,9 +33,11 @@ const SearchWrapper = styled(Box)(() => ({
marginLeft: 'auto',
}))

export const AppendMobileSearch: FC<
PropsWithChildren<AppendMobileSearchProps> & { network: NetworkOrGlobal }
> = ({ network, children, action }) => {
export const AppendMobileSearch: FC<PropsWithChildren<AppendMobileSearchProps> & { network?: Network }> = ({
network,
children,
action,
}) => {
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))

Expand Down
4 changes: 2 additions & 2 deletions src/app/components/PageLayout/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import useMediaQuery from '@mui/material/useMediaQuery'
import { styled, useTheme } from '@mui/material/styles'
import { useConstant } from '../../hooks/useConstant'
import { AppendMobileSearch } from '../AppendMobileSearch'
import { NetworkOrGlobal } from '../../../types/network'
import { Network } from '../../../types/network'

const FooterBox = styled(Box)(({ theme }) => ({
display: 'flex',
Expand All @@ -20,7 +20,7 @@ const FooterBox = styled(Box)(({ theme }) => ({
}))

interface FooterProps {
network: NetworkOrGlobal
network?: Network
mobileSearchAction?: ReactNode
}

Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Search/SearchSuggestionsLinks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { Link as RouterLink } from 'react-router-dom'
import Link from '@mui/material/Link'
import { RouteUtils } from '../../utils/route-utils'
import { OptionalBreak } from '../OptionalBreak'
import { NetworkOrGlobal } from '../../../types/network'
import { Network } from '../../../types/network'

interface Props {
network: NetworkOrGlobal
network?: Network
}

export const SearchSuggestionsLinks: FC<Props> = ({ network }) => {
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import useMediaQuery from '@mui/material/useMediaQuery'
import HighlightOffIcon from '@mui/icons-material/HighlightOff'
import IconButton from '@mui/material/IconButton'
import { SearchSuggestionsButtons } from './SearchSuggestionsButtons'
import { NetworkOrGlobal } from '../../../types/network'
import { Network } from '../../../types/network'

export type SearchVariant = 'button' | 'icon' | 'expandable'

Expand Down Expand Up @@ -84,7 +84,7 @@ SearchButton.defaultProps = {
}

export interface SearchProps {
network: NetworkOrGlobal
network?: Network
variant: SearchVariant
disabled?: boolean
onFocusChange?: (hasFocus: boolean) => void
Expand Down
7 changes: 2 additions & 5 deletions src/app/components/Search/search-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
isValidEthAddress,
getEvmBech32Address,
} from '../../utils/helpers'
import { GlobalNetwork, Network } from '../../../types/network'
import { Network } from '../../../types/network'
import { RouteUtils } from '../../utils/route-utils'
import { AppError, AppErrors } from '../../../types/errors'

Expand Down Expand Up @@ -65,10 +65,7 @@ export function isSearchValid(searchTerm: string) {

export const searchParamLoader = async ({ request, params }: LoaderFunctionArgs) => {
const { network } = params
if (
!network ||
(network !== GlobalNetwork && !RouteUtils.getEnabledNetworks().includes(network as Network))
) {
if (!!network && !RouteUtils.getEnabledNetworks().includes(network as Network)) {
throw new AppError(AppErrors.InvalidUrl)
}

Expand Down
19 changes: 19 additions & 0 deletions src/app/components/ThemeByNetwork/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React, { FC, ReactNode } from 'react'
import { Network } from '../../../types/network'
import { ThemeProvider } from '@mui/material/styles'
import { getThemesForNetworks } from '../../../styles/theme'
import CssBaseline from '@mui/material/CssBaseline'

export const ThemeByNetwork: FC<{ network: Network; children: React.ReactNode }> = ({
network,
children,
}) => (
<ThemeProvider theme={getThemesForNetworks()[network]}>
<CssBaseline />
{children}
</ThemeProvider>
)

export const withDefaultTheme = (node: ReactNode) => (
<ThemeByNetwork network={Network.mainnet}>{node}</ThemeByNetwork>
)
9 changes: 4 additions & 5 deletions src/app/hooks/useNetworkParam.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { useParams } from 'react-router-dom'
import { Network, NetworkOrGlobal } from '../../types/network'
import { Network } from '../../types/network'
import { RouteUtils } from '../utils/route-utils'
import { AppError, AppErrors } from '../../types/errors'

export const useNetworkParam = (): NetworkOrGlobal => {
export const useNetworkParam = (): Network | undefined => {
const { network } = useParams()

return network as NetworkOrGlobal
return network as Network | undefined
}

/**
* Use this in situations where we can be sure that the network has already been checked
*/
export const useSafeNetworkParam = (): Network => {
const network = useNetworkParam()
if (!RouteUtils.getEnabledNetworks().includes(network as any)) {
if (!network || !RouteUtils.getEnabledNetworks().includes(network as any)) {
throw new AppError(AppErrors.UnsupportedNetwork)
}
return network as Network
Expand Down
10 changes: 2 additions & 8 deletions src/app/pages/HomePage/Graph/NetworkSelector/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { TFunction } from 'i18next'
import { useTheme } from '@mui/material/styles'
import useMediaQuery from '@mui/material/useMediaQuery'
import AddIcon from '@mui/icons-material/Add'
Expand All @@ -11,7 +10,7 @@ import RemoveIcon from '@mui/icons-material/Remove'
import Typography from '@mui/material/Typography'
import { styled } from '@mui/material/styles'
import { COLORS } from '../../../../../styles/theme/colors'
import { Network } from '../../../../../types/network'
import { getNetworkNames, Network } from '../../../../../types/network'
import Collapse from '@mui/material/Collapse'
import { RouteUtils } from '../../../../utils/route-utils'

Expand Down Expand Up @@ -60,18 +59,13 @@ type NetworkSelectorProps = {
setNetwork: (network: Network) => void
}

const getLabels = (t: TFunction): { [key in Network]: string } => ({
mainnet: t('common.mainnet'),
testnet: t('common.testnet'),
})

export const NetworkSelector: FC<NetworkSelectorProps> = ({ network, setNetwork }) => {
const { t } = useTranslation()
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
const [open, setOpen] = useState(false)
const options: Network[] = RouteUtils.getEnabledNetworks()
const labels = getLabels(t)
const labels = getNetworkNames(t)

return (
<StyledNetworkSelector>
Expand Down
10 changes: 2 additions & 8 deletions src/app/pages/HomePage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'
import { useTranslation } from 'react-i18next'
import { ParaTimeSelectorStep } from './Graph/types'
import { BuildPreviewBanner } from '../../components/BuildPreviewBanner'
import { GlobalNetwork } from '../../../types/network'

export const zIndexHomePage = {
paraTimeSelector: 1,
Expand Down Expand Up @@ -133,12 +132,7 @@ export const HomePage: FC = () => {
</LogotypeBox>
<SearchInputContainer>
<SearchInputBox>
<Search
network={GlobalNetwork}
disabled={isApiOffline}
variant={searchVariant}
onFocusChange={onFocusChange}
/>
<Search disabled={isApiOffline} variant={searchVariant} onFocusChange={onFocusChange} />
</SearchInputBox>
{isApiOffline && (
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
Expand All @@ -157,7 +151,7 @@ export const HomePage: FC = () => {
<InfoOutlinedIcon fontSize="medium" sx={{ color: 'white' }} />
</IconButton>
)}
{!isMobile && <Footer network={GlobalNetwork} />}
{!isMobile && <Footer />}
</FooterStyled>
</HomepageLayout>
</>
Expand Down
10 changes: 7 additions & 3 deletions src/app/pages/SearchResultsPage/NoResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ import Link from '@mui/material/Link'
import { SearchSuggestionsLinks } from '../../components/Search/SearchSuggestionsLinks'
import { OptionalBreak } from '../../components/OptionalBreak'
import { useTheme } from '@mui/material/styles'
import { NetworkOrGlobal } from '../../../types/network'
import { getNetworkNames, Network } from '../../../types/network'

export const NoResults: FC<{ network: NetworkOrGlobal }> = ({ network }) => {
export const NoResults: FC<{ network?: Network }> = ({ network }) => {
const { t } = useTranslation()
const theme = useTheme()
const title = !network
? t('search.noResults.header')
: t('search.noResults.networkHeader', { network: getNetworkNames(t)[network] })

return (
<EmptyState
title={t('search.noResults.header')}
title={title}
description={
<Box
sx={{ textAlign: 'center', a: { color: theme.palette.layout.main, textDecoration: 'underline' } }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useTranslation } from 'react-i18next'
import React from 'react'
import { Link as RouterLink } from 'react-router-dom'
import { SubPageCard } from '../../components/SubPageCard'
import { useTranslation } from 'react-i18next'
import Button from '@mui/material/Button'
import Box from '@mui/material/Box'
import Divider from '@mui/material/Divider'
import { styled } from '@mui/material/styles'
import { SubPageCard } from '../../components/SubPageCard'

interface Props<T> {
title: string
Expand All @@ -24,7 +25,12 @@ export const ViewResultButton = (() => {
return ViewResultButton as typeof Button
})()

export function ResultsGroup<T>({ title, results, resultComponent, link, linkLabel }: Props<T>) {
/**
* Component for displaying search results of the same type, from the same network.
*
* It doesn't actually run a search query, but uses existing results.
*/
export function ResultsGroupByType<T>({ title, results, resultComponent, link, linkLabel }: Props<T>) {
const { t } = useTranslation()

if (!results || results.length <= 0) {
Expand Down
116 changes: 116 additions & 0 deletions src/app/pages/SearchResultsPage/ResultsOnForeignNetworkThemed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { FC, useState } from 'react'
import { getNetworkNames, Network } from '../../../types/network'
import { Trans, useTranslation } from 'react-i18next'
import { styled, useTheme } from '@mui/material/styles'
import { getThemesForNetworks } from '../../../styles/theme'
import useMediaQuery from '@mui/material/useMediaQuery'
import Box from '@mui/material/Box'
import { ResultsOnNetwork } from './ResultsOnNetwork'
import { SearchQueries } from './hooks'
import { COLORS } from '../../../styles/theme/colors'
import ZoomIn from '@mui/icons-material/ZoomIn'
import Warning from '@mui/icons-material/Warning'

const NotificationBox = styled(Box)(({ theme }) => ({
// TODO: this is probably not fully correct.
marginTop: 10,
marginBottom: 20,
fontSize: 14,

boxSizing: 'border-box',
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
padding: '5px 10px',
gap: 10,

height: 50,

background: theme.palette.background.default,
border: `2px solid ${theme.palette.layout.border}`,
color: theme.palette.layout.main,

borderRadius: 50,
}))

/**
* Component for selectively displaying a subset of search results that belongs to a specific foreign network,
* with appropriate theming and collapse/open functionality.
*
* It doesn't actually run a search query, but uses existing results.
* Except the theming and the collapse functionality, it relies on ResultsOnNetwork.
*/
export const ResultsOnForeignNetworkThemed: FC<{
network: Network
alsoHasLocalResults: boolean
openByDefault?: boolean
searchQueries: SearchQueries
numberOfResults: number
roseFiatValue: number | undefined
}> = ({
network,
searchQueries,
numberOfResults,
roseFiatValue,
openByDefault = false,
alsoHasLocalResults,
}) => {
const [open, setOpen] = useState(openByDefault)
const { t } = useTranslation()
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
const networkName = getNetworkNames(t)[network]
if (!numberOfResults) {
return null
}
const otherTheme = getThemesForNetworks()[network]

if (!open) {
return (
<NotificationBox theme={otherTheme} onClick={() => setOpen(true)}>
<ZoomIn />
<span>
<Trans
t={t}
i18nKey={
alsoHasLocalResults
? 'search.otherResults.clickToShowMore'
: 'search.otherResults.clickToShowThem'
}
values={{
countLabel: t(alsoHasLocalResults ? 'search.results.moreCount' : 'search.results.count', {
count: numberOfResults,
}),
networkName,
}}
/>
</span>
</NotificationBox>
)
}
return (
<Box
sx={{
marginTop: 50,
pt: 4,
px: isMobile ? 0 : '4%',
border: isMobile ? 'none' : `solid 15px ${otherTheme.palette.layout.border}`,
background: otherTheme.palette.background.default,
}}
>
<NotificationBox
sx={{
background: COLORS.white, // TODO should come from theme
color: COLORS.grayDark, // TODO should come from theme
border: `2px solid ${otherTheme.palette.layout.border}`,
}}
onClick={() => setOpen(false)}
>
<Warning />
{t('search.otherResults.clickToHide', { networkName })}
</NotificationBox>
<ResultsOnNetwork network={network} searchQueries={searchQueries} roseFiatValue={roseFiatValue} />
</Box>
)
}

0 comments on commit 7a2d0fa

Please sign in to comment.