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

ParaTime picker #426

Merged
merged 20 commits into from
May 26, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/components/Circle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export const Circle = styled(Box)<CircleProps>(({ color, size, theme }) => ({
height: theme.spacing(size),
backgroundColor: color,
borderRadius: theme.spacing(size),
color: 'inherit',
}))
7 changes: 4 additions & 3 deletions src/app/components/PageLayout/Logotype.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import Typography from '@mui/material/Typography'
import { useTranslation } from 'react-i18next'

interface LogotypeProps {
color?: string
showText?: true
}

export const Logotype: FC<LogotypeProps> = ({ showText }) => {
export const Logotype: FC<LogotypeProps> = ({ color, showText }) => {
const { t } = useTranslation()
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
Expand All @@ -27,12 +28,12 @@ export const Logotype: FC<LogotypeProps> = ({ showText }) => {
display: 'inline-flex',
alignItems: 'center',
gap: 4,
color: theme.palette.layout.main,
color: color || theme.palette.layout.main,
}}
>
<OasisIcon sx={{ fontSize: logoSize }} />
{showTypography && (
<Typography variant="h1" color={theme.palette.layout.main} sx={{ whiteSpace: 'nowrap' }}>
<Typography variant="h1" color={color || theme.palette.layout.main} sx={{ whiteSpace: 'nowrap' }}>
{t('pageTitle')}
</Typography>
)}
Expand Down
32 changes: 10 additions & 22 deletions src/app/components/PageLayout/NetworkButton.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,15 @@
import { FC, ReactNode } from 'react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { TFunction } from 'i18next'
import Box from '@mui/material/Box'
import Button, { buttonClasses } from '@mui/material/Button'
import CheckIcon from '@mui/icons-material/Check'
import EditIcon from '@mui/icons-material/Edit'
import { styled } from '@mui/material/styles'
import { COLORS } from '../../../styles/theme/colors'
import { Circle } from '../Circle'
import { MainnetIcon } from '../../components/CustomIcons/Mainnet'
import { TestnetIcon } from '../../components/CustomIcons/Testnet'
import { Network } from '../../../types/network'
import { Layer } from '../../../oasis-indexer/api'

const getLabels = (t: TFunction): { [key in Layer]: string } => ({
[Layer.emerald]: t('common.emerald'),
[Layer.sapphire]: t('common.sapphire'),
[Layer.cipher]: t('common.cipher'),
[Layer.consensus]: t('common.consensus'),
})

const getIcons = (): Record<Network, ReactNode> => ({
[Network.mainnet]: <MainnetIcon />,
[Network.testnet]: <TestnetIcon />,
})
import { getLayerLabels, getNetworkIcons } from '../../utils/content'

export const StyledNetworkButton = styled(Button)(({ theme }) => ({
alignItems: 'center',
Expand Down Expand Up @@ -84,12 +70,13 @@ export const StyledBox = styled(Box)(({ theme }) => ({
type NetworkButtonProps = {
layer: Layer
network: Network
onClick: () => void
}

export const NetworkButton: FC<NetworkButtonProps> = ({ layer, network }) => {
export const NetworkButton: FC<NetworkButtonProps> = ({ layer, network, onClick }) => {
const { t } = useTranslation()
const labels = getLabels(t)
const icons = getIcons()
const labels = getLayerLabels(t)
const icons = getNetworkIcons()

return (
<StyledNetworkButton
Expand All @@ -98,6 +85,7 @@ export const NetworkButton: FC<NetworkButtonProps> = ({ layer, network }) => {
variant="outlined"
startIcon={icons[network]}
endIcon={<EditIcon />}
onClick={onClick}
>
<StyledBox>
{labels[layer]}
Expand Down Expand Up @@ -126,12 +114,12 @@ export const StyledMobileNetworkButton = styled(Button)(({ theme }) => ({
},
}))

export const MobileNetworkButton: FC<NetworkButtonProps> = ({ layer }) => {
export const MobileNetworkButton: FC<Omit<NetworkButtonProps, 'network'>> = ({ layer, onClick }) => {
const { t } = useTranslation()
const labels = getLabels(t)
const labels = getLayerLabels(t)

return (
<StyledMobileNetworkButton>
<StyledMobileNetworkButton onClick={onClick}>
{labels[layer]}
<Circle color={COLORS.eucalyptus} size={4}>
<CheckIcon sx={{ fontSize: 15, color: COLORS.white }} />
Expand Down
21 changes: 18 additions & 3 deletions src/app/components/PageLayout/NetworkSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FC } from 'react'
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import { useTheme } from '@mui/material/styles'
Expand All @@ -9,6 +10,8 @@ import { NetworkButton, MobileNetworkButton } from './NetworkButton'
import { COLORS } from '../../../styles/theme/colors'
import { Network, getNetworkNames } from '../../../types/network'
import { Layer } from '../../../oasis-indexer/api'
import { ParaTimePicker } from './../ParaTimePicker'
import { RouteUtils } from '../../utils/route-utils'

export const StyledBox = styled(Box)(({ theme }) => ({
marginLeft: `-${theme.spacing(1)}`,
Expand All @@ -30,10 +33,14 @@ type NetworkSelectorProps = {

export const NetworkSelector: FC<NetworkSelectorProps> = ({ layer, network }) => {
const { t } = useTranslation()
const navigate = useNavigate()
const theme = useTheme()
const isDesktop = useMediaQuery(theme.breakpoints.up('md'))
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
const labels = getNetworkNames(t)
const [openDrawer, setOpenDrawer] = useState(false)
const handleDrawerClose = () => setOpenDrawer(false)
const handleDrawerOpen = () => setOpenDrawer(true)

return (
<Box
Expand All @@ -43,7 +50,15 @@ export const NetworkSelector: FC<NetworkSelectorProps> = ({ layer, network }) =>
justifyContent: isDesktop ? 'center' : 'flex-end',
}}
>
{!isMobile && <NetworkButton layer={layer} network={network} />}
<ParaTimePicker
open={openDrawer}
onClose={handleDrawerClose}
onConfirm={(network: Network, layer: Layer) => {
handleDrawerClose()
navigate(RouteUtils.getDashboardRoute({ network, layer }))
}}
/>
{!isMobile && <NetworkButton layer={layer} network={network} onClick={handleDrawerOpen} />}
{isDesktop && network !== Network.mainnet && (
<StyledBox>
<Typography
Expand All @@ -56,7 +71,7 @@ export const NetworkSelector: FC<NetworkSelectorProps> = ({ layer, network }) =>
</Typography>
</StyledBox>
)}
{isMobile && <MobileNetworkButton layer={layer} network={network} />}
{isMobile && <MobileNetworkButton layer={layer} onClick={handleDrawerOpen} />}
</Box>
)
}
183 changes: 183 additions & 0 deletions src/app/components/ParaTimePicker/LayerDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { TFunction } from 'i18next'
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import { useTheme } from '@mui/material/styles'
import OpenInNewIcon from '@mui/icons-material/OpenInNew'
import CheckIcon from '@mui/icons-material/Check'
import Link from '@mui/material/Link'
import { Circle } from '../Circle'
import { COLORS } from '../../../styles/theme/colors'
import { Network, getNetworkNames } from '../../../types/network'
import { Layer } from '../../../oasis-indexer/api'
import { Link as RouterLink } from 'react-router-dom'
import { docs } from '../../utils/externalLinks'
import { TextList, TextListItem } from '../TextList'
import { getLayerLabels, getNetworkIcons } from '../../utils/content'

type LayerDetailsContent = {
description: string
rpcHttp: string
rpcWebSockets: string
chainHexId: string
chainDecimalId: string
docs: string
}

type NetworkDetails = Partial<Record<Layer, LayerDetailsContent>>
type Details = Record<Network, NetworkDetails>
const getDetails = (t: TFunction): Details => ({
[Network.mainnet]: {
[Layer.emerald]: {
description: t('paraTimePicker.mainnet.emerald'),
rpcHttp: 'https://emerald.oasis.dev',
rpcWebSockets: 'wss://emerald.oasis.dev/ws',
chainHexId: '0xa516',
chainDecimalId: '42262',
docs: docs.emerald,
},
[Layer.sapphire]: {
description: t('paraTimePicker.mainnet.sapphire'),
rpcHttp: 'https://sapphire.oasis.io',
rpcWebSockets: 'wss://sapphire.oasis.io/ws',
chainHexId: '0x5afe',
chainDecimalId: '23294',
docs: docs.sapphire,
},
},
[Network.testnet]: {
[Layer.emerald]: {
description: t('paraTimePicker.testnet.emerald'),
rpcHttp: 'https://testnet.emerald.oasis.dev',
rpcWebSockets: 'wss://testnet.emerald.oasis.dev/ws',
chainHexId: '0xa515',
chainDecimalId: '42261',
docs: docs.emerald,
},
[Layer.sapphire]: {
description: t('paraTimePicker.testnet.sapphire'),
rpcHttp: 'https://testnet.sapphire.oasis.dev',
rpcWebSockets: 'wss://testnet.sapphire.oasis.dev/ws',
chainHexId: '0x5aff',
chainDecimalId: '23295',
docs: docs.sapphire,
},
},
})

type LayerDetailsProps = {
activeLayer: Layer
hoveredLayer?: Layer
network: Network
selectedLayer?: Layer
}

// Prevent modal height from changing height when switching between layers
const contentMinHeight = '270px'

export const LayerDetails: FC<LayerDetailsProps> = ({
activeLayer,
hoveredLayer,
network,
selectedLayer,
}) => {
const { t } = useTranslation()
const theme = useTheme()
const labels = getNetworkNames(t)
const layerLabels = getLayerLabels(t)
const icons = getNetworkIcons()
const layer = hoveredLayer || selectedLayer || activeLayer
const details = getDetails(t)[network][layer]

if (!details) {
return null
}

return (
<Box sx={{ px: 5, py: 4, display: 'flex', minHeight: contentMinHeight }}>
<Box sx={{ pt: 1, pr: 4, color: COLORS.brandDark }}>
<Circle
color={COLORS.white}
size={5}
sx={{
borderColor: COLORS.brandDark,
borderWidth: theme.spacing(1),
borderStyle: 'solid',
}}
>
{icons[network]}
</Circle>
</Box>
<Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
pb: 2,
}}
>
<Typography sx={{ fontSize: 24, color: COLORS.brandDark, fontWeight: 700, mr: 3 }} component="span">
{layerLabels[layer]} {labels[network]}
</Typography>
<Typography sx={{ fontSize: 10, color: COLORS.paraTimeStatus, mr: 3 }} component="span">
{t('common.paraTimeOnline')}
</Typography>
<Circle color={COLORS.eucalyptus} size={4}>
<CheckIcon sx={{ fontSize: 12, color: COLORS.white }} />
</Circle>
</Box>
<Typography sx={{ fontSize: '12px', color: COLORS.brandExtraDark, pb: 2 }}>
{details.description}
</Typography>

<TextList>
<TextListItem>
{t('paraTimePicker.rpcHttp', {
endpoint: details.rpcHttp,
})}
</TextListItem>
<TextListItem>
{t('paraTimePicker.rpcWebSockets', {
endpoint: details.rpcWebSockets,
})}
</TextListItem>
<TextListItem>
{t('paraTimePicker.chainId')}
<TextList>
<TextListItem>
{t('paraTimePicker.hex', {
id: details.chainHexId,
})}
</TextListItem>
<TextListItem>
{t('paraTimePicker.decimal', {
id: details.chainDecimalId,
})}
</TextListItem>
</TextList>
</TextListItem>
</TextList>
<Link
component={RouterLink}
to={details.docs}
target="_blank"
rel="noopener noreferrer"
sx={{
display: 'flex',
alignItems: 'center',
gap: 2,
fontSize: '12px',
fontWeight: 400,
}}
>
{t('paraTimePicker.readMore', {
layer: layerLabels[layer],
network: labels[network],
})}
<OpenInNewIcon sx={{ fontSize: '16px' }} />
</Link>
</Box>
</Box>
)
}