Skip to content

Commit

Permalink
Tweaks for voting (#441)
Browse files Browse the repository at this point in the history
* wip

* feat: implemeted voting and ranking

* ref: sort func

* ref: clean up

* ref: more clean up

* fix: epoch query
  • Loading branch information
MrX-SNX authored Sep 6, 2024
1 parent 135b7f0 commit cf13fa3
Show file tree
Hide file tree
Showing 12 changed files with 402 additions and 179 deletions.
1 change: 1 addition & 0 deletions governance/cypress/cypress/tasks/changePeriod.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export async function changePeriod({ council, period }) {
const electionId = await proxy.spartan.connect(signer).getEpochIndex();

if (period === 'admin') {
console.log(block.timestamp);
await proxy[council]
.connect(signer)
.Epoch_setEpochDates(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Flex, Heading, Icon, Text } from '@chakra-ui/react';
import { Flex, Heading, Icon, Text } from '@chakra-ui/react';
import councils, { CouncilSlugs } from '../../utils/councils';
import { CouncilImage } from '../CouncilImage';
import { Link } from 'react-router-dom';
Expand Down Expand Up @@ -56,8 +56,16 @@ export default function CouncilInformation({ activeCouncil }: { activeCouncil: C
>
Stipends: {council?.stipends}/month
</Heading>
<Link to={council?.docLink || ''} target="_blank" rel="noopener noreferrer">
<Button variant="outline" colorScheme="gray" size="xs">
<Heading
fontSize="xs"
lineHeight="1rem"
border="1px solid"
borderColor="gray.900"
rounded="base"
px="2"
py="1"
>
<Link to={council?.docLink || ''} target="_blank" rel="noopener noreferrer">
Learn more{' '}
<Icon width="12px" height="12px" viewBox="0 0 12 12" fill="none">
<g clipPath="url(#clip0_7624_75578)">
Expand All @@ -72,8 +80,8 @@ export default function CouncilInformation({ activeCouncil }: { activeCouncil: C
</clipPath>
</defs>
</Icon>
</Button>
</Link>
</Link>
</Heading>
</Flex>
</Flex>
</Flex>
Expand Down
32 changes: 3 additions & 29 deletions governance/ui/src/components/CouncilMembers/CouncilMembers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ArrowUpDownIcon } from '@chakra-ui/icons';
import SortArrows from '../SortArrows/SortArrows';
import { useGetCouncilMembers, useGetUserDetailsQuery } from '../../queries';
import TableLoading from '../TableLoading/TableLoading';
import { sortUsers } from '../../utils/sort-users';

export default function CouncilMembers({ activeCouncil }: { activeCouncil: CouncilSlugs }) {
const [sortConfig, setSortConfig] = useState<[boolean, string]>([false, 'start']);
Expand All @@ -34,29 +35,8 @@ export default function CouncilMembers({ activeCouncil }: { activeCouncil: Counc
const nextEpoch = calculateNextEpoch(councilSchedule);

const sortedNominees = useMemo(() => {
// TODO @dev
// Sort user by voting power and add a place key to the object
if (!!councilMemberDetails?.length) {
if (sortConfig[1] === 'ranking') {
return councilMemberDetails.reverse();
}
if (sortConfig[1] === 'name') {
return councilMemberDetails.sort((a, b) => {
if (a.username && b.username) {
return sortConfig[0]
? a.username.localeCompare(b.username)
: a.username.localeCompare(b.username) * -1;
} else {
return sortConfig[0]
? a?.address.localeCompare(b.address)
: a?.address.localeCompare(b.address) * -1;
}
});
}
return councilMemberDetails;
}
return [];
}, [sortConfig, councilMemberDetails]);
return sortUsers(activeCouncil, '', sortConfig, councilMemberDetails);
}, [sortConfig, councilMemberDetails, activeCouncil]);

return (
<Flex
Expand Down Expand Up @@ -128,9 +108,6 @@ export default function CouncilMembers({ activeCouncil }: { activeCouncil: Counc
px="6"
onClick={() => {
setSortConfig([!sortConfig[0], 'votes']);
// sortedNominees = sortedNominees.sort((a, b) => {
// TODO implement sorting for most votes when subgraph is ready
// });
}}
>
Votes {sortConfig[1] === 'votes' && <SortArrows up={sortConfig[0]} />}
Expand All @@ -146,9 +123,6 @@ export default function CouncilMembers({ activeCouncil }: { activeCouncil: Counc
px="6"
onClick={() => {
setSortConfig([!sortConfig[0], 'votingPower']);
// sortedNominees = sortedNominees.sort((a, b) => {
// TODO implement sorting for most votes when subgraph is ready
// });
}}
>
Voting Power{' '}
Expand Down
76 changes: 18 additions & 58 deletions governance/ui/src/components/CouncilNominees/CouncilNominees.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import UserTableView from '../UserTableView/UserTableView';
import { useGetNomineesDetails } from '../../queries/useGetNomineesDetails';
import { useGetCurrentPeriod } from '../../queries/useGetCurrentPeriod';
import { useMemo, useState } from 'react';
import { utils } from 'ethers';
import SortArrows from '../SortArrows/SortArrows';
import { useNetwork, useWallet } from '../../queries/useWallet';
import { CouncilImage } from '../CouncilImage';
Expand All @@ -32,6 +31,7 @@ import { CloseIcon } from '@chakra-ui/icons';
import { useVoteContext } from '../../context/VoteContext';
import { useGetEpochIndex, useGetHistoricalVotes } from '../../queries';
import { getVoteSelectionState } from '../../utils/localstorage';
import { sortUsers } from '../../utils/sort-users';

export default function CouncilNominees({ activeCouncil }: { activeCouncil: CouncilSlugs }) {
const [search, setSearch] = useState('');
Expand All @@ -55,53 +55,10 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
);
const council = councils.find((council) => council.slug === activeCouncil);
const epoch = calculateNextEpoch(councilSchedule, nextEpochDuration);
const votesForCouncil = votes && votes[activeCouncil];

const sortedNominees = useMemo(() => {
if (councilNomineesDetails?.length && votesForCouncil) {
return councilNomineesDetails
.map((nominee) => {
const vote = votesForCouncil.find(
(vote) =>
epochId === vote.id && vote.voter.toLowerCase() === nominee.address.toLowerCase()
);
if (vote) return (nominee = { ...nominee, vote });
return nominee;
})
.filter((nominee) => {
if (utils.isAddress(search)) {
return nominee.address.toLowerCase().includes(search);
}
if (search) {
if (nominee.username) {
return nominee.username.toLowerCase().includes(search);
} else {
return nominee.address.toLowerCase().includes(search);
}
}
return true;
})
.sort((a, b) => {
if (sortConfig[1] === 'name') {
if (a.username && b.username) {
return sortConfig[0]
? a.username.localeCompare(b.username)
: a.username.localeCompare(b.username) * -1;
}
if (a.username && !b.username) {
return -1;
} else if (b.username && !a.username) {
return 1;
}
return sortConfig[0]
? a.address.localeCompare(b.address)
: a.address.localeCompare(b.address) * -1;
}
return 0;
});
}
return [];
}, [search, councilNomineesDetails, sortConfig, votesForCouncil, epochId]);
return sortUsers(activeCouncil, search, sortConfig, councilNomineesDetails, votes);
}, [search, councilNomineesDetails, sortConfig, activeCouncil, votes]);

return (
<Flex
Expand Down Expand Up @@ -199,10 +156,7 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
px="0"
textAlign="center"
onClick={() => {
setSortConfig([!sortConfig[0], 'ranking']);
// sortedNominees = sortedNominees.sort((a, b) => {
// TODO implement sorting for most votes when subgraph is ready
// });
setSortConfig([true, 'ranking']);
}}
>
{' '}
Expand Down Expand Up @@ -232,9 +186,6 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
pl="6"
onClick={() => {
setSortConfig([!sortConfig[0], 'votes']);
// sortedNominees = sortedNominees.sort((a, b) => {
// TODO implement sorting for most votes when subgraph is ready
// });
}}
>
Votes {sortConfig[1] === 'votes' && <SortArrows up={sortConfig[0]} />}
Expand All @@ -248,9 +199,6 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
pl="6"
onClick={() => {
setSortConfig([!sortConfig[0], 'votingPower']);
// sortedNominees = sortedNominees.sort((a, b) => {
// TODO implement sorting for most votes when subgraph is ready
// });
}}
>
Voting Power{' '}
Expand All @@ -264,16 +212,17 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
</Thead>
<Tbody>
{!!sortedNominees?.length ? (
sortedNominees.map((councilNominee, index) => (
sortedNominees.map((councilNominee) => (
<UserTableView
place={index}
place={councilNominee.place}
user={councilNominee!}
isSelectedForVoting={
councilNominee.address.toLowerCase() ===
currentSelectedUser?.toString().toLowerCase()
}
activeCouncil={activeCouncil}
key={councilNominee.address.concat('council-nominees')}
totalVotingPower={votes && votes[totalVotingPowerForCouncil(activeCouncil)]}
/>
))
) : isLoading ? (
Expand All @@ -289,3 +238,14 @@ export default function CouncilNominees({ activeCouncil }: { activeCouncil: Coun
</Flex>
);
}

function totalVotingPowerForCouncil(council: CouncilSlugs) {
switch (council) {
case 'spartan':
return 'totalVotingPowerSpartan';
case 'ambassador':
return 'totalVotingPowerAmbassador';
case 'treasury':
return 'totalVotingPowerTreasury';
}
}
71 changes: 18 additions & 53 deletions governance/ui/src/components/UserTableView/UserTableView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,52 +9,22 @@ import { prettyString } from '@snx-v3/format';
import { useGetEpochIndex, useGetUserBallot, useNetwork } from '../../queries';
import { getVoteSelectionState } from '../../utils/localstorage';
import { useVoteContext } from '../../context/VoteContext';

function renderCorrectBorder(
column: 'place' | 'name' | 'votes' | 'power' | 'badge',
position: 'left' | 'right' | 'bottom',
period: string | undefined,
isSelected: boolean
) {
if (column === 'place') {
if (position === 'left') {
return isSelected ? '1px solid' : '';
} else if (position === 'bottom') {
return isSelected ? '1px solid' : '';
}
} else if (column === 'name') {
if (position === 'left') {
if (period === '2') {
return '';
}
if (period === '0') {
return '';
}
return isSelected ? '1px solid' : '';
} else if (position === 'bottom') {
return isSelected ? '1px solid' : '';
}
} else if (column === 'votes') {
if (position === 'bottom') return isSelected ? '1px solid' : '';
} else if (column === 'power') {
if (position === 'bottom') return isSelected ? '1px solid' : '';
} else if (column === 'badge') {
if (position === 'bottom') return isSelected ? '1px solid' : '';
if (position === 'right') return isSelected ? '1px solid' : '';
}
}
import { BigNumber } from 'ethers';
import { renderCorrectBorder } from '../../utils/table-border';

export default function UserTableView({
user,
activeCouncil,
place,
isSelectedForVoting,
totalVotingPower,
}: {
isSelectedForVoting?: boolean;
place: number;
place?: number;
user: GetUserDetails;
activeCouncil: CouncilSlugs;
isNomination?: boolean;
totalVotingPower?: BigNumber;
}) {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
Expand All @@ -72,6 +42,9 @@ export default function UserTableView({
activeCouncil
);
const voteAddressState = typeof networkForState === 'string' ? networkForState : '';
const totalVotingPowerPercentage = totalVotingPower
? user.voteResult?.votePower.mul(100).div(totalVotingPower).toNumber().toFixed(2)
: 'N/A';

return (
<Tr
Expand All @@ -89,9 +62,12 @@ export default function UserTableView({
borderLeftRadius={isSelected ? 'base' : ''}
>
<Text color="white" fontSize="sm" fontWeight={700}>
{place < 10 ? (
{place === undefined ? (
'-'
) : place <
(activeCouncil === 'spartan' ? 8 : activeCouncil === 'ambassador' ? 5 : 4) ? (
<Flex gap="1" alignItems="center">
{place + 1}
{place}
<CrownIcon />
</Flex>
) : (
Expand Down Expand Up @@ -139,7 +115,7 @@ export default function UserTableView({
fontSize="sm"
fontWeight={700}
>
0
{user.voteResult?.votesReceived || 0}
</Td>
)}
{councilIsInAdminOrVoting && (
Expand All @@ -151,7 +127,10 @@ export default function UserTableView({
fontSize="sm"
fontWeight={700}
>
0
{totalVotingPowerPercentage ? totalVotingPowerPercentage + '%' : 'N/A'}
<Text color="gray.500" fontSize="x-small">
{totalVotingPowerPercentage ? user.voteResult?.votePower.toString() : '—'}
</Text>
</Td>
)}
{councilPeriod === '2' && (
Expand Down Expand Up @@ -203,20 +182,6 @@ export default function UserTableView({
</Button>
</Td>
)}
{councilPeriod === '0' && (
<Td
textAlign="end"
borderTop="1px solid"
borderBottom={isSelected ? '1px solid' : ''}
borderRight={isSelected ? '1px solid' : ''}
borderRightRadius={isSelected ? 'base' : ''}
borderColor={isSelected ? 'cyan.500' : 'gray.900'}
>
<Badge w="fit-content" fontSize="xl" fontWeight={700}>
0
</Badge>
</Td>
)}
</Tr>
);
}
Expand Down
2 changes: 1 addition & 1 deletion governance/ui/src/queries/useGetEpochIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function useGetEpochIndex(council: CouncilSlugs) {
queryKey: ['epochId', council, network?.id],
queryFn: async () => {
return await getCouncilContract(council)
.connect(motherShipProvider(network?.id || 13001))
.connect(motherShipProvider(network?.id || 2192))
.getEpochIndex();
},
staleTime: 900000,
Expand Down
Loading

0 comments on commit cf13fa3

Please sign in to comment.