Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
carina-akaia committed Jan 2, 2025
1 parent 03cf5db commit 1f88e2e
Show file tree
Hide file tree
Showing 25 changed files with 380 additions and 156 deletions.
4 changes: 2 additions & 2 deletions src/common/api/indexer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,10 @@ export const useAccountDonationsSent = ({
/**
* https://test-dev.potlock.io/api/schema/swagger-ui/#/v1/v1_pots_retrieve_2
*/
export const usePot = ({ potId }: Partial<ByPotId>) => {
export const usePot = ({ potId, enabled = true }: ByPotId & ConditionalActivation) => {
const queryResult = generatedClient.useV1PotsRetrieve2(potId ?? "noop", {
...INDEXER_CLIENT_CONFIG,
swr: { enabled: Boolean(potId), refreshInterval: 3000 },
swr: { enabled, refreshInterval: 3000 },
});

return { ...queryResult, data: queryResult.data?.data };
Expand Down
24 changes: 13 additions & 11 deletions src/common/api/indexer/internal/client.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1055,17 +1055,19 @@ export interface LockingPosition {
}

export interface MpdaoVoter {
/** @nullable */
balance_in_contract: string | null;
/** @nullable */
locking_positions: LockingPosition[] | null;
readonly staking_token_balance: string;
readonly staking_token_id: string;
/** @nullable */
vote_positions: VotePosition[] | null;
voter_id: string;
/** @nullable */
voting_power: string | null;
voter_data: {
/** @nullable */
balance_in_contract: string | null;
/** @nullable */
locking_positions: LockingPosition[] | null;
readonly staking_token_balance: string;
readonly staking_token_id: string;
/** @nullable */
vote_positions: VotePosition[] | null;
voter_id: string;
/** @nullable */
voting_power: string | null;
};
}

export interface ListUpvote {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,14 @@ export const AccountGroupEditModal = create(
{accountIds.map((accountId) => (
<AccountListItem
key={accountId}
primaryAction={
primarySlot={
<Checkbox
checked={selectedAccounts.includes(accountId)}
onCheckedChange={handleAccountSelect(accountId)}
className="px-0.75"
/>
}
secondaryAction={
secondarySlot={
<Button
onClick={handleAccountRemove(accountId)}
variant="standard-plain"
Expand Down
12 changes: 6 additions & 6 deletions src/entities/_shared/account/components/AccountListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export type AccountListItemProps = ByAccountId & {
hideStatusOnDesktop?: boolean;
hideStatusOnMobile?: boolean;
disableHandleSummaryPopup?: boolean;
primaryAction?: React.ReactNode;
secondaryAction?: React.ReactNode;
primarySlot?: React.ReactNode;
secondarySlot?: React.ReactNode;
href?: string;
onClick?: (accountId: AccountId) => void;

Expand All @@ -37,8 +37,8 @@ export const AccountListItem = ({
hideStatusOnDesktop = false,
hideStatusOnMobile = false,
disableHandleSummaryPopup = false,
primaryAction,
secondaryAction,
primarySlot,
secondarySlot,
href,
onClick,
classNames,
Expand Down Expand Up @@ -72,7 +72,7 @@ export const AccountListItem = ({
classNames?.root,
)}
>
{primaryAction}
{primarySlot}

<div className="mr-a flex w-full items-center gap-4">
{avatarElement}
Expand Down Expand Up @@ -111,7 +111,7 @@ export const AccountListItem = ({
</div>
</div>

{secondaryAction && <div className="">{secondaryAction}</div>}
{secondarySlot && <div className="">{secondarySlot}</div>}
</div>
);
};
10 changes: 5 additions & 5 deletions src/entities/voting-round/components/CandidateRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type VotingRoundCandidateRowProps = ByElectionId & {

export const VotingRoundCandidateRow: React.FC<VotingRoundCandidateRowProps> = ({
electionId,
data: { account_id: accountId, votes_received: votesCount },
data: { account_id: accountId, votes_received: voteCount },
isVotable = true,
isSelected = false,
onSelect,
Expand Down Expand Up @@ -58,11 +58,11 @@ export const VotingRoundCandidateRow: React.FC<VotingRoundCandidateRowProps> = (
) : (
<div className="color-neutral-500 flex flex-nowrap items-center">
<Dot className="hidden md:block" />
<span className="prose text-sm font-medium leading-tight">{`${votesCount} Votes`}</span>
<span className="prose text-sm font-medium leading-tight">{`${voteCount} Votes`}</span>
</div>
)
}
primaryAction={
primarySlot={
typeof onSelect === "function" ? (
<div
className={cn("pr-3.75 inline-flex h-16 items-center justify-start gap-4 py-4", {
Expand All @@ -77,13 +77,13 @@ export const VotingRoundCandidateRow: React.FC<VotingRoundCandidateRowProps> = (
</div>
) : null
}
secondaryAction={
secondarySlot={
<div className="flex items-center">
<div className="hidden h-16 w-24 items-center justify-end p-4 md:inline-flex">
{isLoading ? (
<Skeleton className="h-5 w-11" />
) : (
<div className="prose text-right text-sm font-medium leading-tight">{votesCount}</div>
<div className="prose text-right text-sm font-medium leading-tight">{voteCount}</div>
)}
</div>

Expand Down
90 changes: 90 additions & 0 deletions src/entities/voting-round/components/ResultRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { useCallback, useMemo } from "react";

import { CheckedState } from "@radix-ui/react-checkbox";
import { Dot } from "lucide-react";

import { ByElectionId } from "@/common/contracts/core/voting";
import { Button, Checkbox, Skeleton } from "@/common/ui/components";
import { cn } from "@/common/ui/utils";
import { AccountListItem } from "@/entities/_shared/account";
import { useSession } from "@/entities/_shared/session";

import { useVotingRoundCandidateEntry } from "../hooks/candidates";
import type { VotingRoundWinner } from "../types";

export type VotingRoundResultRowProps = {
data: VotingRoundWinner;
rank: number;
isSelected?: boolean;
onSelect?: (accountId: string, isSelected: boolean) => void;
};

export const VotingRoundResultRow: React.FC<VotingRoundResultRowProps> = ({
data: { accountId, voteCount, accumulatedWeight, estimatedPayoutAmount },
rank,
isSelected = false,
onSelect,
}) => {
const user = useSession();

const onCheckTriggered = useCallback(
(checked: CheckedState) => onSelect?.(accountId, Boolean(checked)),
[accountId, onSelect],
);

return (
<AccountListItem
highlightOnHover
hideStatusOnDesktop
classNames={{
root: cn("px-4 rounded-lg", {
"bg-neutral-50": isSelected,
}),
}}
statusElement={
<div className="color-neutral-500 flex flex-nowrap items-center">
<Dot className="hidden md:block" />
<span className="prose text-sm font-medium leading-tight">{`${voteCount} Votes`}</span>
</div>
}
primarySlot={
<div className="flex">
<div className="inline-flex h-10 items-center justify-start gap-2 px-4 py-2 pl-0">
<div
className={cn(
"flex h-8 w-8 shrink-0 items-center justify-center",
"rounded-full border border-neutral-200",
)}
>
<span className="text-right text-xs font-medium leading-none">{rank}</span>
</div>
</div>

{typeof onSelect === "function" ? (
<div className={cn("pr-3.75 inline-flex h-16 items-center justify-start gap-4 py-4")}>
<Checkbox checked={isSelected} onCheckedChange={onCheckTriggered} />
</div>
) : null}
</div>
}
secondarySlot={
<div className="hidden items-center md:flex">
<div className="inline-flex h-16 w-24 items-center justify-end p-4">
<div className="prose text-right text-sm font-medium leading-tight">{voteCount}</div>
</div>

<div className="w-30.5 inline-flex h-16 items-center justify-end px-4 py-2">
<span className="font-600 text-right uppercase leading-none">{accumulatedWeight}</span>
</div>

<div className="w-32.5 inline-flex h-16 items-center justify-end overflow-hidden px-4 py-2 pr-0">
<span className="font-600 w-full overflow-x-hidden text-center uppercase leading-none">
{estimatedPayoutAmount}
</span>
</div>
</div>
}
{...{ accountId }}
/>
);
};
37 changes: 20 additions & 17 deletions src/entities/voting-round/components/ResultsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useWindowSize } from "@uidotdev/usehooks";
import { ScrollArea } from "@/common/ui/components";

import type { VotingRoundWinner } from "../types";
import { VotingRoundResultRow } from "./ResultRow";

export type VotingRoundResultsTableProps = {
data: VotingRoundWinner[];
Expand All @@ -14,35 +15,37 @@ export const VotingRoundResultsTable: React.FC<VotingRoundResultsTableProps> = (

return (
<section className="flex w-full flex-col">
<div className="flex justify-between bg-neutral-50 text-xs text-neutral-500">
<div className="mr-a inline-flex h-10 items-center justify-start gap-2 px-4 py-2">
<span className="font-600 shrink grow basis-0 uppercase leading-none">{"Rank"}</span>
</div>
<div className="flex justify-between text-nowrap bg-neutral-50 text-xs text-neutral-500">
<div className="mr-a flex">
<div className="inline-flex h-10 items-center justify-start gap-2 px-4 py-2">
<span className="font-600 uppercase leading-none">{"Rank"}</span>
</div>

<div className="mr-a inline-flex h-10 items-center justify-start gap-2 px-4 py-2">
<span className="font-600 shrink grow basis-0 uppercase leading-none">{"Projects"}</span>
<div className="inline-flex h-10 items-center justify-start gap-2 px-4 py-2">
<span className="font-600 uppercase leading-none">{"Projects"}</span>
</div>
</div>

<div className="hidden md:flex">
<div className="flex h-10 w-24 items-center px-4 py-2">
<span className="font-600 shrink grow basis-0 text-right uppercase leading-none">
{"Votes"}
</span>
<div className="flex h-10 w-24 items-center justify-end px-4 py-2">
<span className="font-600 text-right uppercase leading-none">{"Votes"}</span>
</div>

<div className="flex h-10 w-24 items-center px-4 py-2">
<span className="font-600 shrink grow basis-0 text-center uppercase leading-none">
{"Pool Allocation"}
</span>
<div className="w-30.5 flex h-10 items-center justify-end px-4 py-2">
<span className="font-600 text-right uppercase leading-none">{"Total Weight"}</span>
</div>

<span className="w-36.5 flex h-10 h-full items-center px-4 py-2">
<span className="font-600 text-center uppercase leading-none">{"Pool Allocation"}</span>
</span>
</div>
</div>

<ScrollArea style={{ height: (windowHeight ?? 820) - 320 }}>
<div className="flex flex-col gap-2 pb-8 pt-2">
{/* {data.map((winner) => (
<VotingRoundResultsTableItem key={winner.accountId} data={winner} />
))} */}
{data.map((winner, index) => (
<VotingRoundResultRow key={winner.accountId} data={winner} rank={index + 1} />
))}
</div>
</ScrollArea>
</section>
Expand Down
24 changes: 16 additions & 8 deletions src/entities/voting-round/hooks/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,34 @@ import { indexer } from "@/common/api/indexer";
import { NATIVE_TOKEN_DECIMALS } from "@/common/constants";
import { votingContractHooks } from "@/common/contracts/core/voting";
import { stringifiedU128ToBigNum } from "@/common/lib";
import type { ConditionalActivation } from "@/common/types";
import { usePotFeatureFlags } from "@/entities/pot";

import { useRoundResultsStore } from "../model/round-results";
import type { VotingRoundKey } from "../types";
import { useVotingRound } from "./rounds";

// TODO: Apply performance optimizations
export const useVotingRoundResults = ({ potId }: VotingRoundKey) => {
const { data: pot } = indexer.usePot({ potId });
export const useVotingRoundResults = ({
potId,
enabled = true,
}: VotingRoundKey & ConditionalActivation) => {
const { data: pot } = indexer.usePot({ enabled, potId });
const { hasProportionalFundingMechanism } = usePotFeatureFlags({ potId });
const votingRound = useVotingRound({ enabled: hasProportionalFundingMechanism, potId });

const votingRound = useVotingRound({
enabled: enabled && hasProportionalFundingMechanism,
potId,
});

const { data: votes } = votingContractHooks.useElectionVotes({
enabled: votingRound !== undefined,
enabled: enabled && votingRound !== undefined,
electionId: votingRound?.electionId ?? 0,
});

const store = useRoundResultsStore();

if (pot && votingRound && votes) {
if (enabled && pot && votingRound && votes) {
const cachedResults = store.resultsCache[votingRound.electionId];

// Update results if votes have changed
Expand All @@ -48,7 +56,7 @@ export const useVotingRoundResults = ({ potId }: VotingRoundKey) => {
const handleCsvDownload = useCallback(() => {
if (results?.winners) {
const headers = [
"Project ID",
"Project Account ID",
"Vote Count",
"Accumulated Weight",
"Estimated NEAR Payout Amount",
Expand Down Expand Up @@ -78,12 +86,12 @@ export const useVotingRoundResults = ({ potId }: VotingRoundKey) => {
if (results) {
return {
votingRoundResults: results,
handleVotingRoundResultsCsvDownload: handleCsvDownload,
handleVotingRoundWinnersCsvDownload: handleCsvDownload,
};
} else {
return {
votingRoundResults: undefined,
handleVotingRoundResultsCsvDownload: undefined,
handleVotingRoundWinnersCsvDownload: undefined,
};
}
};
2 changes: 1 addition & 1 deletion src/entities/voting-round/hooks/vote-weight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const useVotingRoundVoterVoteWeight = ({ accountId, potId }: VotingRoundV
? accumulatedWeight.add(
Big(rule.amplificationPercent)
.div(100)
.mul(basicWeight ?? (accumulatedWeight.gt(0) ? accumulatedWeight : 1)),
.mul(basicWeight ?? 1),
)
: accumulatedWeight,

Expand Down
Loading

0 comments on commit 1f88e2e

Please sign in to comment.