-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Continue the work on cross-site / cross-paratime search
- Loading branch information
Showing
17 changed files
with
429 additions
and
323 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { FC, useState } from 'react' | ||
import { Trans, useTranslation } from 'react-i18next' | ||
import { styled } from '@mui/material/styles' | ||
import { getThemesForNetworks } from '../../../styles/theme' | ||
import Box from '@mui/material/Box' | ||
import { SearchQueries } from './hooks' | ||
import ZoomIn from '@mui/icons-material/ZoomIn' | ||
import ZoomOut from '@mui/icons-material/ZoomOut' | ||
import { getKeyForScope, getScopeForKey, SearchScope } from '../../../types/searchScope' | ||
import { getNetworkNames, Network } from '../../../types/network' | ||
import { RouteUtils } from '../../utils/route-utils' | ||
import { ResultsFilteredThemed } from './ResultsFilteredThemed' | ||
|
||
const NotificationBox = styled(Box)(({ theme }) => ({ | ||
// TODO: this is probably not fully correct. | ||
marginTop: 30, | ||
marginBottom: 30, | ||
fontSize: 14, | ||
marginLeft: '10%', | ||
marginRight: '10%', | ||
|
||
boxSizing: 'border-box', | ||
display: 'flex', | ||
flexDirection: 'row', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
padding: '5px 10px', | ||
gap: 10, | ||
|
||
height: 50, | ||
|
||
background: theme.palette.layout.notificationBackground, | ||
border: `2px solid ${theme.palette.layout.darkBorder}`, | ||
color: theme.palette.layout.notificationText, | ||
|
||
borderRadius: 50, | ||
})) | ||
|
||
export const ResultsElsewhere: FC<{ | ||
wantedScope: SearchScope | ||
resultsInScopes: Record<string, number> | ||
searchQueries: SearchQueries | ||
roseFiatValue: number | undefined | ||
}> = ({ wantedScope, resultsInScopes, searchQueries, roseFiatValue }) => { | ||
const { t } = useTranslation() | ||
const wantedScopeKey = getKeyForScope(wantedScope) | ||
const alsoHasWantedResults = !!resultsInScopes[wantedScopeKey] | ||
const otherScopesKeys = Object.keys(resultsInScopes) | ||
.filter(key => !!resultsInScopes[key]) | ||
.filter(scopeKey => scopeKey !== wantedScopeKey) | ||
const otherScopes = otherScopesKeys.map(getScopeForKey) | ||
const hasResultsOnDifferentParatimes = otherScopes.some( | ||
scope => scope.network === wantedScope.network && scope.layer !== wantedScope.layer, | ||
) | ||
const hasResultsOnDifferentNetworks = otherScopes.some(scope => scope.network !== wantedScope.network) | ||
const hasAllKindsOfResults = hasResultsOnDifferentParatimes && hasResultsOnDifferentNetworks | ||
const location = t( | ||
hasAllKindsOfResults | ||
? 'search.otherResults.otherNetworksAndParatimes' | ||
: hasResultsOnDifferentNetworks | ||
? 'search.otherResults.otherNetworks' | ||
: 'search.otherResults.otherParatimes', | ||
) | ||
|
||
const totalNumberOfResults = otherScopesKeys.reduce( | ||
(partialSum, scopeKey) => partialSum + resultsInScopes[scopeKey], | ||
0, | ||
) | ||
|
||
// openByDefault={scope.network === Network.mainnet && !hasNoResultsInWantedScope} | ||
const openByDefault = false | ||
|
||
const [open, setOpen] = useState(openByDefault) | ||
|
||
const hasMainnetResults = otherScopes.some(scope => scope.network === Network.mainnet) | ||
|
||
const themes = getThemesForNetworks() | ||
const networkNames = getNetworkNames(t) | ||
|
||
const notificationTheme = hasMainnetResults ? themes[Network.mainnet] : themes[otherScopes[0].network] | ||
|
||
if (!otherScopes.length) return null | ||
|
||
const resultsInNetworks: Record<Network, number> = {} as any | ||
const allNetworks = RouteUtils.getEnabledNetworks() | ||
allNetworks.forEach(net => (resultsInNetworks[net] = 0)) | ||
otherScopes.forEach(scope => (resultsInNetworks[scope.network] += resultsInScopes[scope.key])) | ||
|
||
if (!open) { | ||
return ( | ||
<NotificationBox theme={notificationTheme} onClick={() => setOpen(true)}> | ||
<ZoomIn /> | ||
<span> | ||
<Trans | ||
t={t} | ||
i18nKey={ | ||
alsoHasWantedResults | ||
? 'search.otherResults.clickToShowMore' | ||
: 'search.otherResults.clickToShowThem' | ||
} | ||
values={{ | ||
countLabel: t(alsoHasWantedResults ? 'search.results.moreCount' : 'search.results.count', { | ||
count: totalNumberOfResults, | ||
}), | ||
location, | ||
}} | ||
/> | ||
</span> | ||
</NotificationBox> | ||
) | ||
} | ||
|
||
return ( | ||
<> | ||
<NotificationBox theme={notificationTheme} onClick={() => setOpen(false)}> | ||
<ZoomOut /> | ||
<span> | ||
<Trans i18nKey={'search.otherResults.clickToHide'} values={{ location }} /> | ||
</span> | ||
</NotificationBox> | ||
{hasResultsOnDifferentParatimes && ( | ||
<ResultsFilteredThemed | ||
title={t('search.otherResults.otherParatimesOnNetwork', { | ||
network: networkNames[wantedScope.network], | ||
})} | ||
filter={item => item.network === wantedScope.network && item.layer !== wantedScope.layer} | ||
networkForTheme={wantedScope.network} | ||
searchQueries={searchQueries} | ||
numberOfResults={resultsInNetworks[wantedScope.network]} | ||
roseFiatValue={roseFiatValue} | ||
/> | ||
)} | ||
{allNetworks | ||
.filter(net => net !== wantedScope.network && !!resultsInNetworks[net]) | ||
.map(net => ( | ||
<ResultsFilteredThemed | ||
key={net} | ||
networkForTheme={net} | ||
title={networkNames[net]} | ||
filter={item => item.network === net} | ||
searchQueries={searchQueries} | ||
numberOfResults={resultsInNetworks[net]} | ||
roseFiatValue={roseFiatValue} | ||
/> | ||
))} | ||
</> | ||
) | ||
} |
140 changes: 140 additions & 0 deletions
140
src/app/pages/SearchResultsPage/ResultsFilteredThemed.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { FC } from 'react' | ||
import { useTranslation } from 'react-i18next' | ||
import { ResultsGroupByType } from './ResultsGroupByType' | ||
import { BlockDetailView } from '../BlockDetailPage' | ||
import { RouteUtils } from '../../utils/route-utils' | ||
import { TransactionDetailView } from '../TransactionDetailPage' | ||
import { AccountDetailsView } from '../AccountDetailsPage' | ||
import { SearchQueries } from './hooks' | ||
import { HasScope } from '../../../oasis-indexer/api' | ||
import { getThemesForNetworks } from '../../../styles/theme' | ||
import { Network } from '../../../types/network' | ||
import { SubPageCard } from '../../components/SubPageCard' | ||
import useMediaQuery from '@mui/material/useMediaQuery' | ||
import { styled } from '@mui/material/styles' | ||
import Box from '@mui/material/Box' | ||
|
||
const ResultListFrame = styled(Box)(({ theme }) => { | ||
const isMobile = useMediaQuery(theme.breakpoints.down('sm')) | ||
return { | ||
marginBottom: 20, | ||
border: isMobile ? 'none' : `solid 15px ${theme.palette.layout.networkBubbleBorder}`, | ||
background: theme.palette.layout.networkBubbleBackground, | ||
borderRadius: 12, | ||
boxShadow: '-20px 4px 40px rgba(34, 47, 63, 0.24)', | ||
'&& > div > div': { | ||
// border: '2px solid green', | ||
borderTopLeftRadius: 0, | ||
borderTopRightRadius: 0, | ||
paddingLeft: 64, | ||
paddingRight: 64, | ||
background: theme.palette.layout.networkBubbleBackground, | ||
}, | ||
'&& > div > div > div.MuiBox-root': { | ||
background: theme.palette.layout.networkBubbleBorder, | ||
borderRadius: 0, | ||
// border: '2px solid red', | ||
marginLeft: -64, | ||
marginTop: -32, | ||
marginRight: -64, | ||
paddingLeft: 64, | ||
paddingRight: 64, | ||
paddingBottom: 32, | ||
paddingTop: 32, | ||
}, | ||
'&& > div > div > div.MuiCardContent-root': {}, | ||
'&& dt, && dd': { | ||
boxShadow: `0px 1px 0px ${theme.palette.layout.descriptionListSeparator}`, | ||
}, | ||
} | ||
}) | ||
|
||
export type ResultFilter = (item: HasScope) => boolean | ||
|
||
/** | ||
* Component for selectively displaying a subset of search results that matches a filter | ||
* | ||
* It doesn't actually run a search query, but uses existing results. | ||
*/ | ||
const ResultsFiltered: FC<{ | ||
searchQueries: SearchQueries | ||
filter: ResultFilter | ||
roseFiatValue: number | undefined | ||
}> = ({ searchQueries, filter, roseFiatValue }) => { | ||
const { t } = useTranslation() | ||
return ( | ||
<> | ||
<ResultsGroupByType | ||
title={t('search.results.blocks.title')} | ||
results={searchQueries.blockHeight.results.filter(filter)} | ||
resultComponent={item => <BlockDetailView isLoading={false} block={item} showLayer={true} />} | ||
link={block => RouteUtils.getBlockRoute(block, block.round)} | ||
linkLabel={t('search.results.blocks.viewLink')} | ||
/> | ||
|
||
<ResultsGroupByType | ||
title={t('search.results.transactions.title')} | ||
results={searchQueries.txHash.results.filter(filter)} | ||
resultComponent={item => ( | ||
<TransactionDetailView isLoading={false} transaction={item} showLayer={true} /> | ||
)} | ||
link={tx => RouteUtils.getTransactionRoute(tx, tx.eth_hash || tx.hash)} | ||
linkLabel={t('search.results.transactions.viewLink')} | ||
/> | ||
|
||
<ResultsGroupByType | ||
title={t('search.results.accounts.title')} | ||
results={[ | ||
...(searchQueries.oasisAccount.results ?? []).filter(filter), | ||
...(searchQueries.evmBech32Account.results ?? []).filter(filter), | ||
]} | ||
resultComponent={item => ( | ||
<AccountDetailsView | ||
isLoading={false} | ||
account={item} | ||
roseFiatValue={roseFiatValue} | ||
showLayer={true} | ||
/> | ||
)} | ||
link={acc => RouteUtils.getAccountRoute(acc, acc.address_eth ?? acc.address)} | ||
linkLabel={t('search.results.accounts.viewLink')} | ||
/> | ||
</> | ||
) | ||
} | ||
|
||
/** | ||
* Component for selectively displaying a subset of search results that matched a passed filter, | ||
* with appropriate theming. | ||
* | ||
* It doesn't actually run a search query, but uses existing results. | ||
*/ | ||
export const ResultsFilteredThemed: FC<{ | ||
title: string | ||
filter: ResultFilter | ||
networkForTheme: Network | ||
searchQueries: SearchQueries | ||
numberOfResults: number | ||
roseFiatValue: number | undefined | ||
}> = ({ filter, title, networkForTheme, searchQueries, numberOfResults, roseFiatValue }) => { | ||
const { t } = useTranslation() | ||
|
||
if (!numberOfResults) { | ||
return null | ||
} | ||
const theme = getThemesForNetworks()[networkForTheme] | ||
|
||
return ( | ||
<ResultListFrame theme={theme}> | ||
<SubPageCard | ||
title={title} | ||
featured | ||
subheader={t('search.results.count', { | ||
count: numberOfResults, | ||
})} | ||
> | ||
<ResultsFiltered filter={filter} searchQueries={searchQueries} roseFiatValue={roseFiatValue} /> | ||
</SubPageCard> | ||
</ResultListFrame> | ||
) | ||
} |
Oops, something went wrong.