Skip to content

Commit

Permalink
add voting page
Browse files Browse the repository at this point in the history
  • Loading branch information
pdp2121 committed Sep 18, 2023
1 parent 0752ddf commit 0ed55ad
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 3 deletions.
7 changes: 7 additions & 0 deletions public/locales/en-US/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,13 @@
"unauthorize": "unauthorize",
"missed_validations": "{{count}} missed validations",
"incomplete": "incomplete",
"base_fee": "BASE FEE",
"reserve_base": "RESERVE BASE",
"reserve_inc": "RESERVE INC.",
"amendment_name": "Name",
"amendment_id": "Amendment ID",
"vote": "Vote",
"no_amendment_in_voting": "There is no amendment in voting for this network at the moment.",
"required": "required",
"source": "source",
"destination": "destination",
Expand Down
2 changes: 1 addition & 1 deletion src/containers/App/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const TRANSACTION_ROUTE: RouteDefinition<{

export const VALIDATOR_ROUTE: RouteDefinition<{
identifier: string
tab?: 'details' | 'history'
tab?: 'details' | 'history' | 'voting'
}> = {
path: `/validators/:identifier/:tab?`,
}
Expand Down
2 changes: 1 addition & 1 deletion src/containers/Ledgers/LedgerMetrics.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const DEFAULTS = {
nUnl: [],
}

const renderXRP = (d, language) => {
export const renderXRP = (d, language) => {
const options = { ...CURRENCY_OPTIONS, currency: 'XRP' }
return localizeNumber(d, language, options)
}
Expand Down
122 changes: 121 additions & 1 deletion src/containers/Validators/VotingTab.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,124 @@
import { useTranslation } from 'react-i18next'
import { FC } from 'react'
import axios from 'axios'
import { useQuery } from 'react-query'

export const VotingTab =
import { ValidatorSupplemented } from '../shared/vhsTypes'
import { SimpleRow } from '../shared/components/Transaction/SimpleRow'

import './votingTab.scss'
import { renderXRP } from '../Ledgers/LedgerMetrics'
import {
FETCH_INTERVAL_ERROR_MILLIS,
FETCH_INTERVAL_VHS_MILLIS,
SERVER_ERROR,
} from '../shared/utils'
import { useAnalytics } from '../shared/analytics'

const DROPS_TO_XRP_FACTOR = 1000000

export const VotingTab: FC<{
validatorData: ValidatorSupplemented
network: string | undefined
}> = ({ validatorData, network }) => {
const { t } = useTranslation()
const { trackException } = useAnalytics()

const votedAmenments = new Set(
validatorData.amendments
? validatorData.amendments.map((amendment) => amendment.id)
: [],
)
const { data } = useQuery<Array<{ id: string; name: string }>>(
['fetchNetworkVotingData', network],
async () => fetchNetworkVote(network),
{
refetchInterval: (returnedData, _) =>
returnedData == null
? FETCH_INTERVAL_ERROR_MILLIS
: FETCH_INTERVAL_VHS_MILLIS,
refetchOnMount: true,
enabled: !!network,
},
)

function fetchNetworkVote(networkID: string | undefined) {
const url = `${process.env.VITE_DATA_URL}/amendments/vote/${networkID}`
return axios
.get(url)
.then((resp) => resp.data)
.then((response) =>
response.amendments.voting.amendments.map((amendment) => ({
id: amendment.id,
name: amendment.name,
})),
)
.catch((axiosError) => {
const status =
axiosError.response && axiosError.response.status
? axiosError.response.status
: SERVER_ERROR
trackException(`${url} --- ${JSON.stringify(axiosError)}`)
return Promise.reject(status)
})
}

const renderAmendment = (id: string, name: string, voted: boolean) => (
<div className="row-amendment">
<SimpleRow label={t('amendment_name')} className="amendment-name">
{name}
</SimpleRow>
<SimpleRow label={t('amendment_id')}>{id}</SimpleRow>
{voted ? (
<SimpleRow label={t('vote')} className="pill yea">
Yea
</SimpleRow>
) : (
<SimpleRow label={t('vote')} className="pill nay">
Nay
</SimpleRow>
)}
</div>
)

return (
<div className="voting">
<div className="metrics metrics-voting">
<div className="cell">
<div className="label">{t('base_fee')}</div>
<div>{renderXRP(validatorData.base_fee / DROPS_TO_XRP_FACTOR)}</div>
</div>
<div className="cell">
<div className="label">{t('reserve_base')}</div>
<div>
{renderXRP(validatorData.reserve_base / DROPS_TO_XRP_FACTOR)}
</div>
</div>
<div className="cell">
<div className="label">{t('reserve_inc')}</div>
<div>
{renderXRP(validatorData.reserve_inc / DROPS_TO_XRP_FACTOR)}
</div>
</div>
</div>
<div className="amendment-label">Amendments</div>
<div className="voting-amendment">
<div className="rows">
{data !== undefined && data.length > 0 ? (
data.map((amendment) => {
let voted = false
if (votedAmenments.has(amendment.id)) {
voted = true
}
return renderAmendment(amendment.id, amendment.name, voted)
})
) : (
<div className="no-match no-match-amendments">
<div className="hint">{t('no_amendment_in_voting')}</div>
</div>
)}
</div>
</div>
</div>
)
}
4 changes: 4 additions & 0 deletions src/containers/Validators/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ValidatorReport, ValidatorSupplemented } from '../shared/vhsTypes'
import NetworkContext from '../shared/NetworkContext'
import { VALIDATOR_ROUTE } from '../App/routes'
import { buildPath, useRouteParams } from '../shared/routing'
import { VotingTab } from './VotingTab'

const ERROR_MESSAGES = {
[NOT_FOUND]: {
Expand Down Expand Up @@ -172,6 +173,9 @@ export const Validator = () => {
case 'history':
body = <HistoryTab reports={reports ?? []} />
break
case 'voting':
body = data && <VotingTab validatorData={data} network={network} />
break
default:
body = data && <SimpleTab data={data} width={width} />
break
Expand Down
90 changes: 90 additions & 0 deletions src/containers/Validators/votingTab.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
@import '../shared/css/variables';

.voting {
margin-left: 24px;

.metrics {
&.metrics-voting {
width: auto;
padding-left: 0;
text-align: left;

.cell {
display: flex;
justify-content: space-between;
margin: 0 !important;
text-align: left;

@include for-size(tablet-landscape-up) {
display: inline-block;
}
}
}
}

.amendment-label {
margin-top: 48px;
font-size: 24px;
font-weight: 700;
}

.voting-amendment {
font-size: 14px;

.row-amendment {
margin-top: 32px;
background-color: $black-80;
}

.amendment-name {
color: $green-30
}

.row {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
padding: 16px;
border-bottom: 1px solid $black-70;
}

.label {
margin-top: 0;
font-weight: 100;
}

.value {
overflow-x: scroll;
scrollbar-width: none;
text-align: end;

&::-webkit-scrollbar {
/* WebKit */
width: 0;
height: 0;
}
}
}

.pill {
align-items: center;
justify-content: center;
padding: 2px 12px;
border-radius: 30px;
color: $black-100;

&.yea {
background-color: $green-60;
}

&.nay {
background-color: $black-30;
}
}

.no-match {
&.no-match-amendments {
margin: 32px 0;
}
}
}
4 changes: 4 additions & 0 deletions src/containers/shared/vhsTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ export interface ValidatorSupplemented extends ValidatorResponse {
ledger_hash: string
// eslint-disable-next-line camelcase -- mimicking rippled
last_ledger_time: string
amendments: Array<{ id: string; name: string }>
base_fee: number
reserve_base: number
reserve_inc: number
}

export interface StreamValidator extends ValidatorResponse {
Expand Down

0 comments on commit 0ed55ad

Please sign in to comment.