Skip to content

Commit

Permalink
add support to link metric cards
Browse files Browse the repository at this point in the history
  • Loading branch information
ramirotw committed Apr 23, 2020
1 parent d1c9948 commit f8b06b9
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 57 deletions.
125 changes: 69 additions & 56 deletions src/components/PollDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
getTopVotersTableData,
} from './helpers'
import styled from 'styled-components'
import LinkableComponent from '../common/LinkableComponent'

const CardStyled = styled(Card)`
height: ${props => props.theme.defaultCardHeight};
Expand Down Expand Up @@ -131,6 +132,8 @@ function PollDetails(props: Props) {
}

const setModal = (data: any, isChart: boolean = false): void => {
if (isModalOpen) return

setModalOpen(true)
setModalChart(isChart)
setModalData(data)
Expand Down Expand Up @@ -250,64 +253,74 @@ function PollDetails(props: Props) {
<NoData>Cannot fetch poll description.</NoData>
)}
</CardStyled>
<CardStyled style={{ gridArea: 'col4' }}>
<VotersDistribution content="Vote Count By Option" component="votersDistribution" />
</CardStyled>
<CardStyled style={{ gridArea: 'col5' }}>
{pollPerOptionData.length === 0 ? (
<Loading />
) : (
<PollPerOption content="Voters Per Option" isVoter component="pollPerOptionVoters" />
)}
</CardStyled>
<CardStyled style={{ gridArea: 'col6' }}>
{pollPerOptionData.length === 0 ? (
<Loading />
) : (
<PollPerOption content="MKR Votes Per Option" component="pollPerOptionMkr" />
)}
</CardStyled>
<LinkableComponent id="VOTE_COUNT">
<CardStyled style={{ gridArea: 'col4' }}>
<VotersDistribution content="Vote Count By Option" component="votersDistribution" />
</CardStyled>
</LinkableComponent>
<LinkableComponent id="VOTERS_PER_OPTION">
<CardStyled style={{ gridArea: 'col5' }}>
{pollPerOptionData.length === 0 ? (
<Loading />
) : (
<PollPerOption content="Voters Per Option" isVoter component="pollPerOptionVoters" />
)}
</CardStyled>
</LinkableComponent>
<LinkableComponent id="VOTES_PER_OPTION">
<CardStyled style={{ gridArea: 'col6' }}>
{pollPerOptionData.length === 0 ? (
<Loading />
) : (
<PollPerOption content="MKR Votes Per Option" component="pollPerOptionMkr" />
)}
</CardStyled>
</LinkableComponent>
</PollDetailContainer>
<CenteredRowGrid>
<CardStyled>
{mkrDistributionData.length === 0 ? (
<Loading />
) : (
<MakerDistribution content="MKR Count By Option" component="makerDistribution" />
)}
</CardStyled>
<CardStyled style={{ padding: 0 }}>
<StrippedTableWrapper
markdown
info={`This tile shows a leaderboard for the largest MKR holders that have voted in this poll. This is primarily a navigational tool that provides access to each address’s voting history and etherscan address. <br><br> This metric is generated using the Voted event emitted by the PollingEmitter governance contract. The total MKR held by each address voting in this poll is counted and added to this list. This MKR value is then converted into a percentage of the total MKR voting in this poll. This list is then sorted large to small and displayed.`}
links={[
{
title: 'MakerDAO Governance Graph',
uri: 'https://thegraph.com/explorer/subgraph/protofire/makerdao-governance?query=Polls',
},
{
title: 'MKR Registry Graph',
uri: 'https://thegraph.com/explorer/subgraph/protofire/mkr-registry?query=Account%20balances',
},
]}
content="Top Voters"
>
<StrippedRowsContainer>
{Object.keys(topVoters).length === 0 ? (
<Loading />
) : (
getTopVotersTableData(topVoters)
.slice(0, 8)
.map(el => (
<StrippedTableRow key={el.key}>
<StrippedTableCell>{el.supports}%</StrippedTableCell>
<StrippedTableCell>{el.sender}</StrippedTableCell>
</StrippedTableRow>
))
)}
</StrippedRowsContainer>
</StrippedTableWrapper>
</CardStyled>
<LinkableComponent id="MKR_COUNT">
<CardStyled>
{mkrDistributionData.length === 0 ? (
<Loading />
) : (
<MakerDistribution content="MKR Count By Option" component="makerDistribution" />
)}
</CardStyled>
</LinkableComponent>
<LinkableComponent id="TOP_VOTERS">
<CardStyled style={{ padding: 0 }}>
<StrippedTableWrapper
markdown
info={`This tile shows a leaderboard for the largest MKR holders that have voted in this poll. This is primarily a navigational tool that provides access to each address’s voting history and etherscan address. <br><br> This metric is generated using the Voted event emitted by the PollingEmitter governance contract. The total MKR held by each address voting in this poll is counted and added to this list. This MKR value is then converted into a percentage of the total MKR voting in this poll. This list is then sorted large to small and displayed.`}
links={[
{
title: 'MakerDAO Governance Graph',
uri: 'https://thegraph.com/explorer/subgraph/protofire/makerdao-governance?query=Polls',
},
{
title: 'MKR Registry Graph',
uri: 'https://thegraph.com/explorer/subgraph/protofire/mkr-registry?query=Account%20balances',
},
]}
content="Top Voters"
>
<StrippedRowsContainer>
{Object.keys(topVoters).length === 0 ? (
<Loading />
) : (
getTopVotersTableData(topVoters)
.slice(0, 8)
.map(el => (
<StrippedTableRow key={el.key}>
<StrippedTableCell>{el.supports}%</StrippedTableCell>
<StrippedTableCell>{el.sender}</StrippedTableCell>
</StrippedTableRow>
))
)}
</StrippedRowsContainer>
</StrippedTableWrapper>
</CardStyled>
</LinkableComponent>
</CenteredRowGrid>

{isModalOpen && (
Expand Down
11 changes: 11 additions & 0 deletions src/components/common/ChartWrapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { CardTitle, ExpandIcon, ChartSelect, Modal, InfoIcon, CloseIcon, Descrip
import { filters, getIconContainer } from '../../../utils'
import { IconContainer } from '../../common/styled'
import styled from 'styled-components'
import { LinkableContext } from '../LinkableComponent'
import CopyLink from '../LinkableComponent/CopyLink'

const Right = styled.div`
margin-left: auto;
Expand Down Expand Up @@ -45,6 +47,7 @@ type Props = {
versus?: string
info?: string
links?: Array<any>
id?: string
}

function ChartWrapper(props: Props) {
Expand All @@ -63,12 +66,20 @@ function ChartWrapper(props: Props) {
links,
} = props
const [isInfoModalOpen, setInfoModalOpen] = useState(false)
const linkable = React.useContext(LinkableContext)

React.useEffect(() => {
if (linkable.active) {
linkable.onInitCallback(handleModal)
}
}, [linkable, handleModal])

return (
<>
<CardTitle content={content} versus={versus}>
{!hideFilters && <ChartSelect value={value} values={filters} onChange={onChange} />}
<Right>
<CopyLink />
<InfoIconContainer>{info && <InfoIcon onClick={() => setInfoModalOpen(true)} />}</InfoIconContainer>
{!hideIcon && getIconContainer(ExpandIcon, handleModal, isModalOpen)}
</Right>
Expand Down
38 changes: 38 additions & 0 deletions src/components/common/LinkableComponent/CopyLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react'
import styled from 'styled-components'
import Tooltip from '@material-ui/core/Tooltip'
import { LinkableContext } from '.'
import CopyToClipboard from '../CopyToClipboard'
import { IconContainer } from '../styled'

const HashContainer = styled.div`
display: flex;
position: relative;
bottom: 5px;
right: 9px;
cursor: pointer;
`

export default function CopyLink({ tooltip = 'Copy Metric link' }) {
const { id } = React.useContext(LinkableContext)

return id ? (
<HashContainer>
<CopyToClipboard>
{({ copy }) => (
<IconContainer>
<Tooltip title={tooltip} arrow>
<span
onClick={() => {
copy(window.location.origin + window.location.pathname + `#${id}`)
}}
>
#
</span>
</Tooltip>
</IconContainer>
)}
</CopyToClipboard>
</HashContainer>
) : null
}
43 changes: 43 additions & 0 deletions src/components/common/LinkableComponent/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react'
import { useLocation } from 'react-router-dom'
import { GlowingWrapper } from '../styled'

export const LinkableContext = React.createContext({ active: false, onInitCallback: fn => {}, id: '' })

export default function LinkableComponent({ children, id }) {
const location = useLocation()
const wrapperRef = React.useRef<HTMLElement>(null)
const [initialized, setInitialized] = React.useState(false)
const glow = location.hash === `#${id}`
const onInitCallback = React.useCallback(
(fn: Function) => {
if (initialized) return

fn()
setInitialized(true)
},
[initialized],
)
const value = React.useMemo(
() => ({
active: glow,
onInitCallback,
id,
}),
[glow, onInitCallback, id],
)

React.useEffect(() => {
if (glow && wrapperRef && wrapperRef.current) {
wrapperRef.current.scrollIntoView({ behavior: 'smooth' })
}
}, [glow])

return (
<LinkableContext.Provider value={value}>
<GlowingWrapper ref={wrapperRef} glow={glow}>
{children}
</GlowingWrapper>
</LinkableContext.Provider>
)
}
2 changes: 2 additions & 0 deletions src/components/common/StrippedTableWrapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import styled from 'styled-components'
import { StrippedRowsContainer, CardTitle, ViewAll, Modal, InfoIcon, CloseIcon, DescriptionBox } from '..'
import { getIconContainer } from '../../../utils'
import { IconContainer } from '../styled'
import CopyLink from '../LinkableComponent/CopyLink'

const TitleWrapper = styled.div`
flex-shrink: 0;
Expand Down Expand Up @@ -63,6 +64,7 @@ function StrippedTableWrapper(props: Props) {
<TitleWrapper>
<CardTitle content={content}>
<Right>
<CopyLink />
<InfoIconContainer>{info && <InfoIcon onClick={() => setInfoModalOpen(true)} />}</InfoIconContainer>
{handleModal ? getIconContainer(() => <ViewAll>View All</ViewAll>, handleModal, isModalOpen) : null}
</Right>
Expand Down
22 changes: 21 additions & 1 deletion src/components/common/styled/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import styled, { css } from 'styled-components'
import styled, { css, keyframes } from 'styled-components'

export const LegendLi = styled.li`
display: inline-block;
Expand Down Expand Up @@ -27,6 +27,19 @@ export const Card = styled.div`
}
`

const glow = color => keyframes`
0% { box-shadow: 0px 0px 33px -2px ${color}}
100% { box-shadow: 0 }
`

export const GlowingWrapper = styled.div`
${props =>
props.glow &&
css`
animation: ${glow(props.theme.colors.primary)} 10s linear;
`}
`

export const PageTitle = styled.h1`
color: ${props => props.theme.colors.textCommon};
font-size: 20px;
Expand Down Expand Up @@ -195,6 +208,13 @@ export const CenteredRowGrid = styled.div`
width: 401px;
margin-right: ${props => props.theme.separation.gridSeparation};
}
${GlowingWrapper} {
margin-right: ${props => props.theme.separation.gridSeparation};
${Card} {
margin-right: 0;
}
}
}
`

Expand Down

0 comments on commit f8b06b9

Please sign in to comment.