Skip to content

Commit

Permalink
Merge pull request #211 from DAOmasons/votingTouchUp
Browse files Browse the repository at this point in the history
Voting touch up
  • Loading branch information
jordanlesich authored Jun 10, 2024
2 parents 46bde8c + 971889a commit 2e78361
Show file tree
Hide file tree
Showing 14 changed files with 787 additions and 409 deletions.
126 changes: 121 additions & 5 deletions src/components/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import { Link } from 'react-router-dom';

import classes from '../pages/PageStyles.module.css';
import { useGameManager } from '../hooks/useGameMangers';
import { GameStatus } from '../types/common';
import { ContestStatus, GameStatus, VotingStage } from '../types/common';
import { ReactNode } from 'react';
import { useMobile } from '../hooks/useBreakpoint';
import { useVoting } from '../hooks/useVoting';
import { secondsToLongDate } from '../utils/time';

export const Banner = () => {
const { gm, isLoadingGm, gmError } = useGameManager();
const { contestStatus, contest, votingStage } = useVoting();
const isMobile = useMobile();

if (isLoadingGm) return <BannerBG />;
Expand Down Expand Up @@ -119,12 +122,67 @@ export const Banner = () => {
);
}

if (gm.currentRound.gameStatus === GameStatus.Completed) {
const roundOver = gm.currentRound.gameStatus === GameStatus.Completed;

if (
(roundOver && contestStatus === ContestStatus.Populating) ||
(roundOver && contestStatus === ContestStatus.None)
) {
return (
<BannerBG>
<Innards
statusText="Round Complete."
ctaText="Stay tuned for election details."
ctaText="Stay tuned for voting details."
ctaButton={
<Button component={Link} to="/vote" size={isMobile ? 'xs' : 'sm'}>
Preview Portfolios
</Button>
}
infoBtn={
<Button
component="a"
href="https://rules.grantships.fun/how-to-play/as-a-dao-mem.html"
variant="transparent"
rel="noopener noreferrer"
target="_blank"
>
Vote details
</Button>
}
/>
</BannerBG>
);
}

const voteIsIdle =
roundOver &&
contestStatus === ContestStatus.None &&
votingStage === VotingStage.None;

const voteIsSetup =
roundOver &&
contestStatus === ContestStatus.Voting &&
votingStage === VotingStage.Initiated;

const voteIsActive =
roundOver &&
contestStatus === ContestStatus.Voting &&
votingStage === VotingStage.Active;

const voteIsClosed =
votingStage >= VotingStage.Closed ||
contestStatus >= ContestStatus.Finalized;

if (voteIsIdle || voteIsSetup) {
return (
<BannerBG>
<Innards
statusText=""
ctaText={
voteIsSetup && contest?.startTime
? `Vote Starts on ${secondsToLongDate(contest.startTime)}`
: 'Vote Starts Soon'
}
ctaButton={
<Button
component={Link}
Expand All @@ -137,12 +195,70 @@ export const Banner = () => {
infoBtn={
<Button
component="a"
href="https://rules.grantships.fun/"
href="https://rules.grantships.fun/how-to-play/as-a-dao-mem.html"
variant="transparent"
rel="noopener noreferrer"
target="_blank"
>
Vote details
</Button>
}
/>
</BannerBG>
);
}

if (voteIsActive) {
return (
<BannerBG>
<Innards
statusText="Grant Ships voting is live! "
ctaText="Cast your vote now."
ctaButton={
<Button component={Link} to="/vote" size={isMobile ? 'xs' : 'sm'}>
Vote Now
</Button>
}
infoBtn={
<Button
component="a"
href="https://rules.grantships.fun/how-to-play/as-a-dao-mem.html"
variant="transparent"
rel="noopener noreferrer"
target="_blank"
>
What am I voting on?
</Button>
}
/>
</BannerBG>
);
}

if (voteIsClosed) {
return (
<BannerBG>
<Innards
statusText="Voting is Closed. "
ctaText="Stay tuned for the next round."
ctaButton={
<Button
component={Link}
to="create-project"
size={isMobile ? 'xs' : 'sm'}
>
See Results
</Button>
}
infoBtn={
<Button
component="a"
href="https://rules.grantships.fun/how-to-play/as-a-dao-mem.html"
variant="transparent"
rel="noopener noreferrer"
target="_blank"
>
What are we electing?
More info.
</Button>
}
/>
Expand Down
13 changes: 1 addition & 12 deletions src/components/dashboard/ship/PortfolioReport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { GAME_TOKEN } from '../../../constants/gameSetup';
import {
IconChevronDown,
IconChevronUp,
IconExclamationCircle,
IconExternalLink,
IconSquare,
IconSquareCheck,
Expand Down Expand Up @@ -76,8 +75,6 @@ export const PortfolioReport = ({
onReportSubmit?: () => void;
reportData?: ReportData | null;
}) => {
const theme = useMantineTheme();

const form = useForm({
initialValues: defaultValues,
validate: zodResolver(portfolioReportSchema),
Expand All @@ -93,15 +90,7 @@ export const PortfolioReport = ({
</Stack>
);

if (error || !grants)
return (
<AppAlert
title="Error"
icon={<IconExclamationCircle />}
description={error?.message || 'Grant Data failed to load'}
bg={theme.colors.pink[8]}
/>
);
if (error || !grants) return null;

if (grants.length === 0)
return (
Expand Down
12 changes: 11 additions & 1 deletion src/components/voting/ConfirmationPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,17 @@ export const ConfirmationPanel = ({
</Box>
);
})}
<Text fz="md" mb="xs">
<Text
fz="md"
mb="xs"
c={
totalPercent < 100
? theme.colors.yellow[6]
: exceeds100percent
? theme.colors.red[7]
: 'inherit'
}
>
<Text component="span" fw={600} fz="inherit">
Total Vote:{' '}
</Text>
Expand Down
38 changes: 38 additions & 0 deletions src/components/voting/PreVoting.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Group, Paper, Text, useMantineTheme } from '@mantine/core';
import { MainSection, PageTitle } from '../../layout/Sections';
import { ShipBadge } from '../RoleBadges';

export const PreVoting = () => {
const theme = useMantineTheme();
return (
<MainSection>
<PageTitle title="Vote" />
<Paper p="lg" bg={theme.colors.dark[6]} py={48} px={25} mt={80}>
<Group mb="xl">
<ShipBadge size={32} />
<Text fz={32} fw={600}>
Voting is not open yet!
</Text>
</Group>
<Text fw={600} mb={'sm'}>
Stay Tuned!
</Text>
<Text mb="xl" c={theme.colors.dark[2]} fz="md">
The voting round for Grant Ships is opened after the allocation round.
</Text>
<Text fw={600} mb={'sm'}>
How it works
</Text>
<Text fz="md" c={theme.colors.dark[2]} mb="sm">
Ships receive funds from a DAO to distribute as grants for projects in
one round. At the round's end, DAO members allocate votes to ships
based on their performance.
</Text>
<Text fz="md" c={theme.colors.dark[2]}>
Ships then receive funds in the next round based on the proportion of
votes they received.
</Text>
</Paper>
</MainSection>
);
};
48 changes: 11 additions & 37 deletions src/components/voting/ShipVotingPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import { UseFormReturnType } from '@mantine/form';
import { ShipsCardUI } from '../../types/ui';
import { VotingFormValues } from '../../pages/Vote';
import { useQuery } from '@tanstack/react-query';
import { getShipGrants } from '../../queries/getShipGrants';
import { useUserData } from '../../hooks/useUserState';
import { useVoting } from '../../hooks/useVoting';
import { useMemo } from 'react';
import { getRecentPortfolioReport } from '../../queries/getRecordsByTag';
import { ADDR } from '../../constants/addresses';
import { PostedRecord } from '../../queries/getRecordsByTag';
import { formatEther } from 'viem';
import { Avatar, Box, Flex, Paper, Text, useMantineTheme } from '@mantine/core';
import { PortfolioReport } from '../dashboard/ship/PortfolioReport';
import { ContestStatus, ReportStatus, VotingStage } from '../../types/common';
import { Tag } from '../../constants/tags';
import { VotingFooter } from './VotingFooter';
import { FacilitatorFooter } from './FacilitatorFooter';
import { DashGrant } from '../../resolvers/grantResolvers';

export const ShipVotingPanel = ({
ship,
form,
index,
nextStep,
prevStep,
grants,
recentRecord,
}: {
grants: DashGrant[] | null;
recentRecord?: PostedRecord | null;
ship: ShipsCardUI;
form: UseFormReturnType<
VotingFormValues,
Expand All @@ -32,47 +33,20 @@ export const ShipVotingPanel = ({
nextStep: () => void;
prevStep: () => void;
}) => {
const {
data: grants,
error,
isLoading: isLoadingGrants,
} = useQuery({
queryKey: [`portfolio-${ship.id}`],
queryFn: () => getShipGrants(ship.id as string),
enabled: !!ship.id,
});

const {
contest,
contestStatus,
isLoadingVoting,
refetchGsVotes,
votingStage,
} = useVoting();
const { contest, contestStatus, refetchGsVotes, votingStage } = useVoting();
const theme = useMantineTheme();
const { userData, userLoading } = useUserData();
const { userData } = useUserData();

const shipChoiceId = useMemo(() => {
return contest?.choices.find((choice) => choice.shipId === ship.id)?.id;
}, [contest?.choices, ship]);

const { data: recentRecord, isLoading: isLoadingRecord } = useQuery({
queryKey: [`ship-portfolio-${ship.id}`],
queryFn: () =>
getRecentPortfolioReport(
`${Tag.ShipSubmitReport}-${ADDR.VOTE_CONTEST}-${ship.id}`
),
enabled: !!ship.id,
});

const totalAmount = formatEther(
BigInt(ship.amtAllocated) +
BigInt(ship.amtAvailable) +
BigInt(ship.amtDistributed)
);

const isLoading =
isLoadingRecord || isLoadingVoting || isLoadingGrants || userLoading;
return (
<Box>
<Text fz="xl" fw={600} mb="md">
Expand Down Expand Up @@ -103,14 +77,14 @@ export const ShipVotingPanel = ({

<PortfolioReport
grants={grants}
isLoading={isLoading}
error={error}
error={null}
isLoading={false}
reportStatus={ReportStatus.Review}
reportData={recentRecord}
shipId={ship.id}
/>

{contestStatus === ContestStatus.Populating && !isLoading && (
{contestStatus === ContestStatus.Populating && (
<FacilitatorFooter
isFacilitator={userData?.isFacilitator}
recentRecord={recentRecord}
Expand Down
Loading

0 comments on commit 2e78361

Please sign in to comment.