Skip to content

Commit

Permalink
fix web-persistence graphql schema
Browse files Browse the repository at this point in the history
  • Loading branch information
MonikaCat committed Feb 7, 2024
1 parent 0e0222b commit c569464
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Big from 'big.js';
import { useRouter } from 'next/router';
import * as R from 'ramda';
import { useCallback, useState } from 'react';
import chainConfig from '@/chainConfig';
import {
ProposalDetailsTallyQuery,
useProposalDetailsTallyQuery,
} from '@/graphql/types/general_types';
import type { VotesGraphState } from '@/screens/proposal_details/components/votes_graph/types';
import { formatToken } from '@/utils/format_token';

const { votingPowerTokenUnit } = chainConfig();

const defaultTokenUnit: TokenUnit = {
value: '0',
baseDenom: '',
displayDenom: '',
exponent: 0,
};

export const useVotesGraph = () => {
const router = useRouter();
const [state, setState] = useState<VotesGraphState>({
votes: {
yes: defaultTokenUnit,
no: defaultTokenUnit,
abstain: defaultTokenUnit,
veto: defaultTokenUnit,
},
bonded: defaultTokenUnit,
quorum: '0',
});

const handleSetState = useCallback(
(stateChange: (prevState: VotesGraphState) => VotesGraphState) => {
setState((prevState) => {
const newState = stateChange(prevState);
return R.equals(prevState, newState) ? prevState : newState;
});
},
[]
);

useProposalDetailsTallyQuery({
variables: {
proposalId: parseFloat((router?.query?.id as string) ?? '0'),
},
onCompleted: (data) => {
handleSetState((prevState) => ({ ...prevState, ...foramtProposalTally(data) }));
},
});

const foramtProposalTally = (data: ProposalDetailsTallyQuery) => {
const quorumRaw = data.quorum?.[0]?.params?.quorum ?? '0';

return {
votes: {
yes: formatToken(data?.proposalTallyResult?.[0]?.yes ?? '0', votingPowerTokenUnit),
no: formatToken(data?.proposalTallyResult?.[0]?.no ?? '0', votingPowerTokenUnit),
veto: formatToken(data?.proposalTallyResult?.[0]?.noWithVeto ?? '0', votingPowerTokenUnit),
abstain: formatToken(data?.proposalTallyResult?.[0]?.abstain ?? '0', votingPowerTokenUnit),
},
bonded: formatToken(data?.stakingPool?.[0]?.bondedTokens ?? '0', votingPowerTokenUnit),
quorum: Big(quorumRaw)?.times(100).toFixed(2),
};
};

return {
state,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import Box from '@/components/box';
import InfoPopover from '@/components/info_popover';
import QuorumExplanation from '@/screens/proposal_details/components/votes_graph/components/quorum_explanation';
import { useVotesGraph } from '@/screens/proposal_details/components/votes_graph/hooks';
import useStyles from '@/screens/proposal_details/components/votes_graph/styles';
import { formatGraphData } from '@/screens/proposal_details/components/votes_graph/utils';
import Typography from '@mui/material/Typography';
import Big from 'big.js';
import useAppTranslation from '@/hooks/useAppTranslation';
import dynamic from 'next/dynamic';
import numeral from 'numeral';
import { FC } from 'react';
import { Cell, Pie, PieChart } from 'recharts';

const DynamicPieChart = dynamic(() => Promise.resolve(PieChart), { ssr: false });

const VotesGraph: FC<ComponentDefault> = (props) => {
const { classes, cx, theme } = useStyles();
const { t } = useAppTranslation('proposals');
const { state } = useVotesGraph();
const { votes } = state;
const { quorum } = state;

const total = Big(votes.yes.value)
.plus(votes.no.value)
.plus(votes.veto.value)
.plus(votes.abstain.value);

const formattedData = formatGraphData({
data: votes,
theme,
total,
});
const bonded = Big(state.bonded?.value || 0);
const totalVotedFormat = numeral(total.toFixed(2)).format('0,0.[00]');
const totalBondedFormat = numeral(bonded.toNumber()).format('0,0.[00]');
const totalVotedPercent =
total.gt(0) && !bonded.eq(0)
? `${numeral(Big(total.toFixed(2)).div(bonded)?.times(100).toFixed(2)).format('0.[00]')}%`
: '0%';

return (
<Box className={cx(classes.root, props.className)}>
<div className={classes.pie}>
<DynamicPieChart width={250} height={250}>
<Pie
cx="50%"
cy="50%"
stroke="none"
dataKey="value"
data={formattedData}
fill="#8884d8"
isAnimationActive={false}
>
{formattedData.map((entry, index) => (
// eslint-disable-next-line react/no-array-index-key
<Cell key={`cell-${index}`} fill={entry.color} stroke={entry.color} />
))}
</Pie>
</DynamicPieChart>
</div>
<div className={classes.legend}>
<div className={classes.total}>
<Typography variant="caption">
{t('votedTotalCaption', {
totalVotedPercent,
})}
</Typography>
<Typography variant="h2">
{totalVotedFormat} / {totalBondedFormat}
</Typography>
</div>

{formattedData
.filter((x) => String(x.name) !== 'empty')
.map((x) => (
<div key={x.name} className={cx(classes.voteItem, x.name)}>
<Typography variant="caption">
{t(x.name)} ({x.percentage})
</Typography>
<Typography>{x.display}</Typography>
</div>
))}
</div>
<div className={classes.popOver}>
<InfoPopover content={<QuorumExplanation quorum={quorum} />} />
</div>
</Box>
);
};

export default VotesGraph;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface VotesType {
yes: TokenUnit;
no: TokenUnit;
abstain: TokenUnit;
veto: TokenUnit;
}
export interface VotesGraphState {
votes: VotesType;
bonded: TokenUnit;
quorum: string;
}
95 changes: 95 additions & 0 deletions apps/web-persistence/src/screens/proposal_details/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useRouter } from 'next/router';
import * as R from 'ramda';
import { useCallback, useState } from 'react';
import type { ProposalState } from '@/screens/proposal_details/types';
import { ProposalDetailsQuery, useProposalDetailsQuery } from '@/graphql/types/general_types';

// =========================
// overview
// =========================
const formatOverview = (data: ProposalDetailsQuery) => {
const DEFAULT_TIME = '0001-01-01T00:00:00';
let votingStartTime = data?.proposal?.[0]?.votingStartTime ?? DEFAULT_TIME;
votingStartTime = votingStartTime === DEFAULT_TIME ? '' : votingStartTime;
let votingEndTime = data?.proposal?.[0]?.votingEndTime ?? DEFAULT_TIME;
votingEndTime = votingEndTime === DEFAULT_TIME ? '' : votingEndTime;

const overview = {
proposer: data?.proposal?.[0]?.proposer ?? '',
content: data?.proposal?.[0]?.content ?? '',
title: data?.proposal?.[0]?.title ?? '',
id: data?.proposal?.[0]?.proposalId ?? '',
description: data?.proposal?.[0]?.description ?? '',
status: data?.proposal?.[0]?.status ?? '',
submitTime: data?.proposal?.[0]?.submitTime ?? '',
depositEndTime: data?.proposal?.[0]?.depositEndTime ?? '',
votingStartTime,
votingEndTime,
};

return overview;
};

// ==========================
// parsers
// ==========================
const formatProposalQuery = (data: ProposalDetailsQuery) => {
const stateChange: Partial<ProposalState> = {
loading: false,
};

if (!data.proposal.length) {
stateChange.exists = false;
return stateChange;
}

stateChange.overview = formatOverview(data);

return stateChange;
};

export const useProposalDetails = () => {
const router = useRouter();
const [state, setState] = useState<ProposalState>({
loading: true,
exists: true,
overview: {
proposer: '',
content: {
recipient: '',
amount: [],
},
title: '',
id: 0,
description: '',
status: '',
submitTime: '',
depositEndTime: '',
votingStartTime: '',
votingEndTime: '',
},
});

const handleSetState = useCallback((stateChange: (prevState: ProposalState) => ProposalState) => {
setState((prevState) => {
const newState = stateChange(prevState);
return R.equals(prevState, newState) ? prevState : newState;
});
}, []);

// ==========================
// fetch data
// ==========================
useProposalDetailsQuery({
variables: {
proposalId: parseFloat((router?.query?.id as string) ?? '0'),
},
onCompleted: (data) => {
handleSetState((prevState) => ({ ...prevState, ...formatProposalQuery(data) }));
},
});

return {
state,
};
};
24 changes: 24 additions & 0 deletions apps/web-persistence/src/screens/proposal_details/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export interface OverviewType {
title: string;
id: number;
proposer: string;
description: string;
status: string;
submitTime: string;
depositEndTime: string;
votingStartTime: string | null;
votingEndTime: string | null;
content: {
recipient: string;
amount: Array<{
amount: string;
denom: string;
}>;
};
}

export interface ProposalState {
loading: boolean;
exists: boolean;
overview: OverviewType;
}

0 comments on commit c569464

Please sign in to comment.