From feb6c2e3ec0f155de14a34e98438414626b66e40 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Wed, 19 Jul 2023 12:36:45 +1300 Subject: [PATCH 01/12] proposal resolutionType init --- .../common/components/ProposalFeedCard/ProposalFeedCard.tsx | 5 +++++ src/shared/models/Proposals.tsx | 5 +++++ src/shared/models/governance/proposals/BaseProposal.ts | 3 +++ 3 files changed, 13 insertions(+) diff --git a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx index 0afb02b8a0..9ccadb5ae6 100644 --- a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx +++ b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx @@ -16,6 +16,7 @@ import { CommonFeed, Governance, PredefinedTypes, + ResolutionType, } from "@/shared/models"; import { TextEditorValue } from "@/shared/ui-kit"; import { @@ -314,6 +315,10 @@ const ProposalFeedCard: React.FC = (props) => { onHover(false); }} > + {proposal.resolutionType === ResolutionType.IMMEDIATE && ( + NEED TO UPDATE + )} + data.downloadURL; + +export enum ResolutionType { + WAIT_FOR_EXPIRATION = "WAIT_FOR_EXPIRATION", + IMMEDIATE = "IMMEDIATE", +} diff --git a/src/shared/models/governance/proposals/BaseProposal.ts b/src/shared/models/governance/proposals/BaseProposal.ts index 9edb31f8db..0535fabada 100644 --- a/src/shared/models/governance/proposals/BaseProposal.ts +++ b/src/shared/models/governance/proposals/BaseProposal.ts @@ -6,6 +6,7 @@ import { Moderation, ProposalState, VoteOutcome, + ResolutionType, } from "@/shared/models"; export interface VoteTracker { @@ -73,4 +74,6 @@ export interface BaseProposal extends BaseEntity { type: ProposalsTypes; moderation: Moderation; + + resolutionType: ResolutionType; } From a366d78c9103d1eaa23f551f8f0666583f2902a7 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Thu, 20 Jul 2023 12:00:50 +1300 Subject: [PATCH 02/12] updates --- .../ProposalFeedCard/ProposalFeedCard.tsx | 19 ++++++++--- .../ImmediateProposalInfo.module.scss | 15 +++++++++ .../ImmediateProposalInfo.tsx | 32 +++++++++++++++++++ .../components/ImmediateProposalInfo/index.ts | 1 + .../ProposalFeedButtonContainer.tsx | 17 ++++++---- .../VoteButton/VoteButton.module.scss | 22 ++++++------- .../ProposalFeedCard/components/index.ts | 1 + src/shared/icons/voteFor.icon.tsx | 2 +- src/styles/theme.scss | 3 ++ 9 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.module.scss create mode 100644 src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx create mode 100644 src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/index.ts diff --git a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx index 9ccadb5ae6..cb66791818 100644 --- a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx +++ b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx @@ -39,6 +39,7 @@ import { ProposalFeedVotingInfo, ProposalFeedButtonContainer, UserVoteInfo, + ImmediateProposalInfo, } from "./components"; import { useProposalSpecificData } from "./hooks"; import { @@ -315,18 +316,26 @@ const ProposalFeedCard: React.FC = (props) => { onHover(false); }} > + {proposal.resolutionType === ResolutionType.WAIT_FOR_EXPIRATION && ( + + )} + {proposal.resolutionType === ResolutionType.IMMEDIATE && ( - NEED TO UPDATE + )} - {isVotingAllowed && ( )} { + const votersString = getVotersString( + proposal.global.weights, + governanceCircles, + ); + + return ( +
+
+ {`${proposerUserName} requests to join ${votersString} circle`} +
+
+ {`Approval by ${votersString} (1 from ${proposal.votes.totalMembersWithVotingRight} required)`} +
+
+ ); +}; diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/index.ts b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/index.ts new file mode 100644 index 0000000000..330f933831 --- /dev/null +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/index.ts @@ -0,0 +1 @@ +export * from "./ImmediateProposalInfo"; diff --git a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx index c1966e0193..cb487b3811 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx @@ -1,6 +1,6 @@ import React, { FC, useState } from "react"; import { useModal } from "@/shared/hooks"; -import { Vote, VoteOutcome } from "@/shared/models"; +import { ResolutionType, Vote, VoteOutcome } from "@/shared/models"; import { VoteButton } from "../VoteButton"; import { VoteModal } from "./components"; import styles from "./ProposalFeedButtonContainer.module.scss"; @@ -8,12 +8,13 @@ import styles from "./ProposalFeedButtonContainer.module.scss"; interface ProposalFeedButtonContainerProps { proposalId: string; onVoteCreate: (vote: Vote) => void; + resolutionType: ResolutionType; } export const ProposalFeedButtonContainer: FC< ProposalFeedButtonContainerProps > = (props) => { - const { proposalId, onVoteCreate } = props; + const { proposalId, onVoteCreate, resolutionType } = props; const [voteOutcome, setVoteOutcome] = useState(null); const { isShowing: isVoteModalOpen, @@ -39,11 +40,13 @@ export const ProposalFeedButtonContainer: FC< voteOutcome={VoteOutcome.Approved} onClick={handleVoteButtonClick} /> - + {resolutionType === ResolutionType.WAIT_FOR_EXPIRATION && ( + + )} = ({ className }) => ( > Date: Sat, 22 Jul 2023 20:41:33 +1300 Subject: [PATCH 03/12] updates --- .../ProposalFeedCard/ProposalFeedCard.tsx | 34 ++++++---- .../ImmediateProposalInfo.module.scss | 1 + .../ImmediateProposalVoteInfo.module.scss | 15 ++++ .../ImmediateProposalVoteInfo.tsx | 68 +++++++++++++++++++ .../ImmediateProposalVoteInfo/index.ts | 1 + 5 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.module.scss create mode 100644 src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx create mode 100644 src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/index.ts diff --git a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx index cb66791818..7ed0ecbc13 100644 --- a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx +++ b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx @@ -41,6 +41,7 @@ import { UserVoteInfo, ImmediateProposalInfo, } from "./components"; +import { ImmediateProposalVoteInfo } from "./components/ImmediateProposalVoteInfo"; import { useProposalSpecificData } from "./hooks"; import { checkIsVotingAllowed, @@ -317,18 +318,28 @@ const ProposalFeedCard: React.FC = (props) => { }} > {proposal.resolutionType === ResolutionType.WAIT_FOR_EXPIRATION && ( - + <> + + + )} {proposal.resolutionType === ResolutionType.IMMEDIATE && ( - + <> + + + )} {isVotingAllowed && ( @@ -338,11 +349,6 @@ const ProposalFeedCard: React.FC = (props) => { resolutionType={proposal.resolutionType} /> )} - ); diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.module.scss b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.module.scss index e7da72b624..aed53bac63 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.module.scss +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.module.scss @@ -3,6 +3,7 @@ .container { display: flex; flex-direction: column; + margin-bottom: 2rem; } .title { diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.module.scss b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.module.scss new file mode 100644 index 0000000000..e7da72b624 --- /dev/null +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.module.scss @@ -0,0 +1,15 @@ +@import "../../../../../../constants"; + +.container { + display: flex; + flex-direction: column; +} + +.title { + font-size: $moderate-small-2; +} + +.subtitle { + font-size: $mobile-title; + color: var(--gray-60); +} diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx new file mode 100644 index 0000000000..e5abe0bc57 --- /dev/null +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx @@ -0,0 +1,68 @@ +import React, { useEffect, useMemo } from "react"; +import { useSelector } from "react-redux"; +import { selectUser } from "@/pages/Auth/store/selectors"; +import { useEligibleVoters } from "@/shared/hooks/useCases"; +import { + DateFormat, + Proposal, + ProposalState, + VoteOutcome, +} from "@/shared/models"; +import { Loader } from "@/shared/ui-kit"; +import { formatDate } from "@/shared/utils"; +import styles from "./ImmediateProposalVoteInfo.module.scss"; + +interface ImmediateProposalVoteInfoProps { + proposal: Proposal; +} + +const VOTE_OUTCOME_TO_TEXT_MAP: Record = { + [VoteOutcome.Approved]: "Approved", + [VoteOutcome.Abstained]: "Abstained", + [VoteOutcome.Rejected]: "Rejected", +}; + +export const ImmediateProposalVoteInfo = ({ + proposal, +}: ImmediateProposalVoteInfoProps) => { + const user = useSelector(selectUser()); + const { loading, voters, fetchEligibleVoters, error } = useEligibleVoters(); + + const isExpired = + proposal.state === ProposalState.FAILED && proposal.votes.total === 0; + + const vote = useMemo(() => { + if (voters && voters.length > 0) { + return voters[0]; + } + }, [voters]); + + useEffect(() => { + if (!isExpired) { + fetchEligibleVoters(proposal.id); + } + }, [proposal.id, isExpired]); + + if (!isExpired && loading) { + return ; + } + + return ( +
+
+ {isExpired + ? "Expired" + : `${vote?.vote && VOTE_OUTCOME_TO_TEXT_MAP[vote.vote.outcome]} by ${ + user?.uid === vote?.userId ? "You" : vote?.user.displayName + }`} +
+
+ {vote?.vote && + formatDate( + new Date(vote.vote.createdAt.seconds * 1000), + DateFormat.LongHuman, + )} +
+
+ ); +}; diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/index.ts b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/index.ts new file mode 100644 index 0000000000..ea678438df --- /dev/null +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/index.ts @@ -0,0 +1 @@ +export * from "./ImmediateProposalVoteInfo"; From 438b05ce70ab8b3b015be62768eb648838e8bbb4 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Sun, 23 Jul 2023 11:10:50 +1300 Subject: [PATCH 04/12] updates --- .../ImmediateProposalVoteInfo.module.scss | 4 ++ .../ImmediateProposalVoteInfo.tsx | 54 ++++++++++++++----- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.module.scss b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.module.scss index e7da72b624..a45dec2716 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.module.scss +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.module.scss @@ -2,7 +2,11 @@ .container { display: flex; +} + +.voteInfo { flex-direction: column; + margin-left: 0.8rem; } .title { diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx index e5abe0bc57..b68aa43a77 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx @@ -1,7 +1,8 @@ -import React, { useEffect, useMemo } from "react"; +import React, { ReactNode, useEffect, useMemo } from "react"; import { useSelector } from "react-redux"; import { selectUser } from "@/pages/Auth/store/selectors"; import { useEligibleVoters } from "@/shared/hooks/useCases"; +import { VoteAbstain, VoteAgainst, VoteFor } from "@/shared/icons"; import { DateFormat, Proposal, @@ -22,6 +23,12 @@ const VOTE_OUTCOME_TO_TEXT_MAP: Record = { [VoteOutcome.Rejected]: "Rejected", }; +const VOTE_OUTCOME_TO_ICON_MAP: Record = { + [VoteOutcome.Approved]: , + [VoteOutcome.Abstained]: , + [VoteOutcome.Rejected]: , +}; + export const ImmediateProposalVoteInfo = ({ proposal, }: ImmediateProposalVoteInfoProps) => { @@ -31,6 +38,11 @@ export const ImmediateProposalVoteInfo = ({ const isExpired = proposal.state === ProposalState.FAILED && proposal.votes.total === 0; + /** + * For now we assume that IMMEDIATE proposal is always a single vote proposal. + * In future we would want to support more then a single vote so the logic and the UI might change. + * See more details here https://github.com/daostack/common-backend/issues/1844. + */ const vote = useMemo(() => { if (voters && voters.length > 0) { return voters[0]; @@ -43,25 +55,39 @@ export const ImmediateProposalVoteInfo = ({ } }, [proposal.id, isExpired]); + if (error) { + return ( +
+ Oops! Something went wrong while loading the vote info. Please try again + later. +
+ ); + } + if (!isExpired && loading) { return ; } return (
-
- {isExpired - ? "Expired" - : `${vote?.vote && VOTE_OUTCOME_TO_TEXT_MAP[vote.vote.outcome]} by ${ - user?.uid === vote?.userId ? "You" : vote?.user.displayName - }`} -
-
- {vote?.vote && - formatDate( - new Date(vote.vote.createdAt.seconds * 1000), - DateFormat.LongHuman, - )} + {vote?.vote && VOTE_OUTCOME_TO_ICON_MAP[vote.vote.outcome]} +
+
+ {isExpired + ? "Expired" + : `${ + vote?.vote && VOTE_OUTCOME_TO_TEXT_MAP[vote.vote.outcome] + } by ${ + user?.uid === vote?.userId ? "You" : vote?.user.displayName + }`} +
+
+ {vote?.vote && + formatDate( + new Date(vote.vote.createdAt.seconds * 1000), + DateFormat.LongHuman, + )} +
); From 06a92b6a19adc6064ad6ab5e60398f07cf6707e8 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Mon, 24 Jul 2023 18:09:27 +1300 Subject: [PATCH 05/12] show vote text only is vote is fetched --- .../ImmediateProposalVoteInfo.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx index b68aa43a77..83af38cb3f 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx @@ -73,13 +73,11 @@ export const ImmediateProposalVoteInfo = ({ {vote?.vote && VOTE_OUTCOME_TO_ICON_MAP[vote.vote.outcome]}
- {isExpired - ? "Expired" - : `${ - vote?.vote && VOTE_OUTCOME_TO_TEXT_MAP[vote.vote.outcome] - } by ${ - user?.uid === vote?.userId ? "You" : vote?.user.displayName - }`} + {isExpired && "Expired"} + {vote?.vote && + `${VOTE_OUTCOME_TO_TEXT_MAP[vote.vote.outcome]} by ${ + user?.uid === vote?.userId ? "You" : vote?.user.displayName + }`}
{vote?.vote && From 6f65d32c40a9a7f6ef2a8224c71bf88da19345d1 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Mon, 24 Jul 2023 18:20:39 +1300 Subject: [PATCH 06/12] updated buttons text --- .../ProposalFeedButtonContainer.tsx | 2 ++ .../components/VoteButton/VoteButton.tsx | 26 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx index cb487b3811..cda023b9fd 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx @@ -39,6 +39,7 @@ export const ProposalFeedButtonContainer: FC< className={styles.buttonApprove} voteOutcome={VoteOutcome.Approved} onClick={handleVoteButtonClick} + resolutionType={resolutionType} /> {resolutionType === ResolutionType.WAIT_FOR_EXPIRATION && (
{voteOutcome && ( diff --git a/src/pages/common/components/ProposalFeedCard/components/VoteButton/VoteButton.tsx b/src/pages/common/components/ProposalFeedCard/components/VoteButton/VoteButton.tsx index 0ba3537f1b..96dc854092 100644 --- a/src/pages/common/components/ProposalFeedCard/components/VoteButton/VoteButton.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/VoteButton/VoteButton.tsx @@ -1,7 +1,7 @@ -import React, { ReactNode } from "react"; +import React, { ReactNode, useMemo } from "react"; import classNames from "classnames"; import { VoteAbstain, VoteAgainst, VoteFor } from "@/shared/icons"; -import { VoteOutcome } from "@/shared/models"; +import { ResolutionType, VoteOutcome } from "@/shared/models"; import { Button } from "@/shared/ui-kit"; import styles from "./VoteButton.module.scss"; @@ -9,14 +9,9 @@ interface VoteButtonProps { className?: string; voteOutcome: VoteOutcome; onClick?: (voteOutcome: VoteOutcome) => void; + resolutionType?: ResolutionType; } -const VOTE_OUTCOME_TO_TEXT_MAP: Record = { - [VoteOutcome.Approved]: "Vote for", - [VoteOutcome.Abstained]: "Abstain", - [VoteOutcome.Rejected]: "Vote against", -}; - const VOTE_OUTCOME_TO_ICON_MAP: Record = { [VoteOutcome.Approved]: , [VoteOutcome.Abstained]: , @@ -24,7 +19,18 @@ const VOTE_OUTCOME_TO_ICON_MAP: Record = { }; export const VoteButton: React.FC = (props) => { - const { className, voteOutcome, onClick } = props; + const { className, voteOutcome, onClick, resolutionType } = props; + + const voteOutcomeToTextMap = useMemo( + () => ({ + [VoteOutcome.Approved]: + resolutionType === ResolutionType.IMMEDIATE ? "Approve" : "Vote for", + [VoteOutcome.Abstained]: "Abstain", + [VoteOutcome.Rejected]: + resolutionType === ResolutionType.IMMEDIATE ? "Reject" : "Vote against", + }), + [resolutionType], + ); const handleClick = (event) => { event.stopPropagation(); @@ -53,7 +59,7 @@ export const VoteButton: React.FC = (props) => { [styles.rejectText]: VoteOutcome.Rejected === voteOutcome, })} > - {VOTE_OUTCOME_TO_TEXT_MAP[voteOutcome]} + {voteOutcomeToTextMap[voteOutcome]}

{VOTE_OUTCOME_TO_ICON_MAP[voteOutcome]} From 1bfd93fbbe5ee472043f492d63006cc276bb03e6 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Tue, 25 Jul 2023 08:08:56 +1300 Subject: [PATCH 07/12] buttons styles update when immediate --- .../ProposalFeedButtonContainer.module.scss | 4 ++++ .../ProposalFeedButtonContainer.tsx | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.module.scss b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.module.scss index c6faeb9ebe..1253507bb7 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.module.scss +++ b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.module.scss @@ -16,6 +16,10 @@ } } +.isImmediate { + grid-template-areas: "approve reject"; +} + .buttonApprove { grid-area: approve; } diff --git a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx index cda023b9fd..657b968cf8 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx @@ -1,4 +1,5 @@ import React, { FC, useState } from "react"; +import classNames from "classnames"; import { useModal } from "@/shared/hooks"; import { ResolutionType, Vote, VoteOutcome } from "@/shared/models"; import { VoteButton } from "../VoteButton"; @@ -32,16 +33,22 @@ export const ProposalFeedButtonContainer: FC< onVoteCreate(vote); }; + const isImmediate = resolutionType === ResolutionType.IMMEDIATE; + return ( <> -
+
- {resolutionType === ResolutionType.WAIT_FOR_EXPIRATION && ( + {!isImmediate && ( Date: Tue, 25 Jul 2023 20:35:03 +1300 Subject: [PATCH 08/12] code review updates --- .../ImmediateProposalVoteInfo.tsx | 10 ++---- .../ProposalFeedButtonContainer.module.scss | 2 +- .../ProposalFeedButtonContainer.tsx | 2 +- .../components/VoteButton/VoteButton.tsx | 32 +++++++++++-------- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx index 83af38cb3f..f4b1fb5101 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode, useEffect, useMemo } from "react"; +import React, { ReactNode, useEffect } from "react"; import { useSelector } from "react-redux"; import { selectUser } from "@/pages/Auth/store/selectors"; import { useEligibleVoters } from "@/shared/hooks/useCases"; @@ -40,14 +40,10 @@ export const ImmediateProposalVoteInfo = ({ /** * For now we assume that IMMEDIATE proposal is always a single vote proposal. - * In future we would want to support more then a single vote so the logic and the UI might change. + * In future we would want to support more than a single vote so the logic and the UI might change. * See more details here https://github.com/daostack/common-backend/issues/1844. */ - const vote = useMemo(() => { - if (voters && voters.length > 0) { - return voters[0]; - } - }, [voters]); + const vote = voters && voters.length > 0 ? voters[0] : undefined; useEffect(() => { if (!isExpired) { diff --git a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.module.scss b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.module.scss index 1253507bb7..a44564c89d 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.module.scss +++ b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.module.scss @@ -16,7 +16,7 @@ } } -.isImmediate { +.containerImmediate { grid-template-areas: "approve reject"; } diff --git a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx index 657b968cf8..db7ff282dc 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ProposalFeedButtonContainer/ProposalFeedButtonContainer.tsx @@ -39,7 +39,7 @@ export const ProposalFeedButtonContainer: FC< <>
= { [VoteOutcome.Rejected]: , }; +const getVoteOutcomeText = ( + voteOutcome: VoteOutcome, + resolutionType?: ResolutionType, +) => { + if (voteOutcome === VoteOutcome.Approved) { + return resolutionType === ResolutionType.IMMEDIATE ? "Approve" : "Vote for"; + } + if (voteOutcome === VoteOutcome.Rejected) { + return resolutionType === ResolutionType.IMMEDIATE + ? "Reject" + : "Vote against"; + } + if (voteOutcome === VoteOutcome.Abstained) { + return "Abstain"; + } +}; + export const VoteButton: React.FC = (props) => { const { className, voteOutcome, onClick, resolutionType } = props; - const voteOutcomeToTextMap = useMemo( - () => ({ - [VoteOutcome.Approved]: - resolutionType === ResolutionType.IMMEDIATE ? "Approve" : "Vote for", - [VoteOutcome.Abstained]: "Abstain", - [VoteOutcome.Rejected]: - resolutionType === ResolutionType.IMMEDIATE ? "Reject" : "Vote against", - }), - [resolutionType], - ); - const handleClick = (event) => { event.stopPropagation(); if (onClick) { @@ -59,7 +65,7 @@ export const VoteButton: React.FC = (props) => { [styles.rejectText]: VoteOutcome.Rejected === voteOutcome, })} > - {voteOutcomeToTextMap[voteOutcome]} + {getVoteOutcomeText(voteOutcome, resolutionType)}

{VOTE_OUTCOME_TO_ICON_MAP[voteOutcome]} From 1dab7feb1e7426c7e1d5f33822f2d6da29989b89 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Wed, 26 Jul 2023 07:41:22 +1300 Subject: [PATCH 09/12] temporary hide required voters string --- .../ImmediateProposalInfo/ImmediateProposalInfo.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx index 452f485573..154ed14a43 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx @@ -24,9 +24,10 @@ export const ImmediateProposalInfo = ({
{`${proposerUserName} requests to join ${votersString} circle`}
-
+ {/* Show this only when the required number of voters in greater than 1. Logic for this will be added in the future, see detalis here https://github.com/daostack/common-backend/issues/1844 */} + {/*
{`Approval by ${votersString} (1 from ${proposal.votes.totalMembersWithVotingRight} required)`} -
+
*/}
); }; From ddd68b957008263b6ed1eeaf8fc5e96633741f51 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Wed, 26 Jul 2023 07:43:01 +1300 Subject: [PATCH 10/12] . --- .../components/ImmediateProposalInfo/ImmediateProposalInfo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx index 154ed14a43..2deccbac1a 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalInfo/ImmediateProposalInfo.tsx @@ -24,7 +24,7 @@ export const ImmediateProposalInfo = ({
{`${proposerUserName} requests to join ${votersString} circle`}
- {/* Show this only when the required number of voters in greater than 1. Logic for this will be added in the future, see detalis here https://github.com/daostack/common-backend/issues/1844 */} + {/* Show this only when the required number of voters is greater than 1. Logic for this will be added in the future, see detalis here https://github.com/daostack/common-backend/issues/1844 */} {/*
{`Approval by ${votersString} (1 from ${proposal.votes.totalMembersWithVotingRight} required)`}
*/} From acb893bd8875a72c8fd7cd9542e1865238a68e49 Mon Sep 17 00:00:00 2001 From: Roie Natan Date: Wed, 26 Jul 2023 08:23:59 +1300 Subject: [PATCH 11/12] update the UI immediatly after voting --- .../ProposalFeedCard/ProposalFeedCard.tsx | 5 +++- .../ImmediateProposalVoteInfo.tsx | 23 +++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx index 7ed0ecbc13..c86374aa20 100644 --- a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx +++ b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx @@ -338,7 +338,10 @@ const ProposalFeedCard: React.FC = (props) => { governanceCircles={governanceCircles} proposerUserName={getUserName(feedItemUser)} /> - + )} diff --git a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx index f4b1fb5101..7d069dadc4 100644 --- a/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/ImmediateProposalVoteInfo/ImmediateProposalVoteInfo.tsx @@ -7,6 +7,7 @@ import { DateFormat, Proposal, ProposalState, + Vote, VoteOutcome, } from "@/shared/models"; import { Loader } from "@/shared/ui-kit"; @@ -15,6 +16,7 @@ import styles from "./ImmediateProposalVoteInfo.module.scss"; interface ImmediateProposalVoteInfoProps { proposal: Proposal; + userVote: Vote | null; } const VOTE_OUTCOME_TO_TEXT_MAP: Record = { @@ -31,6 +33,7 @@ const VOTE_OUTCOME_TO_ICON_MAP: Record = { export const ImmediateProposalVoteInfo = ({ proposal, + userVote, }: ImmediateProposalVoteInfoProps) => { const user = useSelector(selectUser()); const { loading, voters, fetchEligibleVoters, error } = useEligibleVoters(); @@ -64,23 +67,25 @@ export const ImmediateProposalVoteInfo = ({ return ; } + const outcome = userVote?.outcome || vote?.vote?.outcome; + const userId = userVote?.voterId || vote?.userId; + const createdAt = + userVote?.createdAt.seconds || vote?.vote?.createdAt.seconds; + return (
- {vote?.vote && VOTE_OUTCOME_TO_ICON_MAP[vote.vote.outcome]} + {outcome && VOTE_OUTCOME_TO_ICON_MAP[outcome]}
{isExpired && "Expired"} - {vote?.vote && - `${VOTE_OUTCOME_TO_TEXT_MAP[vote.vote.outcome]} by ${ - user?.uid === vote?.userId ? "You" : vote?.user.displayName + {outcome && + `${VOTE_OUTCOME_TO_TEXT_MAP[outcome]} by ${ + user?.uid === userId ? "You" : vote?.user.displayName }`}
- {vote?.vote && - formatDate( - new Date(vote.vote.createdAt.seconds * 1000), - DateFormat.LongHuman, - )} + {createdAt && + formatDate(new Date(createdAt * 1000), DateFormat.LongHuman)}
From cce087864b86316a5ea6858fa4b8b80488724937 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Wed, 26 Jul 2023 20:34:08 +0400 Subject: [PATCH 12/12] refactor getVoteOutcomeText helper --- .../components/VoteButton/VoteButton.tsx | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/pages/common/components/ProposalFeedCard/components/VoteButton/VoteButton.tsx b/src/pages/common/components/ProposalFeedCard/components/VoteButton/VoteButton.tsx index 52763913ae..3119a2c117 100644 --- a/src/pages/common/components/ProposalFeedCard/components/VoteButton/VoteButton.tsx +++ b/src/pages/common/components/ProposalFeedCard/components/VoteButton/VoteButton.tsx @@ -21,17 +21,20 @@ const VOTE_OUTCOME_TO_ICON_MAP: Record = { const getVoteOutcomeText = ( voteOutcome: VoteOutcome, resolutionType?: ResolutionType, -) => { - if (voteOutcome === VoteOutcome.Approved) { - return resolutionType === ResolutionType.IMMEDIATE ? "Approve" : "Vote for"; - } - if (voteOutcome === VoteOutcome.Rejected) { - return resolutionType === ResolutionType.IMMEDIATE - ? "Reject" - : "Vote against"; - } - if (voteOutcome === VoteOutcome.Abstained) { - return "Abstain"; +): string => { + switch (voteOutcome) { + case VoteOutcome.Approved: + return resolutionType === ResolutionType.IMMEDIATE + ? "Approve" + : "Vote for"; + case VoteOutcome.Rejected: + return resolutionType === ResolutionType.IMMEDIATE + ? "Reject" + : "Vote against"; + case VoteOutcome.Abstained: + return "Abstain"; + default: + return ""; } };