Skip to content

Commit

Permalink
fix(FE): use highchart instead of rechart, add card new UI (#442)
Browse files Browse the repository at this point in the history
  • Loading branch information
tetogomez authored May 3, 2021
1 parent 105fc4b commit 7699dd3
Show file tree
Hide file tree
Showing 7 changed files with 502 additions and 204 deletions.
205 changes: 205 additions & 0 deletions webapp/src/components/InformationCard/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import React, { memo, useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { makeStyles, useTheme } from '@material-ui/core/styles'
import Card from '@material-ui/core/Card'
import CardHeader from '@material-ui/core/CardHeader'
import CardActions from '@material-ui/core/CardActions'
import Collapse from '@material-ui/core/Collapse'
import { useTranslation } from 'react-i18next'
import Box from '@material-ui/core/Box'
import Typography from '@material-ui/core/Typography'
import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined'
import Link from '@material-ui/core/Link'
import Button from '@material-ui/core/Button'
import useMediaQuery from '@material-ui/core/useMediaQuery'

import moment from 'moment'
import 'flag-icon-css/css/flag-icon.min.css'

import { onImgError } from '../../utils'
import { generalConfig } from '../../config'
import CountryFlag from '../CountryFlag'
import ProducerSocialLinks from '../ProducerSocialLinks'
import ProducerHealthIndicators from '../ProducerHealthIndicators'

import styles from './styles'

const useStyles = makeStyles(styles)

const InformationCard = ({ producer, rank, onNodeClick }) => {
const classes = useStyles()
const theme = useTheme()
const { t } = useTranslation('producerCardComponent')

const matches = useMediaQuery(theme.breakpoints.up('lg'))
const [expanded, setExpanded] = useState(false)
const [producerOrg, setProducerOrg] = useState({})
const [producerNodes, setProducerNodes] = useState([])

const handleExpandClick = () => {
setExpanded(!expanded)
}

useEffect(() => {
setProducerOrg(producer.bp_json?.org || {})
setProducerNodes(producer.bp_json?.nodes || [])
}, [producer])

return (
<Card className={classes.root}>
<CardHeader title={rank ? `Rank #${rank} -Top` : 'No Rank'} />
<Box className={classes.wrapper}>
<Box className={classes.media}>
<img
src={
producerOrg.branding?.logo_256 ||
generalConfig.defaultProducerLogo
}
onError={onImgError(generalConfig.defaultProducerLogo)}
alt="avatar"
/>
<Typography className="bpName">
{producerOrg.candidate_name ||
producerOrg.organization_name ||
producer.owner}
</Typography>
<Typography>12letteracco</Typography>
</Box>
<Collapse in={matches ? true : expanded} timeout="auto" unmountOnExit>
<Box className="bodyWrapper">
<Box className={classes.info}>
<Typography variant="overline">Info</Typography>
<Typography variant="body1">
Location:{` ${producerOrg.location?.name || 'N/A'} `}
<CountryFlag code={producerOrg.location?.country} />
</Typography>
<Typography variant="body1">
Website:{' '}
<Link
href={producerOrg.website}
target="_blank"
rel="noopener noreferrer"
>
{producerOrg.website}
</Link>
</Typography>
<Typography variant="body1">
Email:{' '}
{producerOrg.email ? (
<Link
href={`mailto:${producerOrg.email}`}
target="_blank"
rel="noopener noreferrer"
>
{producerOrg.email}
</Link>
) : (
'N/A'
)}
</Typography>
<Typography variant="body1">
Onwership Disclosure:{' '}
{producerOrg.chain_resources ? (
<Link
href={producerOrg.chain_resources}
target="_blank"
rel="noopener noreferrer"
>
{producerOrg.ownership_disclosure}
</Link>
) : (
'N/A'
)}
</Typography>
<Typography variant="body1">
Chain Resources:{' '}
{producerOrg.chain_resources ? (
<Link
href={producerOrg.chain_resources}
target="_blank"
rel="noopener noreferrer"
>
{producerOrg.chain_resources}
</Link>
) : (
'N/A'
)}
</Typography>
</Box>
<Box className={classes.twoBoxes}>
<Box className="stats">
<Typography variant="overline">Stats</Typography>
<Typography variant="body1">Votes: N/A</Typography>
<Typography variant="body1">Rewards: 0 eos</Typography>
<Typography variant="body1">
Last Checked:
{` ${moment(new Date()).diff(
moment(producer.updated_at),
'seconds'
)} ${t('secondsAgo')}`}
</Typography>
<Typography variant="body1">
Missed Blocks:{' '}
{(producer.missed_blocks || []).reduce(
(result, current) => result + current.value,
0
)}
</Typography>
</Box>
<Box className="nodes">
<Typography variant="overline">{t('nodes')}</Typography>
<Box>
{producerNodes.length > 0 && (
<>
{producerNodes.map((node, i) => (
<Typography variant="body1" key={`node-${i}`}>
{node.node_name || node.node_type}{' '}
<InfoOutlinedIcon
onClick={onNodeClick({ node, producer })}
/>
</Typography>
))}
</>
)}
</Box>
</Box>
</Box>
<Box className={classes.twoBoxes}>
<Box className="healthStatus">
<Typography variant="overline">Health Social</Typography>
<ProducerHealthIndicators producer={producer} />
</Box>
<Box className="social">
<Typography variant="overline">Social</Typography>
<Box>
<ProducerSocialLinks items={producerOrg.social || {}} />
</Box>
</Box>
</Box>
</Box>
</Collapse>
</Box>
<CardActions disableSpacing className={classes.cardActions}>
<Box className={classes.expandMore}>
<Button color="primary" onClick={handleExpandClick}>
{expanded ? 'Collapse' : 'More Info'}
</Button>
</Box>
</CardActions>
</Card>
)
}

InformationCard.propTypes = {
producer: PropTypes.any,
rank: PropTypes.number,
onNodeClick: PropTypes.func
}

InformationCard.defaultProps = {
producer: {},
rank: 0,
onNodeClick: () => {}
}

export default memo(InformationCard)
149 changes: 149 additions & 0 deletions webapp/src/components/InformationCard/styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
export default (theme) => ({
root: {
width: '100%',
marginBottom: theme.spacing(2),
paddingBottom: 0,
[theme.breakpoints.up('sm')]: {
width: 300
},
[theme.breakpoints.up('lg')]: {
width: '100%',
paddingBottom: theme.spacing(2)
}
},
wrapper: {
display: 'flex',
flexDirection: 'column',
padding: theme.spacing(4),
'& .bodyWrapper': {
display: 'flex',
flexDirection: 'column'
},
[theme.breakpoints.up('lg')]: {
flexDirection: 'row',
'& .bodyWrapper': {
flexDirection: 'row'
}
}
},
media: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: 0,
'& img': {
width: 82,
height: 82,
borderRadius: 40
},
'& .bpName': {
fontSize: 28,
lineHeight: '34px',
letterSpacing: '-0.233333px',
marginBottom: theme.spacing(1),
textAlign: 'center'
},
[theme.breakpoints.up('lg')]: {
padding: theme.spacing(0, 6)
}
},
expand: {
transform: 'rotate(0deg)',
marginLeft: 'auto',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest
})
},
expandOpen: {
transform: 'rotate(180deg)'
},
expandMore: {
width: '100%',
display: 'flex',
justifyContent: 'center',
'& .MuiButtonBase-root': {
textTransform: 'capitalize'
}
},
info: {
borderLeft: 'none',
marginBottom: theme.spacing(3),
'& .MuiTypography-body1': {
margin: theme.spacing(1, 0),
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
maxWidth: 350
},
[theme.breakpoints.up('lg')]: {
borderLeft: '1px solid rgba(0, 0, 0, 0.2)',

padding: theme.spacing(0, 2),
marginBottom: 0
}
},
twoBoxes: {
marginBottom: theme.spacing(3),
borderLeft: 'none',
display: 'flex',
justifyContent: 'space-between',
'& .MuiTypography-body1': {
margin: theme.spacing(1, 0),
display: 'flex',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden'
},
'& .nodes': {
borderLeft: 'none',
width: 100,
'& .MuiSvgIcon-root': {
marginLeft: theme.spacing(1),
fontSize: 20
}
},
'& .healthStatus': {
'& .MuiSvgIcon-root': {
marginLeft: theme.spacing(1),
fontSize: 20
}
},
'& .social': {
borderLeft: 'none',
width: 100,
'& a': {
display: 'flex'
},
'& svg': {
marginRight: theme.spacing(1)
}
},
'& .success': {
color: theme.palette.success.main
},
'& .error': {
color: theme.palette.error.main
},
'& .warning': {
color: theme.palette.warning.main
},
[theme.breakpoints.up('lg')]: {
padding: theme.spacing(0, 2),
marginBottom: 0,
borderLeft: '1px solid rgba(0, 0, 0, 0.2)',

'& .nodes, .social': {
borderLeft: '1px solid rgba(0, 0, 0, 0.2)',

paddingLeft: theme.spacing(1),
marginRight: theme.spacing(2)
}
}
},
cardActions: {
display: 'flex',
[theme.breakpoints.up('lg')]: {
display: 'none'
}
}
})
20 changes: 5 additions & 15 deletions webapp/src/components/ProducerHealthIndicators.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,14 @@ import PropTypes from 'prop-types'
import { makeStyles } from '@material-ui/styles'
import Tooltip from '@material-ui/core/Tooltip'
import { useTranslation } from 'react-i18next'
import WarningIcon from '@material-ui/icons/Warning'

import DoneAllIcon from '@material-ui/icons/DoneAll'
import DoneOutlinedIcon from '@material-ui/icons/DoneOutlined'
import ReportProblemOutlinedIcon from '@material-ui/icons/ReportProblemOutlined'
import { Box, Typography } from '@material-ui/core'

const useStyles = makeStyles(() => ({
wrapper: {
display: 'flex',
justifyContent: 'space-between'
},
valid: {
color: 'green'
},
error: {
color: 'orange'
},
warning: {
color: 'yellow'
alignItems: 'center'
}
}))

Expand All @@ -39,8 +29,8 @@ const ProducerHealthIndicators = ({ producer }) => {
>
<Box className={classes.wrapper}>
<Typography>{t(`hs_${item.name}`)}</Typography>
{item.valid && <DoneAllIcon className={classes.valid} />}
{!item.valid && <WarningIcon className={classes.error} />}
{item.valid && <DoneOutlinedIcon className="success" />}
{!item.valid && <ReportProblemOutlinedIcon className="warning" />}
</Box>
</Tooltip>
))}
Expand Down
Loading

0 comments on commit 7699dd3

Please sign in to comment.