VotersListContainer.tsx
1 import { Trans } from '@lingui/macro'; 2 import { Box, Button, CircularProgress, Typography, useMediaQuery, useTheme } from '@mui/material'; 3 import { useState } from 'react'; 4 import { Row } from 'src/components/primitives/Row'; 5 import { ProposalVotes } from 'src/hooks/governance/useProposalVotes'; 6 import { useRootStore } from 'src/store/root'; 7 import { AIP } from 'src/utils/mixPanelEvents'; 8 9 import { ProposalVoteInfo } from '../utils/formatProposal'; 10 import { VotersList } from './VotersList'; 11 import { VotersListModal } from './VotersListModal'; 12 13 type VotersListProps = { 14 proposal: ProposalVoteInfo; 15 proposalVotes: ProposalVotes; 16 }; 17 18 export type GovernanceVoter = { 19 address: string; 20 ensName: string | null; 21 votingPower: number; 22 twitterAvatar: string | null; 23 support: boolean; 24 }; 25 26 export type VotersData = { 27 yaes: GovernanceVoter[]; 28 nays: GovernanceVoter[]; 29 combined: GovernanceVoter[]; 30 }; 31 32 export const VotersListContainer = ({ proposal, proposalVotes }: VotersListProps): JSX.Element => { 33 const [votersModalOpen, setVotersModalOpen] = useState(false); 34 const { breakpoints } = useTheme(); 35 const mdScreen = useMediaQuery(breakpoints.only('md')); 36 const trackEvent = useRootStore((store) => store.trackEvent); 37 38 const handleOpenAllVotes = () => { 39 trackEvent(AIP.VIEW_ALL_VOTES); 40 setVotersModalOpen(true); 41 }; 42 43 if (false) 44 return ( 45 <Box sx={{ mt: 8, mb: 12 }}> 46 <Row sx={{ mb: 3 }}> 47 <Typography sx={{ ml: 'auto' }} variant="subheader2" color="text.secondary"> 48 <Trans>Votes</Trans> 49 </Typography> 50 </Row> 51 <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}> 52 <CircularProgress size={24} sx={{ my: 4 }} /> 53 </Box> 54 </Box> 55 ); 56 57 if (false) 58 return ( 59 <Box sx={{ mt: 8, mb: 12 }}> 60 <Row sx={{ mb: 3 }}> 61 <Typography sx={{ ml: 'auto' }} variant="subheader2" color="text.secondary"> 62 <Trans>Votes</Trans> 63 </Typography> 64 </Row> 65 <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', mt: 8 }}> 66 <Typography variant="helperText" color="error.main"> 67 <Trans>Failed to load proposal voters. Please refresh the page.</Trans> 68 </Typography> 69 </Box> 70 </Box> 71 ); 72 73 if (!proposalVotes || proposalVotes.combinedVotes.length === 0) return <Box sx={{ mt: 8 }} />; 74 75 return ( 76 <Box sx={{ my: 8 }}> 77 <Row sx={{ mb: 3 }}> 78 <Typography variant="subheader2" color="text.secondary"> 79 {proposalVotes.combinedVotes.length > 10 ? ( 80 <Trans>Top 10 addresses</Trans> 81 ) : ( 82 <Trans>Addresses</Trans> 83 )} 84 </Typography> 85 <Typography variant="subheader2" color="text.secondary"> 86 <Trans>Votes</Trans> 87 </Typography> 88 </Row> 89 <VotersList 90 compact={mdScreen} 91 voters={proposalVotes.combinedVotes.slice(0, 10)} 92 sx={{ my: 4, pr: 2.25 }} 93 /> 94 {proposalVotes.combinedVotes.length > 10 && ( 95 <Button variant="outlined" fullWidth onClick={handleOpenAllVotes}> 96 <Trans>View all votes</Trans> 97 </Button> 98 )} 99 {votersModalOpen && ( 100 <VotersListModal 101 open={votersModalOpen} 102 close={() => setVotersModalOpen(false)} 103 proposal={proposal} 104 voters={proposalVotes} 105 /> 106 )} 107 </Box> 108 ); 109 };