Skip to content

Commit

Permalink
feat: votepower (#452)
Browse files Browse the repository at this point in the history
* feat: votepower

* fix: bugs

* style

* button state

* test: fixing tests

* fix: my vote row

* ref:prepare for eval

* wip

* test: fix test

* feat: fix voting period countdown

* fix icons

* fix: typecheck

* fix: typecheck

* wip

* wip

* done
  • Loading branch information
MrX-SNX authored Sep 12, 2024
1 parent 2284c25 commit 29ba630
Show file tree
Hide file tree
Showing 19 changed files with 589 additions and 246 deletions.
3 changes: 2 additions & 1 deletion governance/cypress/cypress/e2e/Councils - Nomination.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ it('Councils - Administration', () => {
cy.get('[data-cy="period-countdown"]').should('exist');
cy.get('[data-cy="period-countdown"]').contains('Voting starts');
cy.get('[data-cy="name-table-header"]').click();
cy.get('[data-cy="sort-arrow-down"]').should('exist');
cy.get('[data-cy="sort-arrow-down"]').click();
cy.get('[data-cy="sort-arrow-up"]').should('exist');
cy.get('[data-cy="sort-arrow-up"]').click();
cy.get('[data-cy="sort-arrow-down"]').should('exist');
cy.get('[data-cy="own-user-list-item"]').should(
'have.css',
'border-top',
Expand Down
4 changes: 3 additions & 1 deletion governance/cypress/cypress/e2e/Councils - Voting.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ it('Councils - Administration', () => {
cy.get('[data-cy="period-countdown"]').should('exist');
cy.get('[data-cy="period-countdown"]').contains('Voting ends');
cy.get('[data-cy="name-table-header"]').click();
cy.get('[data-cy="sort-arrow-down"]').should('exist');
cy.get('[data-cy="sort-arrow-down"]').click();
cy.get('[data-cy="sort-arrow-up"]').should('exist');
cy.get('[data-cy="sort-arrow-up"]').click();
cy.get('[data-cy="sort-arrow-down"]').should('exist');
cy.get('[data-cy="own-user-list-item"]').click();
cy.get('[data-cy="nominate-self-button-user-profile-details-voting-period"]').click();
cy.get('[data-cy="nominate-self-button-in-user-profile"]').click();
cy.get('[data-cy="council-nomination-select-spartan"]').click();
cy.get('[data-cy="nominate-self-cast-nomination-button"]').click();
cy.get('[data-cy="nominate-self-done-button"]').click();
Expand Down
11 changes: 5 additions & 6 deletions governance/ui/src/components/CouncilNominees/CouncilNominees.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { sortUsers } from '../../utils/sort-users';

export default function CouncilNominees({ activeCouncil }: { activeCouncil: CouncilSlugs }) {
const [search, setSearch] = useState('');
const [sortConfig, setSortConfig] = useState<[boolean, string]>([false, 'name']);
const [sortConfig, setSortConfig] = useState<[boolean, string]>([true, 'votingPower']);

const { network } = useNetwork();
const { data: epochId } = useGetEpochIndex(activeCouncil);
Expand Down Expand Up @@ -149,7 +149,7 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
<Table style={{ borderCollapse: 'separate', borderSpacing: '0 1px' }}>
<Thead>
<Tr>
{councilPeriod === '2' && (
{(councilPeriod === '2' || councilPeriod === '3') && (
<Th
cursor="pointer"
w="50px"
Expand All @@ -175,9 +175,8 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
onClick={() => setSortConfig([!sortConfig[0], 'name'])}
>
Name {sortConfig[1] === 'name' && <SortArrows up={sortConfig[0]} />}
{sortConfig[1] === 'start' && <SortArrows up={sortConfig[0]} />}
</Th>
{councilPeriod === '2' && (
{(councilPeriod === '2' || councilPeriod === '3') && (
<Th
cursor="pointer"
w="150px"
Expand All @@ -192,7 +191,7 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
Votes {sortConfig[1] === 'votes' && <SortArrows up={sortConfig[0]} />}
</Th>
)}
{councilPeriod === '2' && (
{(councilPeriod === '2' || councilPeriod === '3') && (
<Th
cursor="pointer"
userSelect="none"
Expand All @@ -206,7 +205,7 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
{sortConfig[1] === 'votingPower' && <SortArrows up={sortConfig[0]} />}
</Th>
)}
{councilPeriod === '2' && (
{(councilPeriod === '2' || councilPeriod === '3') && (
<Th cursor="pointer" userSelect="none" textTransform="capitalize" pl="6"></Th>
)}
</Tr>
Expand Down
28 changes: 15 additions & 13 deletions governance/ui/src/components/CouncilTabs/CouncilTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export default function CouncilTabs({ activeCouncil }: { activeCouncil: CouncilS
address={userInformation[index].userInformation?.address}
size={9}
newVoteCast={newVoteCast}
isCouncilTabs
isCouncilTabs={false}
/>
{userInformation[index]?.userInformation?.address
? newVoteCast?.toLowerCase() !==
Expand All @@ -186,7 +186,7 @@ export default function CouncilTabs({ activeCouncil }: { activeCouncil: CouncilS
address={newVoteCast}
size={9}
newVoteCast={newVoteCast}
isCouncilTabs
isCouncilTabs={true}
/>
</>
)
Expand All @@ -200,23 +200,25 @@ export default function CouncilTabs({ activeCouncil }: { activeCouncil: CouncilS
address={userInformation[index].userInformation?.address}
size={9}
newVoteCast={newVoteCast}
isCouncilTabs
isCouncilTabs={false}
/>
)}

{newVoteCast && userInformation[index].userInformation?.address && (
<ArrowForwardIcon mx="2" />
)}
<Box
data-cy="council-tab-vote-circle"
borderRadius="50%"
w="9"
h="9"
borderWidth="1px"
bg="navy.700"
borderStyle="dashed"
borderColor="gray.500"
/>
{(newVoteCast === 'remove' || !newVoteCast) && (
<Box
data-cy="council-tab-vote-circle"
borderRadius="50%"
w="9"
h="9"
borderWidth="1px"
bg="navy.700"
borderStyle="dashed"
borderColor="gray.500"
/>
)}
</>
)
)}
Expand Down
45 changes: 45 additions & 0 deletions governance/ui/src/components/Icons/Ethereum.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Icon } from '@chakra-ui/react';

export const EthereumIcon = (
<Icon
width="40px"
height="41px"
viewBox="0 0 80 81"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_8101_103827)">
<path
d="M40 80.4902C62.0914 80.4902 80 62.5816 80 40.4902C80 18.3988 62.0914 0.490234 40 0.490234C17.9086 0.490234 0 18.3988 0 40.4902C0 62.5816 17.9086 80.4902 40 80.4902Z"
fill="#627EEA"
/>
<path
d="M41.2451 10.4902V32.6652L59.9876 41.0402L41.2451 10.4902Z"
fill="white"
fillOpacity="0.602"
/>
<path d="M41.245 10.4902L22.5 41.0402L41.245 32.6652V10.4902Z" fill="white" />
<path
d="M41.2451 55.4093V70.4768L60.0001 44.5293L41.2451 55.4093Z"
fill="white"
fillOpacity="0.602"
/>
<path d="M41.245 70.4768V55.4068L22.5 44.5293L41.245 70.4768Z" fill="white" />
<path
d="M41.2451 51.9224L59.9876 41.0399L41.2451 32.6699V51.9224Z"
fill="white"
fillOpacity="0.2"
/>
<path
d="M22.5 41.0399L41.245 51.9224V32.6699L22.5 41.0399Z"
fill="white"
fillOpacity="0.602"
/>
</g>
<defs>
<clipPath id="clip0_8101_103827">
<rect width="80" height="80" fill="white" transform="translate(0 0.490234)" />
</clipPath>
</defs>
</Icon>
);
24 changes: 24 additions & 0 deletions governance/ui/src/components/Icons/Optimism.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Icon } from '@chakra-ui/react';

export const OPIcon = (
<Icon
width="40px"
height="41px"
viewBox="0 0 80 81"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M40 80.4902C62.0914 80.4902 80 62.5816 80 40.4902C80 18.3988 62.0914 0.490234 40 0.490234C17.9086 0.490234 0 18.3988 0 40.4902C0 62.5816 17.9086 80.4902 40 80.4902Z"
fill="#FF0420"
/>
<path
d="M29.0108 51.691C26.5982 51.691 24.6216 51.1102 23.0806 49.9488C21.5601 48.7665 20.7998 47.0865 20.7998 44.9088C20.7998 44.4525 20.8505 43.8925 20.9518 43.2288C21.2155 41.7355 21.5905 39.9414 22.0771 37.8465C23.4556 32.1429 27.0139 29.291 32.7515 29.291C34.3126 29.291 35.7115 29.5606 36.9481 30.1C38.1849 30.6184 39.158 31.4065 39.8676 32.4643C40.5772 33.5014 40.9321 34.7459 40.9321 36.1977C40.9321 36.6333 40.8814 37.1829 40.78 37.8465C40.476 39.6925 40.111 41.4865 39.6852 43.2288C38.9756 46.0702 37.7491 48.1961 36.0054 49.6065C34.2619 50.9961 31.9304 51.691 29.0108 51.691ZM29.4366 47.211C30.572 47.211 31.535 46.8688 32.3257 46.1843C33.1366 45.5 33.7145 44.4525 34.0592 43.0421C34.5254 41.0925 34.8803 39.3918 35.1235 37.94C35.2046 37.5043 35.2451 37.0584 35.2451 36.6021C35.2451 34.7147 34.2822 33.771 32.3561 33.771C31.2208 33.771 30.2476 34.1133 29.4366 34.7977C28.6459 35.4821 28.0782 36.5296 27.7336 37.94C27.3686 39.3296 27.0036 41.0302 26.6388 43.0421C26.5577 43.4569 26.5171 43.8925 26.5171 44.3488C26.5171 46.2569 27.4902 47.211 29.4366 47.211Z"
fill="white"
/>
<path
d="M42.3288 51.3795C42.1057 51.3795 41.9334 51.3068 41.8117 51.1616C41.7104 50.9956 41.68 50.8091 41.7205 50.6016L45.9173 30.3795C45.9577 30.1513 46.0693 29.9646 46.2518 29.8195C46.4342 29.6742 46.6269 29.6016 46.8296 29.6016H54.919C57.1694 29.6016 58.9737 30.0787 60.3321 31.0328C61.7109 31.9868 62.4001 33.366 62.4001 35.1705C62.4001 35.6891 62.3393 36.2283 62.2177 36.7883C61.7109 39.1736 60.687 40.9364 59.1461 42.0772C57.6256 43.2179 55.5373 43.7883 52.8814 43.7883H48.7758L47.3769 50.6016C47.3365 50.8297 47.2249 51.0164 47.0424 51.1616C46.86 51.3068 46.6673 51.3795 46.4646 51.3795H42.3288ZM53.0942 39.495C53.9457 39.495 54.6857 39.2564 55.3144 38.7795C55.963 38.3024 56.3888 37.6179 56.5917 36.726C56.6525 36.3736 56.6829 36.0624 56.6829 35.7928C56.6829 35.1913 56.5105 34.735 56.1659 34.4238C55.8211 34.092 55.2333 33.926 54.4019 33.926H50.7526L49.5969 39.495H53.0942Z"
fill="white"
/>
</Icon>
);
2 changes: 2 additions & 0 deletions governance/ui/src/components/Icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export * from './SNXHeaderIcon';
export * from './SNXHeaderIconSmall';
export * from './EditIcon';
export * from './ShareIcon';
export * from './Optimism';
export * from './Ethereum';
131 changes: 79 additions & 52 deletions governance/ui/src/components/MyVoteRow/MyVoteRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useVoteContext } from '../../context/VoteContext';
import { useGetEpochIndex, useGetUserBallot, useNetwork, useWallet } from '../../queries';
import { getVoteSelectionState } from '../../utils/localstorage';
import { Badge } from '../Badge';
import { utils } from 'ethers';

export default function MyVoteRow({
councilSlug,
Expand All @@ -24,15 +25,62 @@ export default function MyVoteRow({
const { dispatch, state } = useVoteContext();
const { network } = useNetwork();

const networkForState = getVoteSelectionState(
const votedCandidate = ballot?.votedCandidates[0] || '';
const voteSelection = getVoteSelectionState(
state,
activeWallet?.address,
epochId?.toString(),
network?.id.toString(),
councilSlug
);
const voteAddressState = typeof voteSelection === 'string' ? voteSelection : '';

const hasVoted =
utils.isAddress(votedCandidate) &&
utils.isAddress(voteAddressState) &&
votedCandidate.toLowerCase() === voteAddressState.toLowerCase();
const isDisabled = period !== '2';

const handleAddVote = (e: React.MouseEvent) => {
e.stopPropagation();
navigate(`/councils/${councilSlug}`);
};

const handleRemoveVote = (e: React.MouseEvent) => {
e.stopPropagation();
if (
utils.isAddress(votedCandidate) &&
utils.isAddress(voteAddressState) &&
votedCandidate.toLowerCase() !== voteAddressState.toLowerCase()
) {
dispatch({
type: councilSlug.toUpperCase(),
payload: {
action: votedCandidate,
network: network?.id.toString(),
epochId: epochId?.toString(),
wallet: activeWallet?.address,
},
});
} else {
dispatch({
type: councilSlug.toUpperCase(),
payload: {
action: votedCandidate
? voteAddressState === 'remove'
? votedCandidate
: 'remove'
: voteAddressState === 'remove'
? 'remove'
: undefined,
network: network?.id.toString(),
epochId: epochId?.toString(),
wallet: activeWallet?.address,
},
});
}
};

const voteAddressState = typeof networkForState === 'string' ? networkForState : '';
return (
<Flex
key={`vote-${councilSlug}-cart`}
Expand All @@ -43,41 +91,46 @@ export default function MyVoteRow({
borderTop="1px solid"
borderBottom={isLast ? '1px solid' : ''}
borderColor="gray.900"
opacity={period !== '2' ? '0.2' : '1'}
opacity={isDisabled ? '0.2' : '1'}
>
<Flex ml="4" alignItems="center" mr="auto">
<CouncilUser
councilSlug={councilSlug}
address={ballot?.votedCandidates[0] ? ballot?.votedCandidates[0] : voteAddressState}
hideName={!!(ballot?.votedCandidates[0] && voteAddressState)}
/>
{ballot?.votedCandidates[0] &&
voteAddressState &&
ballot.votedCandidates[0].toLowerCase() !== voteAddressState.toLowerCase() && (
<>
<ArrowForwardIcon mx="2" />
<CouncilUser councilSlug={councilSlug} address={voteAddressState} hideName />
</>
)}
<Flex
ml="4"
alignItems="center"
mr="auto"
overflowX="scroll"
sx={{
'::-webkit-scrollbar': {
display: 'none',
},
'-ms-overflow-style': 'none',
'scrollbar-width': 'none',
}}
>
<CouncilUser councilSlug={councilSlug} address={votedCandidate || voteAddressState} />
{!hasVoted && votedCandidate && voteAddressState && (
<>
<ArrowForwardIcon mx="2" />
<CouncilUser councilSlug={councilSlug} address={voteAddressState} />
</>
)}
</Flex>
{ballot?.votedCandidates.includes(voteAddressState) ? (

{hasVoted ? (
<Badge mr="2">Your Vote</Badge>
) : voteAddressState ? (
<Badge color="gray" mr="2" data-cy="selected-badge-my-row">
Selected
</Badge>
) : null}
{!networkForState && !ballot?.votedCandidates[0] ? (

{!voteAddressState && !votedCandidate ? (
<IconButton
aria-label="action-button"
icon={<AddIcon />}
variant="outlined"
mr="4"
isDisabled={period !== '2'}
onClick={(e) => {
e.stopPropagation();
navigate(`/councils/${councilSlug}`);
}}
isDisabled={isDisabled}
onClick={handleAddVote}
/>
) : (
<IconButton
Expand All @@ -87,34 +140,8 @@ export default function MyVoteRow({
data-cy={`remove-vote-button-${councilSlug}`}
variant="outline"
mr="4"
isDisabled={period !== '2'}
onClick={(e) => {
e.stopPropagation();

if (network?.id) {
if (!!ballot?.votedCandidates[0]) {
dispatch({
type: councilSlug.toUpperCase(),
payload: {
action: 'remove',
network: network.id.toString(),
epochId: epochId?.toString(),
wallet: activeWallet?.address,
},
});
} else {
dispatch({
type: councilSlug.toUpperCase(),
payload: {
action: networkForState === 'remove' ? 'remove' : undefined,
network: network.id.toString(),
epochId: epochId?.toString(),
wallet: activeWallet?.address,
},
});
}
}
}}
isDisabled={isDisabled}
onClick={handleRemoveVote}
/>
)}
</Flex>
Expand Down
Loading

0 comments on commit 29ba630

Please sign in to comment.